JDK8到JDK17新特性
前言
SpringBoot3.0开始强制使用JDK17,想必会迎来一波JDK8到JKD17的更新热潮。本文总结了JDK8-JDK17所有重要的更新内容,以供查阅。
原文地址:https://xuedongyun.cn/post/54344/
带资源的try
JDK7新特性
- 在try的后面可以增加(),括号中可以声明流对象并初始化
- try中的代码执行完毕,自动把流对象释放,不用写finally了
说明:
声明的类必须实现
AutoCloseable
或Closeable
接口,实现了其中的close
方法。Java7几乎把所有的资源类都实现了这些接口。写到括号中的变量默认是final的,无法更改。
1 | try ( |
JDK9语法有增强
此时可以在外部初始化变量,括号中引用外部名称即可,用分号隔开。
1 | InputStreamReader reader = new InputStreamReader(System.in); |
Lambda表达式
JDK8新特性
在启动线程时,需要传入一个实现java.lang.Runnable
接口的对象,来定义线程中的工作。通常,我们使用匿名内部类来实现。
1 | new Thread(new Runnable() { |
但是本质上,我们需要的其实只是一个函数。lambda表达式就是为解决这个问题而出现的。
1 | Comparator<Integer> com1 = (Integer o1, Integer o2) -> { |
函数式接口
- 只包含一个抽象方法的接口称为函数式接口(当然可以包含其他非抽象方法)
- 可以用lambda表达式创建接口的对象
- 可以在接口上标注
@FunctionalInterface
注解,用于检查是否满足条件
函数式编程思想:
- 函数是一等公民,注重获取结果
内置的函数式接口
之前常见的函数式接口
java.lang.Runnable
,方法:public void run()
java.lang.Iterable<T>
,方法:public Iterator<T> iterate()
java.lang.Comparable<T>
,方法:public int compareTo(T t)
java.util.Comparator<T>
,方法:public int compare(T t1, T t2)
四大核心函数接口
函数式接口 | 称谓 | 抽象方法 | 用途 |
---|---|---|---|
Consumer<T> | 消费型接口 | void accept(T t) | 对类型为T的对象进行操作 |
Supplier<T> | 供给型接口 | T get() | 返回类型为T的对象 |
Function<T, R> | 函数型接口 | R apply(T t) | 对对象进行操作,返回结果 |
Predicate<T> | 判断型接口 | boolean test(T t) | 判断对象是否满足某条件 |
- 消费型接口
函数式接口 | 抽象方法 | 描述 |
---|---|---|
BiConsumer<T,U> | void accept(T t, U u) | 接收两个对象,用于完成功能 |
DoubleConsumer | void accept(double value) | 接收一个double值 |
IntConsumer | void accept(int value) | 接收一个int值 |
LongConsumer | void accept(long value) | 接收一个long值 |
ObjDoubleConsumer<T> | void accept(T t, double value) | 接收一个对象和一个double值 |
ObjIntConsumer<T> | void accept(T t, int value) | 接收一个对象和一个int值 |
ObjLongConsumer<T> | void accept(T t, long value) | 接收一个对象和一个long值 |
- 供给型接口
接口名 | 抽象方法 | 描述 |
---|---|---|
BooleanSupplier | boolean getAsBoolean() | 返回一个boolean值 |
DoubleSupplier | double getAsDouble() | 返回一个double值 |
IntSupplier | int getAsInt() | 返回一个int值 |
LongSupplier | long getAsLong() | 返回一个long值 |
- 判断型接口
接口名 | 抽象方法 | 描述 |
---|---|---|
BiPredicate<T,U> | boolean test(T t, U u) | 接收两个对象 |
DoublePredicate | boolean test(double value) | 接收一个double值 |
IntPredicate | boolean test(int value) | 接收一个int值 |
LongPredicate | boolean test(long value) | 接收一个long值 |
- 函数型接口(看套路总结即可)
接口名 | 抽象方法 | 描述 |
---|---|---|
UnaryOperator<T> | T apply(T t) | 接收T类型,返回T类型 |
DoubleFunction<R> | R apply(double value) | 接收double,返回R类型 |
IntFunction<R> | R apply(int value) | 接收int,返回R类型 |
LongFunction<R> | R apply(long value) | 接收long,返回类型 |
ToDoubleFunction<T> | double applyAsDouble(T value) | 接收T类型,返回double |
ToIntFunction<T> | int applyAsInt(T value) | 接收T类型,返回int |
ToLongFunction<T> | long applyAsLong(T value) | 接收类型T,返回long |
DoubleToIntFunction | int applyAsInt(double value) | 接收double,返回int |
DoubleToLongFunction | long applyAsLong(double value) | 接收double,返回long |
IntToDoubleFunction | double applyAsDouble(int value) | 接收int,返回double |
IntToLongFunction | long applyAsLong(int value) | 接收int,返回long |
LongToDoubleFunction | double applyAsDouble(long value) | 接收long,返回double |
LongToIntFunction | int applyAsInt(long value) | 接收long,返回int |
DoubleUnaryOperator | double applyAsDouble(double operand) | 接收double,返回double |
IntUnaryOperator | int applyAsInt(int operand) | 接收int,返回int |
LongUnaryOperator | long applyAsLong(long operand) | 接收long,返回long |
BiFunction<T,U,R> | R apply(T t, U u) | 接收T类型和U类型,返回一个R类型 |
BinaryOperator<T> | T apply(T t, T u) | 接收两个T类型,返回T类型 |
ToDoubleBiFunction<T,U> | double applyAsDouble(T t, U u) | 接收T类型和U类型,返回double |
ToIntBiFunction<T,U> | int applyAsInt(T t, U u) | 接收T类型和U类型,返回int |
ToLongBiFunction<T,U> | long applyAsLong(T t, U u) | 接收T类型和U类型,返回long |
DoubleBinaryOperator | double applyAsDouble(double left, double right) | 接收两个double,返回double |
IntBinaryOperator | int applyAsInt(int left, int right) | 接收两个int,返回int |
LongBinaryOperator | long applyAsLong(long left, long right) | 接收两个long,返回long |
命名套路:
Operator:参数返回值类型一致
Fucntion:参数返回值类型不一致
Int
-UnaryOperator
Int
-Function
To-Int
-Function
Double-To-Int
-Function
Bi
-Function
To-Int-Bi
-Function
Binary
-Operator
Int-Binary-
Operator
方法引用与构造器引用
JDK8新特性
本质:使用已有方法赋值lambda表达式,只要类型一致就成立
方法引用
当要传给lambda体的操作,已经有实现的方法时:
对象::实例方法
类::静态方法
类::实例方法
1 | Consumer<String> con = System.out::println; |
构造器引用
当Lambda表达式是为了创建一个对象,且满足Lambda表达式形参时:
类名::new
1 | Supplier<Employee> sup = Employee::new; |
数组构造引用
当Lambda表达式是为了创建一个数组对象,且满足Lambda表达式形参时:
数组类型名::new
1 | Function<Integer,String[]> func = String[]::new; |
Stream API
JDK8新特性
- 使用Stream API对集合进行操作,就类似于使用SQL执行数据库查询
- Stream和Collection的区别
- Collection是一种静态的内存数据结构,核心是数据
- Stream是有关计算的,核心是计算
- Stream操作流程:创建->中间操作->终止操作
创建Stream实例
方法一:通过集合
java8种Collection接口被扩展,提供了两个新的方法
default Stream<E> stream()
: 返回一个顺序流default Stream<E> parallelStream()
: 返回一个并行流
1 | Stream<Integer> stream = list.stream(); |
方法二:通过数组
1 | Stream<String> stream = Arrays.stream(arr); |
方法三:通过Stream.of()创建
1 | Stream<Integer> stream = Stream.of(1,2,3,4,5); |
方法四:创建无限流
可以使用Stream.iterate()
和Stream.generate()
,创建无限流
- 迭代:
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
- 生成:
public static<T> Stream<T> generate(Supplier<T> s)
1 | Stream<Integer> stream = Stream.iterate(0, x -> x + 2); |
中间操作
除非流水线上除法终止操作,否则中间操作不会执行任何处理。所有操作会一次性全部处理
- 筛选和切片
方 法 | 描 述 |
---|---|
filter(Predicatep) | 接收Lambda,从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。 若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
- 映射
方法 | 描述 |
---|---|
map(Function f) | 函数被应用到每个元素上,将其映射成新的元素 |
mapToDouble(ToDoubleFunction f) | 函数被应用到每个元素上,产生新的DoubleStream |
mapToInt(ToIntFunction f) | 函数被应用到每个元素上,产生新的IntStream |
mapToLong(ToLongFunction f) | 函数被应用到每个元素上,产生新的LongStream |
flatMap(Function f) | 将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
- 排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
终止操作
- 匹配和查找
方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代 (使用 Collection 接口需要用户去做迭代,称为外部迭代) |
- 归约
方法 | 描述 |
---|---|
reduce(T identity, BinaryOperator b) | 带初始值,可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) | 不带初始值,可以将流中元素反复结合起来,得到一个值。返回Optional<T> |
- 收集
方 法 | 描 述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收参数:Collector接口的实现 |
Collectors类中帮我们实现了很多静态方法,可以帮助我们很方便的实现收集
方法 | 返回类型 | 作用 | 举例 |
---|---|---|---|
toList | Collector<T, ?, List<T>> | 收集到List | .stream().collect(Collectors.toList()); |
toSet | Collector<T, ?, Set<T>> | 收集到Set | .stream().collect(Collectors.toSet()); |
toCollection | Collector<T, ?, C> | 收集到创建的集合 | .stream().collect(Collectors.toCollection(ArrayList::new)); |
counting | Collector<T, ?, Long> | 计算元素的个数 | .stream().collect(Collectors.counting()); |
summingInt | Collector<T, ?, Integer> | 对Integer属性求和 | .stream().collect(Collectors.summingInt(Employee::getSalary)); |
averagingInt | Collector<T, ?, Double> | 对Integer属性平均 | .stream().collect(Collectors.averagingInt(Employee::getSalary)); |
summarizingInt | Collector<T, ?, IntSummaryStatistics> | 收集流中Integer属性的统计值。如:平均值 | .stream().collect(Collectors.summarizingInt(Employee::getSalary)); |
joining | Collector<CharSequence, ?, String> | 连接流中每个字符串 | .stream().map(Employee::getName).collect(Collectors.joining()); |
maxBy | Collector<T, ?, Optional<T>> | 根据比较器选择最大值 | .stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))); |
minBy | Collector<T, ?, Optional<T>> | 根据比较器选择最小值 | .stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))); |
reducing | Collector<T, ?, Optional<T>> | 从一个作为累加器的初始值开始,利用BinaryOperator 逐个结合,从而归约成单个值 | .stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum)); |
collectingAndThen | Collector<T,A,R> | 包裹另一个收集器,对其结果转换函数 | .stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); |
groupingBy | Collector<T, ?, Map<K, List<T>>> | 根据某属性值对流分组,属性为K,结果为V | .stream().collect(Collectors.groupingBy(Employee::getStatus)); |
partitioningBy | Collector<T, ?, Map<Boolean, List<T>>> | 根据true或false进行分区 | .stream().collect(Collectors.partitioningBy(Employee::getManage)); |
Optional类
JDK8新特性
Optional<T>
类java.util.Optional
是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。如果值存在,则isPresent()方法会返回true,调用get()方法会返回该对象。
- 创建Optional类的方法:
1 | static <T> Optional<T> empty(); // 创建空的Optional实例 |
- 判断Optional容器中是否包含对象:
1 | boolean isPresent(); // 判断值是否存在 |
- 获取Optional容器的对象
1 | T get() // 存在则返回值,否则抛异常 |
JDK9-11新增了特性
新增方法 | 描述 | 新增的版本 |
---|---|---|
boolean isEmpty() | 判断value是否为空 | JDK 11 |
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) | 非空执行参数1; 否则空执行参数2 | JDK 9 |
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) | 非空返回对应的Optional; 否则返回参数封装的Optional | JDK 9 |
Stream<T> stream() | 非空返回仅此value的Stream; 否则返回空Stream | JDK 9 |
T orElseThrow() | 非空返回value; 否则抛异常 NoSuchElementException | JDK 10 |
可以创建空Stream
JDK9新特性
Java8中Stream不能完全为空,否则会报空指针异常。Java9中的ofNullable
方法允许创建一个单元素Stream,可以包含空元素
1 | // 可以 |
iterator终止方式
JDK9新特性
定义了重载的新的iterator方法,可以定义终止条件
1 | // 以前需要靠limit |
jshell命令
JDK9新特性
- jShell命令是Java的REPL工具(交互式编程环境,read-evaluate-print-loop),可以像python那样一行一行执行
- 命令行输入
jshell
即可开始使用
1 | jshell |
- 不是很常用,略过
String存储结构和API变更
JDK9新特性
存储结构变化
产生背景:
The current implementation of the String class stores characters in a char array, using two bytes (sixteen bits) for each character. Data gathered from many different applications indicates that strings are a major component of heap usage and, moreover, that most String objects contain only Latin-1 characters. Such characters require only one byte of storage, hence half of the space in the internal char arrays of such String objects is going unused.
使用说明:
We propose to change the internal representation of the String class from a UTF-16 char array to a byte array plus an encoding-flag field. The new String class will store characters encoded either as ISO-8859-1/Latin-1 (one byte per character), or as UTF-16 (two bytes per character), based upon the contents of the string. The encoding flag will indicate which encoding is used.
对StringBuilder,StringBuffer等来说也是如此
String-related classes such as AbstractStringBuilder, StringBuilder, and StringBuffer will be updated to use the same representation, as will the HotSpot VM’s intrinsic string operations.
结论:String 不用 char[] 来存储,改成了 byte[] 加上编码标记,节约了一些空间
API变化
新增字符串处理方法
JDK11新特性
描述 | 举例 |
---|---|
判断字符串是否为空白 | .isBlank() |
去除首尾空白 | .strip() |
去除尾部空格 | .stripTrailing() |
去除首部空格 | .stripLeading() |
复制字符串 | .repeat(3) |
字符串按行分为流 | Stream<String> lines = str.lines(); |
实现了Constable接口
JDK12新特性
1 | public final class String implements java.io.Serializable, |
- Constable接口
1 | // Constable定义了方法,用于返回Optianl对象 |
JDK12
实现接口的,其实就是用了Optional.of
1 |
|
1 | Optional<String> optional = str.describeConstable(); |
transform方法
JDK12新特性
1 | public <R> R transform(Function<? super String, ? extends R> f) { |
例代码子:
1 | // 有一点类似流中的map |
局部变量类型推断
JDK10新特性
本特性允许开发人员省略通常不必要的类型声明
1 | // 局部变量 |
注意:
- var不是关键词,而是一个类型名
- var不会改变Java是一门静态类型语言的事实。编译器负责推断出结果,将结果写入字节码文件。
文本块
JDK13新特性
1 | // 以前 |
JDK14预览版增加了两个新的语法,JDK15转正
\
:取消换行\s
:表示一个空格
1 | String sql2 = """ |
switch表达式
JDK12预览版特性,JDK14转正
- 使用
case L ->
- 省略了break语句
- 可以将多个case合并在一起
1 | Fruit fruit = Fruit.GRAPE; |
- 更进一步,还可以处理返回值
1 | Fruit fruit = Fruit.GRAPE; |
- JDK13中引入了yield语句。switch语句应使用yield,而不是return。return会直接跳出当前方法,而yield只会跳出当前switch块。
1 | String x = "3"; |
JDK17预览特性:switch的模式匹配
1 | // 自动完成模式匹配,大大简化代码 |
instanceof的模式匹配
JDK14预览版特性,JDK16转正
实现简洁的类型安全代码。使用该方法,可以减少Java中显示强制转换的数量。
- 旧写法
1 | if (obj instanceof String) { |
- 现在的写法
1 | if (obj instanceof String str) { |
Record
JDK14预览版推出,JDK16转正
用record
声明一个类时,该类将自动拥有以下功能:
- 获取成员变量的简单方法,比如例题中的 name() 和 partner() 。注意区别于我们平常getter()的写法。
- 一个 equals 方法的实现,执行比较时会比较该类的所有成员属性。
- 重写 hashCode() 方法。
- 一个可以打印该类所有成员属性的 toString() 方法。
- 包含所有参数的构造方法。
此外:
还可以定义静态字段、静态方法、构造器或实例方法。
不能定义实例字段;类不能声明为abstract;不能声明显式的父类等。
1 | //不可以将record定义的类声明为abstract |
其它结构变化
下划线使用的限制
JDK9新特性
现在不允许使用”_”作为变量名
更简化的编译运行程序
JDK11新特性
以前
1 | // 编译 |
现在
1 | java JavaStack.java |
GC方面新特性
- 此部分待更新
参考文档
https://zhuanlan.zhihu.com/p/458509231
- 标题: JDK8到JDK17新特性
- 作者: 布鸽不鸽
- 创建于 : 2023-04-22 22:18:51
- 更新于 : 2023-06-09 15:05:50
- 链接: https://xuedongyun.cn//post/54344/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。