JDK从1995年发布起至今已历经20多年,从JDK1.0升级到JDK17(October 19, 2021),本节先一起回顾一下JDK的版本变迁和各版本的新特性
1995年5月23日,Java语言诞生;
1996年1月,第一个JDK-JDK1.0诞生;
1996年4月,10个最主要的操作系统供应商申明将在其产品中嵌入Java技术;
1996年9月,约8.3万个网页应用了Java技术来制作;
1997年2月18日,JDK1.1发布;
1997年4月2日,JavaOne会议召开,参与者逾一万人,创当时全球同类会议纪录;
1997年9月,JavaDeveloperConnection社区成员超过十万;
1998年2月,JDK1.1被下载超过2,000,000次;
1998年12月8日,Java 2企业平台J2EE发布;
1999年6月,SUN公司发布Java三个版本:标准版(J2SE)、企业版(J2EE)和微型版(J2ME);
2000年5月8日,JDK1.3发布;
2001年6月5日,Nokia宣布到2003年将出售1亿部支持Java的手机;
2001年9月24日,J2EE1.3发布;
2002年2月26日,J2SE1.4发布,此后Java的计算能力有了大幅提升
2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性,J2SE1.5更名为Java SE 5.0;有诸多重大新特性;代号:Tiger(里程碑版本)
2006年12月,SUN公司发布JDK6.0;代号: Mustang 此版本持续了5年之久才发布新版本,是最经典的版本。
2009年12月,SUN公司发布Java EE 6;
2010年11月,由于甲骨文对Java社区的不友善,因此Apache扬言将退出JCP;
2011年7月28日,甲骨文发布Java SE 7;
2014年3月18日,甲骨文发表Java SE 8。(重大版本 - LTS)
2017年9月21日,JDK9发布。从JDK9开始固定为每半年一个版本,更新内容相应缩减。
2018年3月21日,JDK10发布。
2018年9月25日,JDK11发布。(长期维护版本 - LTS)
2019年3月19日,JDK12发布。
2019年9月17日,JDK13发布。
2020年3月17日,JDK14发布。
2020年9月15日,JDK15发布。
2021年3月16日,JDK16发布。
2021年9月, JDK17发布。(长期维护版本 - LTS)
对重要版本的新特性做一下说明。
改进集合框架,如新增HashMap替代旧的HashTable(常用)
开始提供JIT(Just In Time)编译器;
Dynamic Proxy: 加入了JDK动态代理(常用)
NIO: 在传统BIO的基础上引入了NIO(Non-Blocking IO)(常用)。
里程碑版本,大部分人也是从该版本开始接触Java。引入了很多意义深远的特性,如下:
1)自动拆箱/装箱(Auto Inbox/Outbox)(常用)
2)枚举(Enum)(常用)
3)静态导入 (static import)
4)可变参数列表 (var args)(常用)
5)范型(Generic)(常用)
6)增强for循环(for-each)(常用)
7)注解(Annotation)(常用)
8)协变返回类型:实际返回类型可以是要求返回类型的一个子类
9)concurrent并发包(Doug leg)(常用)
1)Compiler API,可以实现动态编译Java源文件,如jsp编译引擎就是动态的,修改后无需重启服务器
2)对脚本语言的支持:如js, ruby,groovy
注:因JDK6至JDK7中间间隔了足足5年,所以这个版本是个经典版本,很稳定,官方长期维护,使用了很长时间。
JDK7版本从JDK6后5年才发布,原因是中间经历了Sun公司被收购。大体发布历程是:
2009 年 1 月, Sun 开始开发 JDK7 Milestone 1。
2009 年 11 月,Sun 在 Devoxx 2009 大会上宣布将闭包特性加入 JDK7,并将 JDK7 的发布日期推迟到 2010 年底。
2010 年 4 月,Oracle 收购 Sun。
2010 年 9 月,Mark Reinhold 在 JavaOne 大会上宣布 JDK7 将砍去 Lambda、Jigsaw 和部分 Coin 新特性并于 2011 年中发布,其余部分的新特性将于 2012 年底同 JDK8 一同发布。
2010 年 10 月,IBM 宣布加入 OpenJDK,将与 Oracle 合作共同开发 JDK。此后,Apple 和 SAP 也陆续加入 OpenJDK 社区。
2011 年 7 月 28 日,Oracle 正式发布 JDK7,并指定 OpenJDK7 为参考实现。
特性一:一组小的改进
1)Switch支持String(常用)
2)try … with … resource(常用)
3)范型类型自动推断(常用)
4)多重catch(常用)
5)数字可用下划线分割
特性二:G1垃圾回收器(Grabage-First Collector)(常用)
新出的垃圾回收器,用来替代Concurrent Mark-Sweep Collector(CMS)。目标是减少 Full GC 带来的暂停次数,增加吞吐量。
特性三:concurrent包改进(常用)
Doug Lea在此版本引入了轻量级的fork/join框架来支持多核多线程的并发计算。此外,实现了 Phaser 类,它类似于 CyclicBarrier 和 CountDownLatch 但更灵活。最后,ThreadLocalRandom 类提供了线程安全的伪随机数生成器。
特性四:IO与网络的更新
NIO2 主要包括了 3 个方面的改进:
特性五:JDBC更新(常用)
支持JDBC4.1和Rowset 1.1
1)接口默认方法(常用)
即接口中可以声明一个非抽象的方法作为默认的实现,方法的返回类型前要加上“default”关键字
2)lambda表达式(常用)
3)函数式接口(常用)
指仅仅包含一个抽象方法的接口,需要标记@FunctionalInterface
4)使用 :: 来传递方法引用,是lambda的简写(常用)
5)Stream API(常用)
6)新的日期工具类(常用)
1)模块化
即只加载应用运行需要的模块
2)改进的Java doc
生成的Java doc符合H5标准,支持API搜索
3)集合工厂方法,优化集合初始化(常用)
Set<Integer> ints = Set.of(1,2,3);
List<String> strings = List.of("first","second");
4)改进 Stream API
IntStream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println);
5)支持私有接口方法
6)HTTP/2(常用, 是预览版)
新的方式处理HTTP调用,用于替换 HttpURLConnection,并提供对WebSocket和HTTP/2的支持
7)多版本兼容
1)局部变量类型推断(常用)
即只能作为局部变量类型,方法参数,返回类型等不可以。常见示例:
var str = "ABC"; //根据推断为 字符串类型
var l = 10L;//根据10L 推断long 类型
var flag = true;//根据 true推断 boolean 类型
var flag1 = 1;//这里会推断boolean类型。0表示false 非0表示true
var list = new ArrayList<String>(); // 推断 ArrayList
var stream = list.stream(); // 推断 Stream
2)并行full gc的G1
通过并行Full GC, 改善G1的延迟。目前对G1的full GC的实现采用了单线程-清除-压缩算法。JDK10开始使用并行化-清除-压缩算法。
3)基于实验Java的JIT编译器
启用基于Java的JIT编译器Graal,它是JDK9中引入的Ahead-of-time(AOT)编译器的基础。
1)增加一些实用API(常用)
String str = "woshidage";
boolean isblank = str.isBlank(); //判断字符串是空白
boolean isempty = str.isEmpty(); //判断字符串是否为空
String result1 = str.strip(); //首尾空白
String result2 = str.stripTrailing(); //去除尾部空白
String result3 = str.stripLeading(); //去除首部空白
String copyStr = str.repeat(2); //复制几遍字符串
long lineCount = str.lines().count(); //行数统计
2)HttpClient增强(常用,已转换为正式版)
同时提供了同步调用和异步调用实现。JDK对http对调用支持已经足够强,以前apache提供的httpComponents基本可以去除了。
4)ZGC
JDK11最瞩目的特性,但目前是实验性质的。目标是GC暂停时间不会超过10ms,既能处理几百兆的小堆,也能处理几个T的大堆。
5)完全支持Linux容器(常用)
JDK10开始,JVM可以识别当前是否在容器中运行,能接受容器设置的内存限制和CPU限制。
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
如今可简化为:
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
JDK13前:
String html = "\n" +
" \n" +
" Hello, world
\n" +
" \n" +
"\n";
现在:
String html = """
Hello, world
""";
if (o instanceof String) {
String s = (String)o;
System.out.println(s.length);
}
现在可以增强为:
if (o instanceof String s) {
System.out.println(s.length);
}
Exception in thread "main" java.lang.NullPointerException
at jdk14.NullTest.<init>(NullTest.java:16)
at jdk14.Main.main(Main.java:15)
如果异常信息是链式调用时发生,如:a.b.c.d…, 此时很难直接定位NullPointerException发生在哪里。现在打印信息得到了增强:
Exception in thread "main" java.lang.NullPointerException:
Cannot read field "c" because "a.b" is null
at Prog.main(Prog.java:5)
JEP 385 Deprecate RMI Activation for Removal
RMI Activation被标记为Deprecate,将会在未来的版本中删除(JDK17)。RMI大家应该都清楚,RMI就是Remote Method Invocation,翻译成中文就是远程方法调用,是在JDK1.2中引入的。RMI为java提供了开发分布式系统的强大能力。而J2EE的规范EJB就是使用RMI来实现的bean的远程调用的。在RMI系统中,远程系统中存在很多分布式对象,如果这些分布式对象一直处于活动状态的话,将会占用很多宝贵的系统资源。于是RMI引入了一种lazy Activation的方式,这种方式就叫做延迟激活。对于现代应用程序来说,分布式系统大部分都是基于Web的,web服务器已经解决了穿越防火墙,过滤请求,身份验证和安全性的问题,并且也提供了很多延迟加载的技术。所以在现代应用程序中,RMI Activation已经很少被使用到了。并且在各种开源的代码库中,也基本上找不到RMI Activation的使用代码了。为了减少RMI Activation的维护成本,在JDK8中,RMI Activation被置为可选的。现在在JDK15中,终于可以废弃了。
JEP 339 Edwards-Curve Digital Signature Algorithm (EdDSA)
实现了EdDSA椭圆曲线签名算法。
JEP 375 Pattern Matching for instanceof (second preview)
该功能已经在JDK14初次引入,可看上文介绍
JEP 384 Records (Second Preview)
引入了Record类型,解决定义大量get/set方法的问题,可一定程度替代掉lomobok
示例如下:
public record Address(
String addressName,
String city
) {}
public record CustUser(
String firstName,
String lastName,
Address address,
int age
) {}
Record和普通的类的区别就在于Record多了一个括号括起来的定义的字段。
Record类默认是final的,里面的字段默认是private final的。
可借助IDE的反编译功能,反编译字节码可得到Record类的实现:
public final class CustUser extends java.lang.Record {
private final java.lang.String firstName;
private final java.lang.String lastName;
private final com.flydean.records.Address address;
private final int age;
public CustUser(java.lang.String firstName, java.lang.String lastName, com.flydean.records.Address address, int age) { /* compiled code */ }
public java.lang.String toString() { /* compiled code */ }
public final int hashCode() { /* compiled code */ }
public final boolean equals(java.lang.Object o) { /* compiled code */ }
public java.lang.String firstName() { /* compiled code */ }
public java.lang.String lastName() { /* compiled code */ }
public com.flydean.records.Address address() { /* compiled code */ }
public int age() { /* compiled code */ }
}
可以看出Record类继承自Record类,属性默认private final,这意味着Record实例是immutable(不可变的), 且有一个默认的包含所有参数的构造方法,其他如toString(), hashCode(), equals()已得到了默认实现。
对于Record可以做一定限度的定制,如校验属性,定义新属性。
public record CustUserWithBody(
String firstName,
String lastName,
Address address,
int age
) {
public String fullName(){
return firstName + lastName;
}
public CustUserWithBody {
if (age < 18) {
throw new IllegalArgumentException( "年纪太小");
}
}
}
该版本是继JDK11之后3年新推出的长期支持版本。
总体来说JDK17没有在语言层面有新的改进。
市面上有各种jdk,最权威的是官方发布的oracle jdk,其他的还有adoptopenjdk, azul zulu jdk, Amazon Corretto, alibaba dragonwell, Temurin等。 oracle jdk 和Open jdk有什么区别?为什么又冒出各种各样的jdk? Oracle jdk从2019年之后需要商业收费,公司该如何选择?本节将对这些问题做一些澄清。
OpenJDK可理解为两个:源代码存储库和发行版本。
源代码存储库角度: 就源代码而言,只有一套Java源代码,存在OpenJDK项目中,地址是:https://github.com/openjdk/jdk。 这个项目由Oracle公司主导,还有很多大公司参与合作开发,如:IBM, Apple, Microsoft等。
发行版本角度: 各个公司基于同一套源码,加上一些自己的实用工具,为不同的平台(os:Linux, Mac, Windows; 架构:aarch64, x64)编译出二进制包,并附上授权声明,提供给大家下载使用。 各个不同的发行版本也会承诺如有版本更新也会及时释出新版本。
OracleJDK从9开始一样是基于OpenJDK,它额外的提供了一些闭源组件,以及商用license。可以理解为OracleJDK和OpenJDK源码几乎就一样,使用Oracle JDK需要付费,同时也能得到相应的服务: 客服支持,版本更新以及一些实用工具。
Temurin OpenJDK
原来是AdoptOpenJDK ,是2017年,一群Java用户组(JUG)成员、开发者和供应商(包括亚马逊、微软、Pivotal、Redhat等)建立了一个社区称作AdoptOpenJDK。他们提供免费、稳固的OpenJDK build,可用性与更新周期更长。甚至还有两个不同的Java虚拟机可供选择:HotSpot和OpenJ9。
目前它已归属于Eclipse 基金会,下载地址:https://adoptium.net/
该版本是大多数用户(无特殊功能要求)的最佳选择。
Oracle OpenJDK
oracle自己也基于OpenJDK编译了一套发行版,去除了商标,并且免费,但不承诺会及时更新。
Azul Zulu OpenJDK
官方称是世界上最大的OpenJDK商用提供商。它自家闭源的zing jvm在hotspot jvm的基础上进行了大量优化。zulu是Azul提供的开源版本,可自由使用,但不提供支持。 需要支持可选用商业版本:
商业版本分为两种:
Azul Platform Core
即之前的zulu enterprise/embedded版本
Azul Platform Prime
即之前的zing。它提供更优秀的性能。
zulu是本人比较喜欢的版本。下载地址:https://www.azul.com/downloads/?package=jdk
Microsoft OpenJDK
微软也发行了自己的openJDK版本,且不仅仅是Windows版本, macOS, Linux也有对应释出版本。果然Microsoft越来越开放了。 按微软的说法其Azure, SQL Server, Visual Studio Code, LinkedIn等都使用了java技术。
微软提供的软件质量肯定是妥妥的,用于生产都没什么问题,下载地址:https://www.microsoft.com/openjdk
Dragonwell OpenJDK
最后一个介绍一下阿里释出的发行版,命名为龙井。Alibaba Dragonwell 是一款免费的, 生产就绪型Open JDK 发行版,提供长期支持,包括性能增强和安全修复。阿里巴巴拥有最丰富的Java应用场景,覆盖电商,金融,物流等众多领域,世界上最大的Java用户之一。Alibaba Dragonwell作为Java应用的基石,支撑了阿里经济体内所有的Java业务。
阿里生产环境使用的OpenJDK,质量也是经的起考验,需要注意的是:
下载地址:https://www.aliyun.com/product/dragonwell