前言
JDK LTS 版每 2 年一个版本(原 3 年)
非 LTS 版每半年一个版本
JDK 8 2014-03 LTS 版本
JDK 11 2018-09 LTS 版本
JDK 12 2019-03 non-LTS 功能性版本
JDK 13 2019-09 non-LTS 功能性版本
JDK 14 2020-03 non-LTS 功能性版本
JDK 15 2020-09 non-LTS 功能性版本
JDK 16 2021-03 non-LTS 功能性版本
JDK 17 2021-09-15 LTS
JDK 18 2022-03 non-LTS 功能性版本
JDK 19 2022-09 non-LTS 功能性版本
JDK 20 2023-03 non-LTS 功能性版本
JDK 21 2023-09 LTS
Java 17+ 可以免费使用了,包括商用,更详细的条款可以阅读:
https://www.oracle.com/downloads/licenses/no-fee-license.html
JDK 17 是自 2018 年 JDK 11 后的第二个长期支持版本,支持到 2029 年 9 月,好家伙,支持时间长达 8 年,这下可以不用死守 JDK 8 了,JDK 17+ 也可以是一种新的选择了。。
下一个第三个长期支持版本是 JDK 21,时间为 2023 年 9 月,这次长期支持版本发布计划改了,不再是原来的 3 年一次,而是改成了 2 年一次!
另外,非长期支持版本还是半年发一次不变,下一个非长期支持版本计划在 2022/03 发布,但注意不要用在生产。
JDK 17 下载地址:
https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.zip
https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gzOpenJDK 17 发布地址:
http://openjdk.java.net/projects/jdk/17/
OpenJDK 17 下载地址:
https://jdk.java.net/17/
JEP
JDK Enhancement Process
Oracle发布了JDK增强提案与路线图进程,JEP的目的在于根据某个特性来定义所需的增强或是修改。
鼓励OpenJDK提交者贡献点子和扩展以改进OpenJDK生态圈。
进程文档明确指出 JEPs 并不会取代 Java Community Process;
因为 JCP 是标准 Java SE APIs 与相关接口的管理部门。
JEPs会经历各种状态转换,如下所示:
- 草案:开放讨论
- 张贴:进入JEP归档
- 提交:开始评估
- 活动:批准公开发布
- 候选:获准进入OpenJDK路线图
- 资助:由小组/区域领导判断给予全力资助
- 完成:完成与交付
- 撤回:退出(或许未来还会重新加入进来)
- 拒绝:现在或将来不值得继续
JDK9 集合加强
Jdk 9 里面为集合(List/ Set/ Map)都添加了
of
和copyOf
方法,它们两个都用来创建不可变的集合
示例1:
List list = List.of("Java", "Python", "C");
List copy = List.copyOf(list);
System.out.println(list == copy); // true
示例2:
List list = new ArrayList<String>();
List copy = List.copyOf(list);
System.out.println(list == copy); // false
源码:
static <E> List<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
return ImmutableCollections.emptyList();
case 1:
return new ImmutableCollections.List12<>(elements[0]);
case 2:
return new ImmutableCollections.List12<>(elements[0], elements[1]);
default:
return new ImmutableCollections.ListN<>(elements);
}
}
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
static <E> List<E> listCopy(Collection<? extends E> coll) {
if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
return (List<E>)coll;
} else {
return (List<E>)List.of(coll.toArray());
}
}
可以看出
copyOf
方法会先判断来源集合是不是AbstractImmutableList
类型的,如果是,就直接返回,如果不是,则调用of
创建一个新的集合。示例2因为用的 new 创建的集合,不属于不可变
AbstractImmutableList
类的子类,所以copyOf
方法又创建了一个新的实例,所以为false.注意:使用 of 和 copyOf 创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报
java.lang.UnsupportedOperationException
异常。
JDK9 Stream 加强
-
- 增加单个参数构造方法,可为null
Stream.ofNullable(null).count(); // 0
-
- 增加 takeWhile 和 dropWhile 方法
Stream.of(1, 2, 3, 2, 1)
.takeWhile(n -> n < 3)
.collect(Collectors.toList()); // [1, 2]
从开始计算,当 n < 3 时就截止。
Stream.of(1, 2, 3, 2, 1)
.dropWhile(n -> n < 3)
.collect(Collectors.toList()); // [3, 2, 1]
这个和上面的相反,一旦 n < 3 不成立就开始计算。
- 3)iterate重载
这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
Optional 加强
Opthonal 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换成一个 Stream, 或者当一个空 Optional 时给它一个替代的。
Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
.or(() -> Optional.of("javastack"))
.get(); // javastack
InputStream 加强
InputStream 终于有了一个非常有用的方法:transferTo,可以用来将数据直接传输到 IutputStream,这是在处理原始数据流时非常常见的一种用法,如下示例。
var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
inputStream.transferTo(outputStream);
}
JDK10 局部变量类型推断
1、字面量定义局部变量
private static void testVar() {
var javastack = "javastack";
System.out.println(javastack);
}
2、接收方法返回值定义局部变量
private static void testMethod() {
var javastack = getJavastack();
System.out.println(javastack);
}
public static String getJavastack() {
return "javastack";
}
3、循环中定义局部变量
private static void testLoop() {
for (var i = 0; i < 3; i++) {
for (var m = 10; m < 15; m++) {
System.out.println(i + m);
}
}
}
4、泛型结合局部变量
private static void testGeneric() {
// 表达式1
List<String> list1 = new ArrayList<>();
list1.add("javastack");
// 表达式2
var list2 = new ArrayList<>();
list2.add(2018);
// 表达式3
var list3 = new ArrayList<String>();
list3.add("javastack");
}
表达式1后面
<>
里面 jdk 1.7+开始是不用带具体类型的,在接口中指明就行了。
表达式2中如果使用var
的话,<>
里面默认会是Object
的,所以可以添加任意类型。
表达式3中在<>
强制使用了 String 来指定泛型。
局部变量类型推断不能用在以下场景
- 1、类成员变量类型
- 2、方法返回类型
- 3、Lambda 表达式
优点:简化代码
缺点:掩盖类型
var 关键字原理
var其实就是 Java 10 增加的一种语法糖而已,在编译期间会自动推断实际类型,其编译后的字节码和实际类型一致,如以下例子所示。
private static void testByteCode() {
String javastack1 = "javastack";
var javastack2 = "javastack";
}
编译成字节码后:
private static testByteCode()V
L0
LINENUMBER 22 L0
LDC "javastack"
ASTORE 0
L1
LINENUMBER 23 L1
LDC "javastack"
ASTORE 1
L2
LINENUMBER 24 L2
RETURN
L3
LOCALVARIABLE javastack1 Ljava/lang/String; L1 L3 0
LOCALVARIABLE javastack2 Ljava/lang/String; L2 L3 1
MAXSTACK = 1
MAXLOCALS = 2
可以看出
javastack1
和javastack2
都是虚拟机所认识的的本地变量类型:java.lang.String
,虚拟机并不认识 var, 所以var
并不神奇。
JDK11 字符串加强
// 判断字符串是否为空白
" ".isBlank(); // true
// 去除首尾空格
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
/**************** repeat ******************/
// 复制字符串
"Java".repeat(3); // "JavaJavaJava"
// 小于0:java.lang.IllegalArgumentException
str.repeat(-2);
// 等于0:空白串("")
str.repeat(0);
// java.lang.OutOfMemoryError
// 并不是可以无限增长的,有使用限制的,达到一定量就会报内存溢出异常
str.repeat(Integer.MAX_VALUE);
/**************** lines ******************/
// 方法返回一个字符串 Stream, 可以识别 \n 和 \r 换行符换行
public Stream<String> lines() {
return isLatin1() ? StringLatin1.lines(value)
: StringUTF16.lines(value);
}
// 行数统计
"A\nB\nC".lines().count(); // 3
// 如批量读取文件内容到一个 Stream 中,就能很好的识别行结束符了
JDK11 快速运行源代码
/*旧方法*/
// 编译
javac Javastack.java
// 运行
java Javastack
/*新方法*/
java Javastack.java
JDK12 String 字符串骚操作
1.transform
transform:即字符串转换,源码:
public <R> R transform(Function<? super String, ? extends R> f) {
return f.apply(this);
}
private static void testTransform() {
System.out.println("======test java 12 transform======");
List<String> list1 = List.of("Java", " Python", " C++ ");
List<String> list2 = new ArrayList<>();
list1.forEach(element ->
list2.add(element.transform(String::strip)
.transform(String::toUpperCase)
.transform((e) -> "Hi," + e))
);
list2.forEach(System.out::println);
/**输出:
======test java 12 transform======
Hi,JAVA
Hi,PYTHON
Hi,C++
*/
}
2.indent
private static void testIndent() {
System.out.println("======test java 12 indent======");
// 换行符 \n 后前缩进 N 个空格,为 0 或负数不缩进。
String result = "Java\n Python\nC++".indent(3);
System.out.println(result);
}
indent 的核心源码:
private String indent(int n, boolean removeBlanks) {
Stream<String> stream = removeBlanks ? lines(Integer.MAX_VALUE, Integer.MAX_VALUE)
: lines();
if (n > 0) {
final String spaces = " ".repeat(n);
stream = stream.map(s -> spaces + s);
} else if (n == Integer.MIN_VALUE) {
stream = stream.map(s -> s.stripLeading());
} else if (n < 0) {
stream = stream.map(s -> s.substring(Math.min(-n, s.indexOfNonWhitespace())));
}
return stream.collect(Collectors.joining("\n", "", "\n"));
}
其实就是调用了 lines() 方法来创建一个 Stream,然后再往前拼接指定数量的空格。
3.describeConstable
private static void testDescribeConstable() {
System.out.println("======test java 12 describeConstable======");
String name = "Java爱好者";
Optional<String> optional = name.describeConstable();
System.out.println(optional.get());
}
结果输出:
======test java 12 describeConstable======
Java爱好者
Java 12, String 实现了 Constable 接口:
java.lang.constant.Constable
这个接口就有一个方法,源码如下:
public interface Constable {
Optional<? extends ConstantDesc> describeConstable();
}
Java 12 String 的实现源码:
@Override
public Optional<String> describeConstable() {
return Optional.of(this);
}
很简单,其实就是调用 Optional.of 方法返回一个 Optional 类型
JDK13 文本块
Java 13 之前:
String html = "<html>\n" +
" <body>\n" +
" <p>Hi, Java技术栈</p>\n" +
" <p>欢迎关注,分享更多干货</p>\n" +
" </body>\n" +
"</html>\n";
Java 13+:
String html = """
<html>
<body>
<p>Hi, Java技术栈</p>
<p>欢迎关注,分享更多干货</p>
</body>
</html>
""";
JDK14 instanceof 模式匹配
老代码写法:
if (object instanceof Kid) {
Kid kid = (Kid) object;
// ...
} else if (object instanceof Kiddle) {
Kid kid = (Kid) object;
// ...
}
新代码写法:
if (object instanceof Kid kid) {
// ...
} else if (object instanceof Kiddle kiddle) {
// ...
}
JDK14 Records 代替 Lombok?
不能完全代替!
public record Student(String name, int id, int age) {}
Records 类有以下限制:
- 1)record 类是 final 修饰的,所以不能被其他子类继承;
- 2)因为 Java 类是单继承,而自身又已经继承了 Record 类,所以不能再继承其他类,但是可以实现接口;
- 3)成员变量也是 final 类型的,所以其值或者引用不能被更改,如果是引用类型,可以修改对象里面的值。
JDK14 空指针异常详细信息
javastack.name = params.user.name;
----------------------------------
Exception in thread "main" java.lang.NullPointerException:
Cannot read field "name" because "params.user" is null
at Test.main(Test.java:3)
a[i][j][k] = 2020;
----------------------------------
Exception in thread "main" java.lang.NullPointerException:
Cannot load from object array because "a[i][j]" is null
at Test.main(Test.java:18)
在同一行上显示异常类型、异常消息会导致行很长,所以为了保持可读性,会在第二行显示详细异常信息。
这个功能在 Java 14 默认情况下是不开启的,可以使用以下 JVM 参数进行切换:
开启:-XX:+ShowCodeDetailsInExceptionMessages
关闭:-XX:-ShowCodeDetailsInExceptionMessages
为什么现在默认不开启?
1)性能
如果应用程序频繁地抛出并打印异常堆栈消息,势必会带来一定的开销、影响性能,所以应尽量避免这种开销。
2)安全
这个会导致更多源代码的暴露,如果这个不能接受,则不应由 JVM 配置应用程序打印,而应捕获并丢弃。
3)兼容性
过去的 JDK 都是不打印详细空指针异常信息的,JVM 相关工具要依赖于异常消息的准确格式,有可能会存在兼容性问题。
所以,这个特性暂时默认是关闭的,在未来不久的版本中会默认开启。
JDK15 特性介绍
- 371:Hidden Classes
隐藏类,这一看也是个很有意思的特性。
隐藏类是为框架(frameworks)所设计的,隐藏类不能直接被其他类的字节码使用,只能在运行时生成类并通过反射间接使用它们。
- 372:Remove the Nashorn JavaScript Engine
移除了 Nashorn
JavaScript 脚本引擎、APIs,以及 jjs
工具。这些早在 JDK 11 中就已经被标记为 deprecated
了,JDK 15 被移除就很正常了。
- 374:Disable and Deprecate Biased Locking
准备禁用和废除偏向锁,在 JDK 15 中,默认情况下禁用偏向锁,并弃用所有相关的命令行选项。
后面再确定是否需要继续支持偏向锁,国为维护这种锁同步优化的成本太高了。
- 377:ZGC: A Scalable Low-Latency Garbage Collector
ZGC:一个可伸缩、低延迟的垃圾回收器。
ZGC
最早是在 JDK 11 中集成进来的,JDK 15 只是将 ZGC
垃圾收集器从预览特性变更为正式特性而已,没错,转正了。
这个 JEP
不会更改默认的 GC,默认仍然是 G1
。
- 378:Text Blocks
文本块,是一个多行字符串,它可以避免使用大多数转义符号,自动以可预测的方式格式化字符串,并让开发人员在需要时可以控制格式。
文本块最早准备在 JDK 12 添加的,但最终撤消了,然后在 JDK 13 中作为预览特性进行了添加,然后又在 JDK 14 中再次预览,在 JDK 15 中,文本块终于转正,暂不再做进一步的更改。
- 379:Shenandoah: A Low-Pause-Time Garbage Collector
Shenandoah:一个低停顿时间的垃圾回收器。
Shenandoah
最早是在 JDK 12 中集成进来的,JDK 15 只是将 Shenandoah
垃圾收集器从预览特性变更为正式特性而已,没错,又是转正了。
- 383:Foreign-Memory Access API (Second Incubator)
外存访问 API(二次孵化),可以允许 Java 应用程序安全有效地访问 Java 堆之外的外部内存。
这个最早在 JDK 14 中成为孵化特性,JDK 15 继续二次孵化并对其 API 有了一些更新。
- 384:Records (Second Preview)
Records 最早在 JDK 14 中成为预览特性,JDK 15 继续二次预览。
Records 在某些场合可以干掉 Lombok
的存在,能自动生成了类构造器、toString()、hashCode()、equals(),以及类似 getter 的变量访问方法。
JDK17 switch 模式匹配(预览中)
老代码写法:
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
新代码写法:
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
JDK 17 Sealed Classes 密封类
在 JDK 15 中首次成为预览特性,在 JDK 16 中进行二次预览,在 JDK 17 中终于正式转正
public abstract sealed class Student
permits ZhangSan, LiSi, ZhaoLiu {
...
}
密封类可以用来增强 Java 编程语言,防止其他类或接口扩展或实现它们。
类 Student 被
sealed
修饰,说明它是一个密封类,并且只允许指定的 3 个子类继承
Oracle JDK VS OpenJDK
有的,虽然两者很接近,但也还是有一点区别!
- 1、Oracle JDK 提供了各种安装程序,还包含更新规则,而 OpenJDK 只提供了一个纯压缩包;
- 2、Usage Logging 仅在 Oracle JDK 中可用;
- 3、Oracle JDK 要求第三方加密提供程序使用 Java 加密扩展(JCE)进行签名,而 OpenJDK 继续允许使用未签名的第三方加密提供程序;
- 4、java -version 的输出也是不同的,Oracle JDK 返回 java 并包含 Oracle 特定的标识符,OpenJDK 返回 OpenJDK 并且不包含特定于 Oracle 的标识符;
- 5、许可证不同,Oracle JDK 17+ 是根据 Oracle 免费条款和条件许可发布的,而 OpenJDK 在 GPLv2wCP 下发布的;
- 6、Oracle JDK 源代码含有 “ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.”,其使用受许可条款约束的,而 OpenJDK 源代码可参考 GPL 许可条款;
后记
- Java 9 的模块化–壮士断"腕"的涅槃
- Java 10 实战第 1 篇:局部变量类型推断
- Java 11 已发布,String 还能这样玩!
- Java 11 正式发布,这 8 个逆天新特性教你写出更牛逼的代码
- Java 12 骚操作, String居然还能这样玩!
- Java 14 之模式匹配,非常赞的一个新特性!
- Java 14 祭出代码简化神器,Lombok 要被干掉了?
- Java 15 正式发布, 14 个新特性,刷新你的认知!!
- JDK 16 正式发布,一次性发布 17 个新特性
- JDK 17 发布,Oracle 宣布从 JDK 17 开始正式免费
- Shenandoah GC:一个来自JDK12的全新并发压缩垃圾回收器
- 新一代垃圾回收器ZGC的探索与实践
- 4.6 W 字总结!Java 11—Java 17特性详解
评论区