JDK里程碑:JDK8到JDK17的重要特性汇总

648 阅读5分钟

从BenchMark可以看到,仅需要从JDK8升级到JDK17就能够获得64%的改进 — JavaOne开幕式

本文章的灵感来源于Java One开幕式上JDK开发者的这句话。JDK向前兼容的重要特性意味着,我们不需要改动任何代码只需要将运行源代码的JDK从8替换为JDK17就能够获得大量的提升(极地的成本)。

这篇文章讲汇总JDK8到JDK17的关键特性,理解为什么从JDK8到JDK17有着重要意义。

JDK底层/API语法:

JDK9

  1. 接口方法可以使用private修饰
  2. 支持http2.0和websocketAPI
  3. 模块化编程(对于依赖于Maven的开发者来说使用率和其产生的作用不高)
  4. String类底层数组从char[]变更为了byte[]。(byte能够在同样支持拉丁字符的情况下只占用1个字节,而char需要2个)
  5. 支持NumberFormat API,能够对数字进行格式化或者压缩

JDK10

  1. 推出var关键字支持局部变量类型推断,类似JS推断出值的真实类型

JDK11

  1. 集合API的增强
  2. 对Stream、Optional、集合API增强

JDK13

  1. Socket底层优化,引入NIO
  2. switch表达式添加yield关键字,用于返回结果,作用类似return
  3. 引入"""三双引号语法(文本块),内部不需要使用换行的转义字符。

JDK14

  1. instanceof关键字优化,代码块中会直接给对象赋值
  2. 引入record类,会自动生成构造器、getter、setter等方法,类似Lombok。
  3. NPE优化,可以打印具体哪个方法跑出了NPE,方便单行代码多个函数调用时的异常排查。(开发者福音)

JDK15

  1. 隐藏类Hiden Class
  2. 密封类 Sealed Class,密封类能够限定继承或者实现的子类。
  3. 对应java.lang.Class问类中新增了isSealedgetPermittedSubClasses()两个方法用于判断密封类和密封类所允许的拓展Class列表

JDK16 正式的将record、instanceof特性引入到JDK版本中

JDK17 正式引入密封类sealed class

  1. 统一日志一步刷新

JVM优化:

JDK9

  1. 设置为G1默认垃圾回收器

JDK10

  1. 并行FullGC,优化G1的延迟(JDK9的Full GC只有单线程,而10之后会采用Young和Mixed相同数量的线程进行FullGC)
  2. 线程局部管控,支持在不执行全局VM安全点的情况下对线程执行回调方法,停止单个线程,而不需要停止所有线程。

JDK11

  1. 推出ZGC(随后经过了多次的优化,是JDK17中综合性能最好的垃圾收集器,根据JavaOne的介绍其目标是能够支持亚秒级别回收TB界别的堆,还没达到但已经非常强了)

JDK12

  1. 推出Shenandoan垃圾收集器(12, 仅支持Linux,)
  2. 拓展swtich表达式,支持返回值(12
  3. 优化G1收集器,将G1的垃圾分为强制回收和可选部分,提高GC效率

JDK13

  1. ZGC优化,将标记长时间的空闲对内存空间返回给OS,保证堆大小不会小于配置的最小堆内存

JDK15

  1. ZGC性能优化

新语法/API实际使用

val局部变量类型推断

标识符var不是关键字,而只是一个保留的类型名称,仅适用于局部变量,能够通过值来推断出值的数据类型过是什么。 示例

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<String>
var stream = list.stream();          // 推断 Stream<String>

反编译class文件:

String str = "ABC";
long l = 10L;
boolean flag = true;
int flag1 = true;
ArrayList<String> list = new ArrayList();
Stream<String> stream = list.stream();

switch表达式

  • 现在支持使用switch赋值
  • 引入了lambda表达式,
  • 引入了yield语法,能够返回值,而不是使用break;

String result = switch (day) {
    case "M", "W", "F" -> "MWF";
    case "T", "TH", "S" -> "TTS";
    default -> {
        if(day.isEmpty())
            yield "Please insert a valid day.";
        else
            yield "Looks like a Sunday.";
}

instanceof模式匹配

JDK14之前

if (obj instanceof Article) {
  Article a= (Article) obj;
  System.out.println(a.getAuthor());
}

JDK14之后

if (obj instanceof Article a) {
  System.out.println(a.getAuthor());
}

NPE错误信息更详细

JDK14之前

Exception in thread "main" java.lang.NullPointerException at NullPointerExample.main(NullPointerExample.java:5)

JDK14之后

Exception in thread "main" 
java.lang.NullPointerException: Cannot invoke "Blog.getAuthor()" because the return value of "Article.getBlog()" is null at NullPointerExample.main(NullPointerExample.java:4)

record记录类

record Author(){}
//or
record Author (String name, String topic) {}

编译器会自动生成构造函数、g/setter、equals/hashCode、toString等方法

sealed 密封类

// 创建一个密封的Hello接口,只允许Hello2类对其进行实现
public interface sealed class Hello permits Hello2{}

NumberFormat增加了对压缩数字的支持

String number = NumberFormat.getCompactNumberInstance(Locale.US, 
		NumberFormat.Style.SHORT).format(1000);
// 其中number = “1k“

String类API的增强

添加了strip()isBlack()isEmpty()lines()repeat()等多个方法

  • strip()看作是trim的增强,能够去掉unicode空格,对应的还有stripLeading()和stripTailing()
  • isBlack()isEmpty()两者是String类中内置的方法,但依然建议使用各个工具包下的StringUtils。因为使用内置方法时,如果对象为空会产生NPE;而工具类下的StringUtils则不会。
  • lines()会将单个多行字符才成多个单行字符
  • repeat()能够构建一个或多个相同字符串组合的字符串