JDK1.8新特性
一,Lambda表达式
二,函数式接口
三,方法引用和构造器调用
四,Stream API
五,接口中的默认方法和静态方法
六,新时间日期API
除此之外还对hashmap等map集合数据结构进行了优化
1.7时map的数据结构是哈希表(数组+链表)hashmap默认大小为16,是一个0-15索引的数组,加载因子0.75,达到容量的75%时就进行扩容,无法避免碰撞的情况发生,
1.8之后hashmap的数据结构变成了,数组+链表+红黑树,当碰撞元素个数大于8并且容量达到64会有红黑树引入,除了效率比链表高外,新加的元素加到末尾,
ConcurrentHashMap(锁分段机制)concurrentLevel,jdk1.8采用CAS算法(无锁算法,不再使用锁分段),数组+链表中也引入了红黑树的使用
Lambda表达式:
实质上是一段匿名内部类,也可以是一段可传递的代码
Comparator<Integer> cpt = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
}
用Lambda表达式优化:
Comparator<Integer> cpt2=(x,y)->Integer.compare(x,y);
Lmabda表达式的语法总结: () -> ();
无参数无返回值 () -> System.out.println(“Hello WOrld”);
有一个参数无返回值 (x) -> System.out.println(x);
有且只有一个参数无返回值 x -> System.out.println(x);
有多个参数,有返回值,有多条lambda体语句 (x,y) -> {System.out.println(“xxx”);return xxxx;};
有多个参数,有返回值,只有一条lambda体语句 (x,y) -> xxxx;
口诀:左右遇一省括号,左侧推断类型省
注:当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念。
函数是接口:
简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface
常见的四大函数式接口:
Consumer 《T》:消费型接口,有参无返回值
public void test(){
changeStr("hello",(str) -> System.out.println(str));
}
/**
* Consumer<T> 消费型接口
* @param str
* @param con
*/
public void changeStr(String str, Consumer<String> con){
con.accept(str);
}
Supplier 《T》:供给型接口,无参有返回值
@Test
public void test2(){
String value = getValue(() -> "hello");
System.out.println(value);
}
/**
* Supplier<T> 供给型接口
* @param sup
* @return
*/
public String getValue(Supplier<String> sup){
return sup.get();
}
Function 《T,R》::函数式接口,有参有返回值
@Test
public void test3(){
Long result = changeNum(100L, (x) -> x + 200L);
System.out.println(result);
}
/**
* Function<T,R> 函数式接口
* @param num
* @param fun
* @return
*/
public Long changeNum(Long num, Function<Long, Long> fun){
return fun.apply(num);
}
Predicate《T》: 断言型接口,有参有返回值,返回值是boolean类型
public void test4(){
boolean result = changeBoolean("hello", (str) -> str.length() > 5);
System.out.println(result);
}
/**
* Predicate<T> 断言型接口
* @param str
* @param pre
* @return
*/
public boolean changeBoolean(String str, Predicate<String> pre){
return pre.test(str);
}
总结:函数式接口的提出是为了让我们更加方便的使用lambda表达式,不需要自己再手动创建一个函数式接口,直接拿来用就好了
方法引用和构造器调用
Stream API:
Stream操作的三个步骤
1.创建stream
2.中间操作(过滤、筛选,去重,map)
过滤
list.stream().filter(user->user.getAge()>20).collect(Collectors.toList());
生成新的stream,getName的list
list.stream().map(User::getName).collect(Collectors.toList());
去重(引用数据类型要重写equas和hashCode)
list.stream().distinct().collect(Collectors.toList());
3.终止操作
Optional容器:
Optional.of(T t); // 创建一个Optional实例
Optional.empty(); // 创建一个空的Optional实例
Optional.ofNullable(T t); // 若T不为null,创建一个Optional实例,否则创建一个空实例
isPresent(); // 判断是否包含值
orElse(T t); //如果调用对象包含值,返回该值,否则返回T
orElseGet(Supplier s); // 如果调用对象包含值,返回该值,否则返回s中获取的值
map(Function f): // 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty();
flatMap(Function mapper);// 与map类似。返回值是Optional
get() //获取容器内的值
总结:Optional.of(null) 会直接报NPE
新的日期API LocalDate | LocalTime | LocalDateTime:
java。time包中的是类是不可变且线程安全的。新的时间及日期API位于java.time中,下面是一些关键类
●Instant——它代表的是时间戳
●LocalDate——不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。
●LocalTime——它代表的是不含日期的时间
●LocalDateTime——它包含了日期及时间,不过还是没有偏移信息或者说时区。
●ZonedDateTime——这是一个包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
1. 如何在java8中获取当天的日期没有时间
LocalDateTime date = LocalDateTime.now();
2.如何在java8中获取当前的年月日
date.getYear()//年
date.getMouthValue()//月
date.getDayofMouth()//日
3.在java8中如何获取某个特定的日期(月份和日期是一位数时要写成01)
LocalDateTime date = new LocalDate(2022,01,23)
4.在java8中检查两个日期是否相等,LocalDate重写了equals方法来进行日期的比较
5.如何在java中判断是否是某个节日或者重复事件,使用MonthDay类。这个类由月日组合,不包含年信息,可以用来代表每年重复出现的一些日期或其他组合
6.在java8中获取当前时间,用的是LocalTime类,默认的格式是hh:mm:ss:nnn
LocalTime localTime=new LocalTime.now();
7、如何增加时间里面的小时数
LocalTime localTime=new LocalTime.now();
LocalTime time = localTime.plusHours(2);//两个小时后的时间
8、如何获取1周后的日期
LocalDate localDate = LocalDate.now();
LocalDate date = localDate.plusWeeks(1);
可以看到一周后的日期是什么,也可以用这个方法来增加一个月,一年,一小时,一分等等
9,在java中如何判断某个日期在另一个日期的前面还是后面
在java8中,LocalDate类中使用isBefore()、isAfter()、equals()方法来比较两个日期。如果调用方法的那个日期比给定的日期要早的话,isBefore()方法会返回true。
10.如何表示固定的日期,比如信用卡过期时间
正如MonthDay表示的是某个重复出现的日子,YearMonth是另外一个组合,代表的是像信用卡还款日,定期存款到期日,options到期日这类的日期。你可以用这个类找出这个月有多少天,LengthOfMonth()这个方法返回的是这个YearMonth实例有多少天,这对于检查2月是否润2月很有用
YearMonth now = YearMonth.now();
//今年的这个月有多少天
int dayNum = now.lengthOfMonth();
11. 如何在java8中检查闰年
LocalDate类由一个isLeapYear()方法来返回当前LocalDate对应的那年是否是闰年
Boolean bl=localDate.isLeapYear();
12.两个日期之间包含多少天,多少月计算两个日期之间包含多少天、周、月、年。可以用java.time.Period类完成该功能。下面例子中将计算日期与将来的日期之间一共有几个月
LocalDate today = localDate.of(2022,01,02);
LocalDate nextDate = localDate.of(2022,01,22);
Period period = Period.between(today, nextDate);
period.getYears();//俩个日期查几年
period.getMonths();//俩个日期查几个月
period.getDays();//俩个日期查几天
13.在java8中获取当前时间戳
java8获取时间戳特别简单。Instant类由一个静态的工厂方法now()可以返回当前时间戳
Instant instant = Instant.now();
14.DateTimeFormatter类用于在Java中进行日期的格式化与解析。与SimpleDateFormat不同,它是不可变且线程安全的,如果需要的话,可以赋值给一个静态变量。DateTimeFormatter类提供了许多预定义的格式器,你也可以自定义自己想要的格式。当然了,根据约定,它还有一个parse()方法是用于将字符串转换成日期的,如果转换期间出现任何错误,它会抛出DateTimeParseException异常。类似的,DateFormatter类也有一个用于格式化日期的format()方法,它出错的话则会抛出DateTimeException异常。