|
| 1 | +--- |
| 2 | +title: Java 14 & 15 新特性概览 |
| 3 | +category: Java |
| 4 | +tag: |
| 5 | + - Java新特性 |
| 6 | +--- |
| 7 | + |
| 8 | +## Java14 |
| 9 | + |
| 10 | +### 空指针异常精准提示 |
| 11 | + |
| 12 | +通过 JVM 参数中添加`-XX:+ShowCodeDetailsInExceptionMessages`,可以在空指针异常中获取更为详细的调用信息,更快的定位和解决问题。 |
| 13 | + |
| 14 | +```java |
| 15 | +a.b.c.i = 99; // 假设这段代码会发生空指针 |
| 16 | +``` |
| 17 | + |
| 18 | +Java 14 之前: |
| 19 | + |
| 20 | +```java |
| 21 | +Exception in thread "main" java.lang.NullPointerException |
| 22 | + at NullPointerExample.main(NullPointerExample.java:5) |
| 23 | +``` |
| 24 | + |
| 25 | +Java 14 之后: |
| 26 | + |
| 27 | +```java |
| 28 | + // 增加参数后提示的异常中很明确的告知了哪里为空导致 |
| 29 | +Exception in thread "main" java.lang.NullPointerException: |
| 30 | + Cannot read field 'c' because 'a.b' is null. |
| 31 | + at Prog.main(Prog.java:5) |
| 32 | +``` |
| 33 | + |
| 34 | +### switch 的增强(转正) |
| 35 | + |
| 36 | +Java12 引入的 switch(预览特性)在 Java14 变为正式版本,不需要增加参数来启用,直接在 JDK14 中就能使用。 |
| 37 | + |
| 38 | +Java12 为 switch 表达式引入了类似 lambda 语法条件匹配成功后的执行块,不需要多写 break ,Java13 提供了 `yield` 来在 block 中返回值。 |
| 39 | + |
| 40 | +```java |
| 41 | +String result = switch (day) { |
| 42 | + case "M", "W", "F" -> "MWF"; |
| 43 | + case "T", "TH", "S" -> "TTS"; |
| 44 | + default -> { |
| 45 | + if(day.isEmpty()) |
| 46 | + yield "Please insert a valid day."; |
| 47 | + else |
| 48 | + yield "Looks like a Sunday."; |
| 49 | + } |
| 50 | + |
| 51 | + }; |
| 52 | +System.out.println(result); |
| 53 | +``` |
| 54 | + |
| 55 | +### 预览新特性 |
| 56 | + |
| 57 | +#### record 关键字 |
| 58 | + |
| 59 | +`record` 关键字可以简化 **数据类**(一个 Java 类一旦实例化就不能再修改)的定义方式,使用 `record` 代替 `class` 定义的类,只需要声明属性,就可以在获得属性的访问方法,以及 `toString()`,`hashCode()`, `equals()`方法 |
| 60 | + |
| 61 | +类似于使用 `class` 定义类,同时使用了 lombok 插件,并打上了`@Getter,@ToString,@EqualsAndHashCode`注解 |
| 62 | + |
| 63 | +```java |
| 64 | +/** |
| 65 | + * 这个类具有两个特征 |
| 66 | + * 1. 所有成员属性都是final |
| 67 | + * 2. 全部方法由构造方法,和两个成员属性访问器组成(共三个) |
| 68 | + * 那么这种类就很适合使用record来声明 |
| 69 | + */ |
| 70 | +final class Rectangle implements Shape { |
| 71 | + final double length; |
| 72 | + final double width; |
| 73 | + |
| 74 | + public Rectangle(double length, double width) { |
| 75 | + this.length = length; |
| 76 | + this.width = width; |
| 77 | + } |
| 78 | + |
| 79 | + double length() { return length; } |
| 80 | + double width() { return width; } |
| 81 | +} |
| 82 | +/** |
| 83 | + * 1. 使用record声明的类会自动拥有上面类中的三个方法 |
| 84 | + * 2. 在这基础上还附赠了equals(),hashCode()方法以及toString()方法 |
| 85 | + * 3. toString方法中包括所有成员属性的字符串表示形式及其名称 |
| 86 | + */ |
| 87 | +record Rectangle(float length, float width) { } |
| 88 | +``` |
| 89 | + |
| 90 | +#### 文本块 |
| 91 | + |
| 92 | +Java14 中,文本块依然是预览特性,不过,其引入了两个新的转义字符: |
| 93 | + |
| 94 | +- `\` : 表示行尾,不引入换行符 |
| 95 | +- `\s` :表示单个空格 |
| 96 | + |
| 97 | +```java |
| 98 | +String str = "凡心所向,素履所往,生如逆旅,一苇以航。"; |
| 99 | + |
| 100 | +String str2 = """ |
| 101 | + 凡心所向,素履所往, \ |
| 102 | + 生如逆旅,一苇以航。"""; |
| 103 | +System.out.println(str2);// 凡心所向,素履所往, 生如逆旅,一苇以航。 |
| 104 | +String text = """ |
| 105 | + java |
| 106 | + c++\sphp |
| 107 | + """; |
| 108 | +System.out.println(text); |
| 109 | +//输出: |
| 110 | +java |
| 111 | +c++ php |
| 112 | +``` |
| 113 | + |
| 114 | +#### instanceof 增强 |
| 115 | + |
| 116 | +依然是**预览特性** ,[Java 12 新特性](./java12-13.md)中介绍过。 |
| 117 | + |
| 118 | +### 其他 |
| 119 | + |
| 120 | +- 从 Java11 引入的 ZGC 作为继 G1 过后的下一代 GC 算法,从支持 Linux 平台到 Java14 开始支持 MacOS 和 Window(个人感觉是终于可以在日常开发工具中先体验下 ZGC 的效果了,虽然其实 G1 也够用) |
| 121 | +- 移除了 CMS(Concurrent Mark Sweep) 垃圾收集器(功成而退) |
| 122 | +- 新增了 jpackage 工具,标配将应用打成 jar 包外,还支持不同平台的特性包,比如 linux 下的`deb`和`rpm`,window 平台下的`msi`和`exe` |
| 123 | + |
| 124 | +## Java15 |
| 125 | + |
| 126 | +### CharSequence |
| 127 | + |
| 128 | +`CharSequence` 接口添加了一个默认方法 `isEmpty()` 来判断字符序列为空,如果是则返回 true。 |
| 129 | + |
| 130 | +```java |
| 131 | +public interface CharSequence { |
| 132 | + default boolean isEmpty() { |
| 133 | + return this.length() == 0; |
| 134 | + } |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +### TreeMap |
| 139 | + |
| 140 | +`TreeMap` 新引入了下面这些方法: |
| 141 | + |
| 142 | +- `putIfAbsent()` |
| 143 | +- `computeIfAbsent()` |
| 144 | +- `computeIfPresent()` |
| 145 | +- `compute()` |
| 146 | +- `merge()` |
| 147 | + |
| 148 | +### ZGC(转正) |
| 149 | + |
| 150 | +Java11 的时候 ,ZGC 还在试验阶段。 |
| 151 | + |
| 152 | +当时,ZGC 的出现让众多 Java 开发者看到了垃圾回收器的另外一种可能,因此备受关注。 |
| 153 | + |
| 154 | +经过多个版本的迭代,不断的完善和修复问题,ZGC 在 Java 15 已经可以正式使用了! |
| 155 | + |
| 156 | +不过,默认的垃圾回收器依然是 G1。你可以通过下面的参数启动 ZGC: |
| 157 | + |
| 158 | +```bash |
| 159 | +$ java -XX:+UseZGC className |
| 160 | +``` |
| 161 | + |
| 162 | +### EdDSA(数字签名算法) |
| 163 | + |
| 164 | +新加入了一个安全性和性能都更强的基于 Edwards-Curve Digital Signature Algorithm (EdDSA)实现的数字签名算法。 |
| 165 | + |
| 166 | +虽然其性能优于现有的 ECDSA 实现,不过,它并不会完全取代 JDK 中现有的椭圆曲线数字签名算法( ECDSA)。 |
| 167 | + |
| 168 | +```java |
| 169 | +KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519"); |
| 170 | +KeyPair kp = kpg.generateKeyPair(); |
| 171 | + |
| 172 | +byte[] msg = "test_string".getBytes(StandardCharsets.UTF_8); |
| 173 | + |
| 174 | +Signature sig = Signature.getInstance("Ed25519"); |
| 175 | +sig.initSign(kp.getPrivate()); |
| 176 | +sig.update(msg); |
| 177 | +byte[] s = sig.sign(); |
| 178 | + |
| 179 | +String encodedString = Base64.getEncoder().encodeToString(s); |
| 180 | +System.out.println(encodedString); |
| 181 | +``` |
| 182 | + |
| 183 | +输出: |
| 184 | + |
| 185 | +``` |
| 186 | +0Hc0lxxASZNvS52WsvnncJOH/mlFhnA8Tc6D/k5DtAX5BSsNVjtPF4R4+yMWXVjrvB2mxVXmChIbki6goFBgAg== |
| 187 | +``` |
| 188 | + |
| 189 | +### 文本块(转正) |
| 190 | + |
| 191 | +在 Java 15 ,文本块是正式的功能特性了。 |
| 192 | + |
| 193 | +### 隐藏类(Hidden Classes) |
| 194 | + |
| 195 | +隐藏类是为框架(frameworks)所设计的,隐藏类不能直接被其他类的字节码使用,只能在运行时生成类并通过反射间接使用它们。 |
| 196 | + |
| 197 | +### 预览新特性 |
| 198 | + |
| 199 | +#### 密封类 |
| 200 | + |
| 201 | +**密封类(Sealed Classes)** 是 Java 15 中的一个预览新特性。 |
| 202 | + |
| 203 | +没有密封类之前,在 Java 中如果想让一个类不能被继承和修改,我们可以使用`final` 关键字对类进行修饰。不过,这种方式不太灵活,直接把一个类的继承和修改渠道给堵死了。 |
| 204 | + |
| 205 | +密封类可以对继承或者实现它们的类进行限制,这样这个类就只能被指定的类继承。 |
| 206 | + |
| 207 | +```java |
| 208 | +// 抽象类 Person 只允许 Employee 和 Manager 继承。 |
| 209 | +public abstract sealed class Person |
| 210 | + permits Employee, Manager { |
| 211 | + |
| 212 | + //... |
| 213 | +} |
| 214 | +``` |
| 215 | + |
| 216 | +另外,任何扩展密封类的类本身都必须声明为 `sealed`、`non-sealed` 或 `final`。 |
| 217 | + |
| 218 | +```java |
| 219 | +public final class Employee extends Person { |
| 220 | +} |
| 221 | + |
| 222 | +public non-sealed class Manager extends Person { |
| 223 | +} |
| 224 | +``` |
| 225 | + |
| 226 | + |
| 227 | + |
| 228 | +如果允许扩展的子类和封闭类在同一个源代码文件里,封闭类可以不使用 permits 语句,Java 编译器将检索源文件,在编译期为封闭类添加上许可的子类。 |
| 229 | + |
| 230 | +#### instanceof 模式匹配 |
| 231 | + |
| 232 | +Java 15 并没有对此特性进行调整,继续预览特性,主要用于接受更多的使用反馈。 |
| 233 | + |
| 234 | +在未来的 Java 版本中,Java 的目标是继续完善 `instanceof` 模式匹配新特性。 |
| 235 | + |
| 236 | +### 其他 |
| 237 | + |
| 238 | +- **Nashorn JavaScript 引擎彻底移除** :Nashorn 从 Java8 开始引入的 JavaScript 引擎,Java9 对 Nashorn 做了些增强,实现了一些 ES6 的新特性。在 Java 11 中就已经被弃用,到了 Java 15 就彻底被删除了。 |
| 239 | +- **DatagramSocket API 重构** |
| 240 | +- **禁用和废弃偏向锁(Biased Locking)** : 偏向锁的引入增加了 JVM 的复杂性大于其带来的性能提升。不过,你仍然可以使用 `-XX:+UseBiasedLocking` 启用偏向锁定,但它会提示 这是一个已弃用的 API。 |
| 241 | +- ...... |
0 commit comments