whats new in Java8:
https://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
1. lambda表达式
- http://www.importnew.com/26080.html
- Java8 lambda表达式10个示例 http://www.importnew.com/16436.html
- 为什么要用lambda
- 又称闭包或匿名函数,用来代替匿名内部类
- 使代码变的更加紧凑
- new Thread(() -> System.out.println("Hello World!")).start();
- 修改方法的能力:函数中可以接受以函数为单元的参数
- String []datas = new String[] {"peng","zhao","li"};
- Arrays.sort(datas,(v1 , v2) -> Integer.compare(v1.length(), v2.length()));
- 语法
- 单行表达式
- (params) -> an expression
- 多个语句块
- (params) -> {expressions;};
- 没有参数,用空括号表示
- () -> {for (int i = 0; i < 1000; i++) doSomething();};`
- Java是一个强类型的语言,因此参数必须要有类型,如果编译器能够推测出Lambda表达式的参数类型,则不需要我们显示的进行指定
- Arrays.sort(datas,(v1, v2) -> Integer.compare(v1.length(), v2.length()));
- 编译器会根据Lambda表达式对应的函数式接口Comparator进行自动推断
- 如果Lambda表达式只有一个参数,并且参数的类型是可以由编译器推断出来的
- Stream.of(datas).forEach(param -> {System.out.println(param.length());});`
- Lambda表达式的返回类型,无需指定,编译器会自行推断,说是自行推断
- 参数可以使用修饰符及注解,如final、@NonNull等
-
- 方法引用
- String []datas = new String[] {"peng","Zhao","li"};
- Arrays.sort(datas,String::compareToIgnoreCase);
- Stream.of(datas).forEach(System.out::println);
- 方法引用的具体分类
- Object:instanceMethod
- Class:staticMethod
- Class:instanceMethod
- 两种在Lambda表达式的意义上等同
- System.out::println == x -> System.out.println(x);
- String::compareToIgnoreCase == (x,y) -> x.compareToIgnoreCase(y)
- java 8中内部类或者Lambda表达式对外部类变量的引用,不要求强制的加上final关键字了,但是Java 8中要求这个变量是effectively final(有效只读变量,一旦定义后,在后面就不能再随意修改)
```
String []datas = new String[] {"peng","Zhao","li"};
datas = null;
new Thread(() -> System.out.println(datas)).start(); //compile error
```
- Java中内部类以及Lambda表达式中也不允许修改外部类中的变量,这是为了避免多线程情况下的race condition
- 缺点
- 坑
- variable used in lambda expression should be final or effectively final
- lambda和inner class中的变量都得是final
- 如果在匿名类或 Lambda 表达式中访问的局部变量,如果不是 final 类型的话,编译器自动加上 final 修饰符
```
String version = "1.8";
version = "1.7"; //注释掉这行或下行中另一行才能编译通过
foo(() -> version ); //这行让编译器决定给 version 加上 final 属性
```
- 解释:为什么 Lambda 表达式(匿名类) 不能访问非 final 的局部变量呢?因为实例变量存在堆中,而局部变量是在栈上分配,Lambda 表达(匿名类)会在另一个线程中执行。如果在线程中要直接访问一个局部变量,可能线程执行时该局部变量已经被销毁了,而 final 类型的局部变量在 Lambda 表达式(匿名类) 中其实是局部变量的一个拷贝。
2. 接口的默认方法
- 在Java8种引入新的机制,支持在接口中声明方法同时提供实现
- 这令人激动不已,你有两种方式完成
- 1.在接口内声明静态方法
- 2.指定一个默认方法
- 比如List接口中添加了sort方法
- Java8操作集合的时候可以直接foreach的原因也是在Iterable接口中也新增了一个默认方法:forEach
3. 流API
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流
- 数组转stream,Arrays.stream(values())
- 流式计算原理
4. 方法引用
- 方法引用使用一对冒号 ::
- names.forEach(System.out::println);
- Arrays.sort(arr, Comparator.comparing(SupplierHS::getCorpId).thenComparing(SupplierHS::getCorpName));
5.FunctionalInterface
- 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
- java8中用lambda表达式代替匿名内部类,本质上是将接口定义为函数式接口,并将函数式接口隐式转换为lambda表达式
- Predicate接口适合用于过滤,测试对象是否符合某个条件,唯一抽象方法是 boolean test(T t)
6. LocalDate、LocalTime、LocalDateTime
- 为什么需要LocalDate、LocalTime、LocalDateTime
- Date如果不格式化,打印出的日期可读性差
- Date对时间处理比较麻烦,比如想获取某年、某月、某星期,以及n天以后的时间
- 使用SimpleDateFormat对时间进行格式化,但SimpleDateFormat是线程不安全的
- 解决SimpleDateFormat非线程安全问题?
- 方法一:用DateTimeFormatter和FastDateFormat替换
- 方法二:每次都创建新的SimpleDateFormat对象
- 方法三:使用ThreadLocal保证每个线程最多只创建一次
- LocalDate,只会获取年月日
- LocalDate.now()
- LocalDate.of(2019, 9, 10)
- int year = localDate.getYear();
- LocalTime,只会获取几点几分几秒
- LocalDateTime=LocalDate+LocalTime
- 转instant:localDateTime.toInstant(ZoneOffset.of("+8"))
- Instant,获取秒数、毫秒数
- 可用来与Date对象转换
- new Date(instant.toEpochMilli())
- Date.from(instant)
- 格式化
LocalDate localDate = LocalDate.of(2019, 9, 10); String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE); String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE); //自定义格式化 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); String s3 = localDate.format(dateTimeFormatter);
8. Optional 类
- 目的:减少空指针异常
- https://www.cnblogs.com/zhangboyu/p/7580262.html
- Optional.ofNullable(user),user可能为null
- Optional.of(user),user不允许为null,否则报空指针
- optional.get(),如果value为null,则报错:NoSuchElementException
- optional.isPresent(),return value != null
- optional.ifPresent(consumer)
- optional.orElse(other),有值返回,无值返回other
- optional.orElseGet(supplier)。
- 与orElse的区别,有值的时候不会执行supplier
- optional.orElseThrow(Supplier exceptionSupplier) throws X
- optional.map((a) -> a.getName())
- optional.flatmap((a) -> a.getName())
- Funcation参数的返回值为Optional,flatmap返回解除包装的 String 值
- optional.filter(predicate)
- 链式
String result = Optional.ofNullable(user) .flatMap(User::getAddress) .flatMap(Address::getCountry) .map(Country::getIsocode) .orElse("default");
List<User> users = new ArrayList<>(); User user = users.stream().findFirst().orElse(new User("default", "1234"));
- Optional 不是 Serializable。因此,它不应该用作类的字段