java8特性
Lambda
Lambda是一种函数式编程,可以不严谨的理解为一个函数,是一套关于函数f(x)定义、输入量、输出量的计算方案。除了输入输出以及函数内容,其他的lambda都不关心:
factory = new Factory() {
@Override
public Object getObject() {
return new User();
}
}
// 只关心 输入 - () 输出 factory 内容 {}
factory = () -> {
return new User();
}函数式编程的主要特点:
函数是一等公民
可以赋值给变量
可以作为其他函数的参数进行传递
可以作为其他函数的返回值
Lambda语法格式
格式1
格式2
其他规则:
可选的大括号,当函数体只包含一个语句,可以省略大括号
可选的参数类型声明,编译器可以根据参数值进行推断
可选的小括号,如果只有一个参数,可以省略小括号
可选的return关键字,如果函数体只有一个表达式,且运算结果匹配返回类型,return可以省略
Lambda使用前提(函数式接口)
因为在Java中没有函数的概念,只有方法的概念,所有的方法一定从属于一个对象或者Class,所以为了可以表达函数的概念,提供了函数式接口。函数式接口是Java中一种特殊的接口:
有且只有一个抽象方法的接口是函数式接口
满足一条件的就是函数式接口,可以通过
@FunctionalInterface注解标记,被标记的接口如果不符合函数式接口的条件将会报错
看到函数式接口,就代表定义了一个这样的函数签名
常见的函数式接口
Runnable / Callable
略。
Comparator
略。
Supplier
Supplier即提供实例的供应商。该接口的定义,是获取一个结果,或者说,返回一个指定类型的实例,而且,针对同一个类型,不保证每次返回实例相同。
当我们把一个实例的类型、数据等信息收集好了,就可以交给Supplier接口(通过反射)去完成实现,当需要的时候就通过get()返回那个实例,这就是懒加载。在Spring和JDK中都有这么用过。
应用场景:
配合Future(J.U.C),把返回的信息封装/设置成具体类型的实例;
在流操作中,获取源数据(资源文件、管道等)的实例,封装各种buffer的实例等,包括反射获取source;
java.util.stream,用作返回收集、分割、查找、过滤等操作的实例;
在日志系统中,封装一个“消息提供者”
在网络编程中,封装二进制数据
在Spring的实例初始化时,在AbstracBeanDefinition中提供了实例供应商,用于回调生成bean
常用于设计模式:委托、工厂等
Consumer
对象消费者:
典型应用场景:
BiConsumer
代表连续消费两个入参的操作:
Predicate
谓语,Predicate代表一个断定式子,其函数名为 test:
评估参数里面的表达式
返回值是一个boolean类型
示例:
提供的其他的default方法:
and, 等同于短路与&&or,等同于逻辑或||negate,等同于逻辑非!isEqual,判断两个对象是否相同,实际是调用Objects.equals方法
注意,上述方法都返回当前Predicate函数对象,所以可以进行链式调用,但是test方法返回true。
Function
BiFunction
接受输入两个参数,返回一个结果
Lambda底层实现
Lambda表达式实际上是匿名内部类的匿名实现。
方法引用
方法引用是对Lambda表达式的再次简化:
方法引用语法格式
方法引用运算符:::
哪儿些方法可以引用?
类方法:
Integer::parseInt构造方法:
Student::new实例方法:
System.out::println,super::方法名,this::方法名,int[]::new数组方法引用
可以采用引用的前提:
参数列表相同
返回值类型兼容
方法引用底层实现
与Lambda的原理一致,本质也是匿名内部类。
Stream
关注做什么,而不是怎么做。
专注对容器对象的聚合操作
提供串行/并行两种模式(fork/join框架拆分任务)
提高编程效率与可读性
Stream常用API
Stream流的API大致可以分为两大类:
中间操作,可以有零个或多个,打开流,过滤/映射,返回新流
终结操作,只能有一个的最后的操作,调用终结操作Stream流将会被关闭。
终结操作也是一种短路操作,可以根据情况中断流处理。
构建Steam
collect 收集
Collector收集器有一个对应的工具类 Collectors,可以返回一些比较常用的收集器:
并行Stream
stream()方法产生的流是串行的,也就是说流中的操作在一个线程中运行。而通过parallelStream()创建的流则是一个并行的流,他的内部是一个ForkJoinPool,处理时拆分处理,最后将结果合并。
获取并行流:
并行流因为基于ForkJoinPool,所以也有线程安全的问题(在流处理函数中访问非线程安全的变量)。个人认为,当数据量处理过慢,或者集合过大,应该优先从其他方面优化(提升执行速度、减少数据量),而不是一定要使用并行流。
使用Optional处理Null
三种构造
何时使用每种构造?
Optional.of(obj):
明确obj不可能为null
明确obj为null,并快速抛出异常
Optional.ofNullable(obj):
不明确obj是否为null,又要对obj进行处理的
存在即返回,无则提供默认值
存在即返回,无则由函数生成
存在则返回, 无则抛出异常
变种,存在则返回,无则抛出空指针异常:
存在才执行, 无则不会执行
map 处理级联数据
有一 user 对象,不知是否为null
如果为null,返回null
如果不为null,返回 name
如果name 为null,返回 null
如果name 不为null, 将name 转换为大写
这种级联的null 处理,需要使用map, map可以嵌套无数层。
flatMap:
flatMap 同 map 类似,只是参数不同,他的函数参数需要返回 Optional 类型:
总结
一句话小结: 使用 Optional 时尽量不直接调用 Optional.get() 方法, Optional.isPresent() 更应该被视为一个私有方法, 应依赖于其他像 Optional.orElse(), Optional.orElseGet(), Optional.map() 等这样的方法.
新的日期API
JSR-310规范提供一个新的和改进的Java日期与时间API,该规范领导者Stephen Colebourne就是joda-time作者,因此很多环节很像joda-time。
JDK8的新的设计时间日期API,位于java.time下面,并且都是线程安全的:
LocalDate本地日期LocalTime本地时间LocalDateTime本地日期时间DateTimeFormatter日期时间格式化类Instant时间戳Duration时间段(两个时间的间隔)Period日期段(两个日期的间隔)ZonedDateTime具有时区的日期时间
此外,Java中使用的历法是ISO 8601日历系统,也就是公历。平年有365天,闰年有366天。此外,Java8还提供了4套其他的历法,他们分别是:
ThaiBuddhistDate:泰国佛教历MinguoDate:中华民国历JapaneseDate:日本历HijraDate:伊斯兰历
旧版日期时间API缺陷
日期时间类设计不合理,有
java.util.date以及java.sql.Date两个类。其中前者拥有日期和时间,后者仅仅拥有日期。日期时间格式化设计不合理,在
java.text下。非线程安全的,所有的日期类都是可变的。
时区处理麻烦,日期类并不提供国际化,没有时区的支持。
LocalDate
LocalTime
LocalDateTime
日期时间修改
LocalDate、LocalTime、LocalDateTime提供了一系列的with方法,用于根据当前日期修改得到新的日期。注意,他们默认都是不可修改的对象,故他们是线程安全的,修改操作会返回一个新的日期时间对象:
也提供了一系列的plus以及minus方法,用于在当前日期的基础上,加上或者减去指定的时间:
更复杂的情况可以借助时间矫正器 TemporalAdjuster,完成类似的以下的日期时间修改功能:
获取下个月的第一天
获取上周三的日期
TemporalAdjuster 提供了大量的默认实现,用于简化常用的日期修改操作。
日期时间比较
日期格式化
在JDK8中,可以通过java.time.format.DateTimeFormatter类进行日期时间格式化于解析:
Instant
表示时间戳,内部保存了从1770年1月1日0时0分以来的秒数以及纳秒数。
Duration 和 Period
DK8提供的用于计算时间日期时间差的工具类。其中
Duration,可以计算
LocalTime、LocalDateTime、Instant的时间差Period,可以计算
LocalDate之间的时间差
时区日期时间类
Java8中,LocalDate、LocalTime、LocalDateTime是不带时区的,带时区的提供了三个对应的类,分别为:
ZonedDateZonedTimeZonedDateTime
其中每个时区都对应着一个ID,存储在ZonedId类中。
框架支持
要想在Mybatis、Jackson中使用JSR310,需要添加JSR310的实现。
LocalDate映射数据库中的date类型
LocalTime来映射数据库中的time类型
LocalDateTime字段来映射数据库中的datetime类型
最后更新于
这有帮助吗?