简介
记录一下JDK版本的历史更新和重要特性。
目前JDK更新较快,每半年发布一个版本,但是对于生产环境采用仍然建议使用LTS(长期支持版本)版本
按照 Oracle 公布的支持路线图,Java 11 将会获得 Oracle 提供的长期支持服务,直至2026年9月。
根据官网从Java 11开始提供用开源许可证和商业许可证的组合
更新记录
- 2018-11-09 补充JDK8的介绍和使用
一些术语
- JCP 是 Java Community Process(Java社区进程)的简称,社会各界Java组成的社区,规划和领导Java的发展。
- JEP 是 JDK Enhancement Proposals (Java 增强提案)的简称,JDK的版本变化将从这些提案中选取。
- JSR 是 Java Specification Requests(Java规范请求)的简称,是 JCP 成员向委员会提交的 Java 发展议案,经过一系列流程后,如果通过会成为 JEP,最终会体现在未来的Java中。
- TCK 是 Technology Compatibility Kit(技术兼容性测试)的简称, 如果一个平台型程序想要宣称自己兼容Java,就必须通过TCK测试
JDK6
- 集合框架增强。
- 为了更好的支持双向访问集合。添加了许多新的类和接口。
- 新的数组拷贝方法。Arrays.copyOf和Arrays.copyOfRange
1 | //以下为添加的新接口和类 |
- Scripting. 可以让其他语言在java平台上运行。 java6包含了一个基于Mozilla Rhino实现的javascript脚本引擎。
- 支持JDBC4.0规范。
JDK7
- 二进制前缀0b或者0B。整型(byte, short, int, long)可以直接用二进制表示。
- 字面常量数字的下划线。用下划线连接整数提升其可读性,自身无含义,不可用在数字的起始和末尾。
- switch 支持String类型。
- 泛型实例化类型自动推断。
- try-with-resources语句。
- 单个catch中捕获多个异常类型(用| 分割)并通过改进的类型检查重新抛出异常。
JDK8
- Lambda 表达式(Lambda Expressions) − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。
- 方法引用(Method references) − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
- 默认方法 (Default methods)− 默认方法就是一个在接口里面有了一个实现的方法。
- 新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
- Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
- Date Time API − 加强对日期与时间的处理。
- Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
- Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
java.util 包下的改进,提供了几个实用的工具类。
并行数组排序。
标准的Base64编解码。
支持无符号运算。java.util.concurrent 包下增加了新的类和方法。
java.util.concurrent.ConcurrentHashMap 类添加了新的方法以支持新的StreamApi和lambada表达式。
java.util.concurrent.atomic 包下新增了类以支持可伸缩可更新的变量。
java.util.concurrent.ForkJoinPool类新增了方法以支持 common pool。
新增了java.util.concurrent.locks.StampedLock类,为控制读/写访问提供了一个基于性能的锁,且有三种模式可供选择。HotSpot
删除了 永久代(PermGen).
方法调用的字节码指令支持默认方法。重复注解(Repeating Annotations)。重复注解提供了在同一声明或类型中多次应用相同注解类型的能力。
- 类型注解(Type Annotation)。在任何地方都能使用注解,而不是在声明的地方。
- 类型推断增强
- 方法参数反射(Method Parameter Reflection)。
- HashMap改进,在键值哈希冲突时能有更好表现。
部分特性说明:
1.Lambda 表达式
Lambda 表达式,也可称为闭包,允许把函数作为一个方法的参数
语法
lambda 表达式的语法格式如下:1
2
3(parameters) -> expression
或
(parameters) ->{ statements; }
以下是lambda表达式的重要特征:
1 | 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。 |
Lambda 表达式实例
1 | # 1. 不需要参数,返回值为 5 |
2.方法引用
方法引用通过方法的名字来指向一个方法,可以使语言的构造更紧凑简洁,减少冗余代码。方法引用使用一对冒号 ::
语法
构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:1
2final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
静态方法引用:它的语法是Class::static_method,实例如下:1
cars.forEach( Car::collide );
特定类的任意对象的方法引用:它的语法是Class::method实例如下:1
cars.forEach( Car::repair );
特定对象的方法引用:它的语法是instance::method实例如下:1
2final Car police = Car.create( Car::new );
cars.forEach( police::follow );
方法引用实例
1 | public class Java8Tester { |
函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
如定义了一个函数式接口如下:1
2
3
4
5@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
}
那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):1
GreetingService greetService1 = message -> System.out.println("Hello " + message);
默认方法
Java 8 新增了接口的默认方法。
简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个default关键字即可实现默认方法。
1 | 为什么要有这个特性? |
语法
默认方法语法格式如下:
1 | public interface Vehicle { |
多个默认方法
一个接口有默认方法,考虑这样的情况,一个类实现了多个接口,且这些接口有相同的默认方法,以下实例说明了这种情况的解决方法:
1 | public interface Vehicle { |
第一个解决方案是创建自己的默认方法,来覆盖重写接口的默认方法:
1 | public class Car implements Vehicle, FourWheeler { |
第二种解决方案可以使用 super 来调用指定接口的默认方法:
1 | public class Car implements Vehicle, FourWheeler { |
静态默认方法
Java 8 的另一个特性是接口可以声明(并且可以提供实现)静态方法。例如:
1 | public interface Vehicle { |
Stream
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
1 | +--------------------+ +------+ +------+ +---+ +-------+ |
以上的流程转换为 Java 代码为:
1 | List<Integer> transactionsIds = |
什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作
元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
生成流
在 Java 8 中, 集合接口有两个方法来生成流:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流。
1 | List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); |
forEach
Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:
1 | Random random = new Random(); |
map
map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
1 | List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); |
filter
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
1 | List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); |
limit
limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:
1 | Random random = new Random(); |
sorted
sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
1 | Random random = new Random(); |
并行(parallel)程序
parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:
1 | List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); |
我们可以很容易的在顺序运行和并行直接切换。
Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
1 | List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); |
统计
另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。
1 | List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); |
Optional 类
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
类声明
以下是一个 java.util.Optional
1 | public final class Optional<T> |
Nashorn JavaScript
Nashorn 一个 javascript 引擎。
从JDK 1.8开始,Nashorn取代Rhino(JDK 1.6, JDK1.7)成为Java的嵌入式JavaScript引擎。Nashorn完全支持ECMAScript 5.1规范以及一些扩展。它使用基于JSR 292的新语言特性,其中包含在JDK 7中引入的 invokedynamic,将JavaScript编译成Java字节码。
与先前的Rhino实现相比,这带来了2到10倍的性能提升。
日期时间 API
ava 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。
在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:
Local(本地) − 简化了日期时间的处理,没有时区的问题。
Zoned(时区) − 通过制定的时区处理日期时间。
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
Base64
在Java 8中,Base64编码已经成为Java类库的标准。
Java 8 内置了 Base64 编码的编码器和解码器。
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:
基本:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
MIME:输出隐射到MIME友好格式。输出每行不超过76字符,并且使用’\r’并跟随’\n’作为分割。编码输出最后没有行分割。
JDK9
JDK 9 于2017年9月21日发布
新特性有:
- 模块化 —— Jigsaw(Java Platform Module System)
- 交互式命令行 —— JShell
- 进程操作改进
- 竞争锁的性能优化
- 分段代码缓存
- 优化字符串占用空间
- Javadoc
简化Doclet API。
支持生成HTML5格式。
加入了搜索框,使用这个搜索框可以查询程序元素、标记的单词和文档中的短语。
支持新的模块系统。 - JVM
增强了Garbage-First(G1)并用它替代Parallel GC成为默认的垃圾收集器。
统一了JVM 日志,为所有组件引入了同一个日志系统。
删除了JDK 8中弃用的GC组合。(DefNew + CMS,ParNew + SerialOld,Incremental CMS)。 - properties文件支持UTF-8编码,之前只支持ISO-8859-1。
- 支持Unicode 8.0,在JDK8中是Unicode 6.2。
- 支持私有接口方法(您可以使用diamond语法与匿名内部类结合使用)。
- 下划线不能用在变量名中。
- diamond语法与匿名内部类结合使用。
- 新的版本号格式。$MAJOR.$MINOR.$SECURITY.$PATCH
JDK10
北京时间 3 月 21 日,Oracle 官方宣布 Java 10 正式发布。新特性有:
- JEP 286: 局部变量的类型推导。该特性在社区讨论了很久并做了调查,可查看 JEP 286 调查结果。
- JEP 296: 将 JDK 的多个代码仓库合并到一个储存库中。
- JEP 304: 垃圾收集器接口。通过引入一个干净的垃圾收集器(GC)接口,改善不同垃圾收集器的源码隔离性。
- JEP 307: 向 G1 引入并行 Full GC。
- JEP 310: 应用类数据共享。为改善启动和占用空间,在现有的类数据共享(“CDS”)功能上再次拓展,以允许应用类放置在共享存档中。
- JEP 312: 线程局部管控。允许停止单个线程,而不是只能启用或停止所有线程。
- JEP 313: 移除 Native-Header Generation Tool (javah)
- JEP 314: 额外的 Unicode 语言标签扩展。包括:cu (货币类型)、fw (每周第一天为星期几)、rg (区域覆盖)、tz (时区) 等。
- JEP 316: 在备用内存设备上分配堆内存。允许 HotSpot 虚拟机在备用内存设备上分配 Java 对象堆。
- JEP 317: 基于 Java 的 JIT 编译器(试验版本)。
- JEP 319: 根证书。开源 Java SE Root CA 程序中的根证书。
- JEP 322: 基于时间的版本发布模式。“Feature releases” 版本将包含新特性,“Update releases” 版本仅修复 Bug 。
部分特性说明
1 | 1. var 类型推断。 |
JDK11
JDK 11 总共包含 17 个新的 JEP ,分别为:
- 181: Nest-Based Access Control(基于嵌套的访问控制)
- 309: Dynamic Class-File Constants(动态类文件常量)
- 315: Improve Aarch64 Intrinsics(改进 Aarch64 Intrinsics)
- 318: Epsilon: A No-Op Garbage Collector(Epsilon — 一个无操作的垃圾收集器)
- 320: Remove the Java EE and CORBA Modules(删除 Java EE 和 CORBA 模块)
- 321: HTTP Client (Standard)
- 323: Local-Variable Syntax for Lambda Parameters(用于 Lambda 参数的局部变量语法)
- 324: Key Agreement with Curve25519 and Curve448(Curve25519 和 Curve448 算法的密钥协议)
- 327: Unicode 10
- 328: Flight Recorder
- 329: ChaCha20 and Poly1305 Cryptographic Algorithms(ChaCha20 和 Poly1305 加密算法)
- 330: Launch Single-File Source-Code Programs(启动单一文件的源代码程序)
- 331: Low-Overhead Heap Profiling(低开销的 Heap Profiling)
- 332: Transport Layer Security (TLS) 1.3(支持 TLS 1.3)
- 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental) (可伸缩低延迟垃圾收集器)
- 335: Deprecate the Nashorn JavaScript Engine(弃用 Nashorn JavaScript 引擎)
- 336: Deprecate the Pack200 Tools and API (弃用 Pack200 工具和 API)
支持Unicode 10.0,在jdk10中是8.0。
标准化HTTP Client
编译器线程的延迟分配。添加了新的命令-XX:+UseDynamicNumberOfCompilerThreads动态控制编译器线程的数量。
新的垃圾收集器—ZGC。一种可伸缩的低延迟垃圾收集器(实验性)。
Epsilon。一款新的实验性无操作垃圾收集器。Epsilon GC 只负责内存分配,不实现任何内存回收机制。这对于性能测试非常有用,可用于与其他GC对比成本和收益。
Lambda参数的局部变量语法。java10中引入的var字段得到了增强,现在可以用在lambda表达式的声明中。如果lambda表达式的其中一个形式参数使用了var,那所有的参数都必须使用var。