1. Java 8
1.1 生态
- Lambda 表达式
- 函数式接口
- 方法引用 / 构造器引用
- Stream API
- 接口中的默认方法 / 静态方法
- 新时间日期 API
- 其他新特性
1.2 新特性
- 速度更快
- 代码更少
- 强大的 Stream API
- 便于并行
- 最大化减少空指针异常 Optional (Kotlin ?)
1.3 温故而知新
- Hashmap 底层结构/原理 老话题不再阐述 …
- 并发hashmap …
- Java虚拟机 …
- Java内存模型 …
2. Lambda
2.1 匿名函数
Lambda是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样传递);可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升。
2.2 匿名内部类
2.3 Lambda
演变过程:
基础语法
口诀:
写死小括号,拷贝右箭头,落地大括号
左右遇一括号省
左侧推断类型省
语法格式:
无参数,无返回值:() -> sout
例如 Runnable接口:
有一个参数,无返回值
有一个参数,无返回值 (小括号可以省略不写)
有两个及以上的参数,有返回值,并且 Lambda 体中有多条语句
有两个及以上的参数,有返回值,并且 Lambda 体中只有1条语句 (大括号 与 return 都可以省略不写)
Lambda 表达式 参数的数据类型可以省略不写 Jvm可以自动进行 “类型推断”
函数式接口:
接口中只有一个抽象方法的接口 @FunctionalIterface
测试:
定义一个函数式接口:
用一下:
再用一下:
2.4 案例
**案例一:**调用 Collections.sort() 方法,通过定制排序 比较两个 Employee (先按照年龄比,年龄相同按照姓名比),使用 Lambda 表达式作为参数传递
定义实体类
定义 List 传入数据
@Test
**案例二:**声明函数式接口,接口中声明抽象方法,String getValue(String str); 声明类 TestLambda,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值;再将一个字符串的第二个和第四个索引位置进行截取字串
**案例三:**声明一个带两个泛型的函数式接口,泛型类型为<T, R> T 为参数,R 为返回值;接口中声明对应的抽象方法;在 TestLambda 类中声明方法,使用接口作为参数,计算两个 Long 类型参数的和;在计算两个 Long 类型参数的乘积
3. 函数式接口
3.1 消费型接口
3.2 提供型接口
3.3 函数型接口
3.4 断言型接口
3.5 其他接口
4. 引用
4.1 方法引用
**定义:**若 Lambda 表达式体中的内容已有方法实现,则我们可以使用“方法引用”
语法格式:
对象 :: 实例方法
类 :: 静态方法
类 :: 实例方法
对象::实例方法
**注意:**Lambda 表达实体中调用方法的参数列表、返回类型必须和函数式接口中抽象方法保持一致
类::静态方法
类::实例方法
**条件:**Lambda 参数列表中的第一个参数是方法的调用者,第二个参数是方法的参数时,才能使用 ClassName :: Method
4.2 构造器引用
格式:
ClassName :: new
**注意:**需要调用的构造器的参数列表要与函数时接口中抽象方法的参数列表保持一致
4.3 数组引用
语法:
Type :: new;
5. Stream API
5.1 创建
什么是 Stream?
Stream的操作步骤:
创建流:(的几种方法如下)
5.2 筛选 / 切片
中间操作:
filter:接收 Lambda ,从流中排除某些元素
limit:截断流,使其元素不超过给定数量
skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素
Stream的中间操作:
内部迭代:迭代操作由 Stream API 完成
外部迭代:我们通过迭代器完成
5.3 映射
map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流
map:
flatMap:
5.4 排序
sorted():自然排序
sorted(Comparator c):定制排序
Comparable:自然排序
Comparator:定制排序
5.5 查找 / 匹配
终止操作:
- allMatch:检查是否匹配所有元素
- anyMatch:检查是否至少匹配一个元素
- noneMatch:检查是否没有匹配所有元素
- findFirst:返回第一个元素
- findAny:返回当前流中的任意元素
- count:返回流中元素的总个数
- max:返回流中最大值
- min:返回流中最小值
5.6 归约 / 收集
归约:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
收集:collect 将流转换成其他形式;接收一个 Collector 接口的实现,用于给流中元素做汇总的方法
reduce:
collect:
5.7 案例
**案例一:**给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?(如:给定【1,2,3,4,5】,返回【1,4,9,16,25】)
**案例二:**怎样使用 map 和 reduce 数一数流中有多少个 Employee 呢?
map分组后排序
public static Map<String, List<PsOnlineDataVo>> sortByValue(Map<String, List<PsOnlineDataVo>> map, int flag) {
Map<String, List<PsOnlineDataVo>> sortMap = new LinkedHashMap<>();
if (flag == 1) {
map.entrySet().stream()
.sorted((o1, o2) -> Integer.valueOf(o1.getKey()).compareTo(Integer.valueOf(o2.getKey())))
.forEach(entry -> sortMap.put(entry.getKey(), entry.getValue()));
} else {
map.entrySet().stream()
.sorted((o1, o2) -> Integer.valueOf(o2.getKey()).compareTo(Integer.valueOf(o1.getKey())))
.forEach(entry -> sortMap.put(entry.getKey(), entry.getValue()));
}
return sortMap;
}
5.8 并行流
- 并行流:就是把一个内容分成几个数据块,并用不同的线程分别处理每个数据块的流
- Java 8 中将并行进行了优化,我们可以很容易的对数据进行操作;Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与串行流之间切换
Fork / Join 框架:
Fork / Join 框架与传统线程池的区别:
Fork / Join 实现:
Java 8 并行流 / 串行流:
@Test
public void test03(){
//串行流(单线程):切换为并行流 parallel()
//并行流:切换为串行流 sequential()
6. Optional
**定义:**Optional 类 (java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在用 Optional 可以更好的表达这个概念;并且可以避免空指针异常
常用方法:
- Optional.of(T t):创建一个 Optional 实例
- Optional.empty(T t):创建一个空的 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
Optional.of(T t):
Optional.empty(T t):
Optional.ofNullable(T t):
isPresent():
不再一一例举…
7. 接口
7.1 默认方法
类优先原则:
7.2 静态方法
8. Date / Time API
8.1 安全问题
传统的日期格式化:
加锁:
DateTimeFormatter:
String compareMonth = DateUtil.format(DateUtil.offset(DateUtil.parse(time, "yyyyMM"), DateField.YEAR, -1), "yyyyMM");
String month = DateUtil.format(DateUtil.offset(new Date(), DateField.MONTH, -1), "yyyyMM");
8.2 本地时间 / 日期
ISO 标准:
常用方法:
LocalDate / LocalTime 不再一一例举…
8.3 时间戳
Instant:以 Unix 元年 1970-01-01 00:00:00 到某个时间之间的毫秒值
@Test:
8.4 时间 / 日期 差
Duration:计算两个时间之间的间隔
Period:计算两个日期之间的间隔
@Test:
8.5 时间校正器
操纵日期:
@Test:
8.6 格式化
DateTimeFormatter:格式化时间 / 日期
8.7 时区
ZonedDate
ZonedTime
ZonedDateTime
@Test:
一些转换:
9. 注解
9.1 重复注解
定义注解:
定义容器:
@Test:
9.2 类型注解
Java 8 新增注解:新增ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER(在Target上)