JDK15已发布,网友:我还在JDK8踏步走...
自从 JDK9 之后,每年 3 月与 9 月 JDK 都会发布一个新的版本,而2020 年 9 月即将引来 JDK15。
恰巧 IDEA 每四五个月会升级一个较大的版本,每次升级之后都会支持最新版本 JDK 引入的新功能。
这几天升级了 IDEA,顺便体验了一下 JDK15 的新特性。
虽然我知道你们可能跟我一样JDK8 都还没用熟,但是无妨,看看新版本 JDK 来酸一下。
Text Blocks 最终定板
之前版本的 JDK,如果我们需要插入 HTML,XML,SQL 或 JSON 片段,非常麻烦,需要对里面符号进行各种转义。
所以我每次都会在其他编辑器将 HTML ,XML 等编辑好,然后直接复制到 IDEA 中,IDEA 自动会对这些字符转义。
每次复制进去就变成上图的效果,如果上面字符再多点,阅读起来就会更难,并且难以维护。
所幸 IDEA 提供了一个 Inject Language 功能,我们可以在里面快速方便的编辑。
Java 开发者也关注到这个问题,他们在 JDK13 引入的一个新的预览特性「Text Blocks」,可以使用三引号将复杂的字符串赋值,从而让我们从各种转义中解脱出来,可以更加方便的编辑字符串。
这个功能在其他语言还是比较常见的,比如 Python 等。
Text Blocks 新功能在 JDK14 再次以预览功能引入,最终在 JDK15 成为新版本的正式功能。
下面我们来对比一下使用 Text Blocks 与之前区别:
Html
SQL
JS
Records (Second Preview)
JDK14 引入一个新的预览特性 record 语法,可以快速创建一个纯数据类,并且不用去生成 getter,toString 等。
使用下面的语法就可以快速创建一个数据类:
public record Point(int x,int y) {
}
JDK15 是 record 这个语法的第二次预览,这个版本增加一个新的功能 「local record」,可以在一个方法在快速创建一个类,以便于方法中业务逻辑计算。
在以下示例中,使用本地记录 MerchantSales 对商人和每月销售额的汇总进行建模,使用此记录可提高以下流操作的可读性:
下面例子的中我们新建一个类 MerchantSales,然后按照销售人员对每月的销售额汇总排序。
List<Merchant> findTopMerchants(List<Merchant> merchants, int month) {
// Local record
record MerchantSales(Merchant merchant, double sales) {}
return merchants.stream()
.map(merchant -> new MerchantSales(merchant, computeSales(merchant, month)))
.sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales()))
.map(MerchantSales::merchant)
.collect(toList());
}
原先如果需要使用这种功能,我们不得不创建一个内部类,后续可能再也不会用到,使用 local record就解决这个尴尬的问题。
除了 local record 我们还可以创建 local enums 以及 local interface。
// local enums
public void organisePeople(List<Person> people) {
enum Role {
Employee, Customer, Both, None
}
HashMap<Role, List<Person>> peopleByRole = new HashMap<>();
people.stream()
.filter(Person::isCustomer)
.forEach(person -> peopleByRole.computeIfAbsent(Role.Customer, role -> new ArrayList<>())
.add(person));
// 其他业务逻辑
}
// local interface
public void localInterface() {
interface MyInterface {
void doSomething();
}
MyInterface testInterface = new MyInterface() {
@Override
public void doSomething() {
System.out.println("Hello World!");
}
};
// 其他业务逻辑
}
最后使用这个特性需要注意一点,local record , local enums ,local interface 创建都是一个局部变量,是不能被传递其他方法引用。
Pattern Matching for instanceof (Second Preview)
我们应该都看到过下面这种代码:
if (obj instanceof String) {
String str = (String) obj;
// use str
}
上面代码意图非常简单,当 obj 对象是 String 类,就将其强制转换,然后进行其他业务操作。
这种写法,类型转换还是比较繁琐,Pattern Matching for instanceof 这个新语法特性,可以帮我们省略这种类型转换动作。这是一个在 JDK14 引入一个预览特性,JDK 15 开始第二次预览。
上面的代码使用 pattern matcher,就可以被修改如下:
if (obj instanceof String s) {
s.contains("T");
} else {
// 编译错误
//s.contains("T");
}
另外如果在 IDEA 中还可以提示我们将代码转化成 pattern matcher 。
大家应该都看过 Effective Java 这本神书吧,里面第八条关于 Equals 有一个例子:
使用 pattern matcher 我们就可以使用下面更加清晰的代码代替:
Sealed Classes (Preview)
Java 中一个正常普通类/接口允许被其他子类继承/实现,但是有时在日常开发中,我们可能希望只有特定的类才能继承扩展。
现有的 Java 语法中存在一些方法,可以限制子类扩展,比如说:我们可以使用 final 修饰类
public final class String
不过这样之后,我们就没办法再继承这个类。
其次我们可以限制的类的范围,比如说不使用 public 修饰类/接口,即使用 default 范围,这样只有同一个包才能继承/实现。
interface DefaultExample {
}
不过使用这种方式,又很尴尬,这个类就无法被其他包使用。
为了解决上述问题,JDK 15 引入一个新的预览特性 Sealed Classes,即可以限定类的扩展,也可以被外部使用。
public sealed class Shape
permits Circle, Rectangle, Square {...}
使用 sealed 修饰之后,Shape
类只能被 Circle
,Rectangle
,Square
继承,再也不能被其他类继承。
同时 Shape 的子类存在一些限制,必须使用 final 修饰,表明这个类无法再被扩展:
public final class Circle extends Shape {...}
或者继续使用 sealed 表示子类只能被指定类继承:
public sealed class Rectangle extends Shape
permits TransparentRectangle, FilledRectangle {...}
public final class TransparentRectangle extends Rectangle {...}
又或者说使用 non-sealed 表明这个子类不限制子类扩展,可以被其他任何类扩展实现。
另外 sealed class 还可以跟上述 record 语法一起使用。
public sealed interface Expr
permits ConstantExpr, PlusExpr, TimesExpr, NegExpr {...}
public record ConstantExpr(int i) implements Expr {...}
public record PlusExpr(Expr a, Expr b) implements Expr {...}
public record TimesExpr(Expr a, Expr b) implements Expr {...}
public record NegExpr(Expr e) implements Expr {...}
ZGC
ZGC(Z Garbage Collector) 这是一款在 JDK11 引入的的具有实验性质的低延迟的 GC 收集器。
这款 GC 收集器的希望在尽可能对吞吐量影响不大的前提下,实现在任意堆内存大小都可以把垃圾收集器的停顿时间限制在十毫秒以内的低延迟。
ZGC 经过这两三年的迭代优化,终于在 JDK15 中正式引入,标志着 ZGC 可以正式应用于生产应用。
JDK15 中默认虚拟机还是 G1,如果需要使用 ZGC,需要在启动参数中加入如下参数:
-XX:+UseZGC command-line
最后
本来这篇文章是准备写下 IDEA 2020.2 新版本特性,顺带介绍一下 JDK15 新特性的。
可是没想到写着写着,JDK15 相关的篇幅就过长了,所以就单独拿出来了。
最后,最后,JDK 都发布到 15 了,而我却还在用 JDK 8 ,真是个悲伤的故事,逃了逃了!
我是楼下小黑哥,每天学习一点点,成长亿点点!!
参考链接
https://openjdk.java.net/projects/jdk/15/
- WordPress在RSS Feed 中输出自定义特色图像(缩略图)
- 单拼域名can.com以高达99.2万元成交!
- CI学习 CCNET Config 第一天
- IBatisNet基础组件
- 学习altas笔记[客户端JS和Altas环境初始化关系和DataTable返回数据的客户端处理]
- 在Windows 8 Hyper-V下的安装CentOS 6和SSH配置
- WordPress RSS Feed 优化/设置技巧六则
- SourceTree 基本介绍
- 学习Altas 笔记[JS简单调用服务端方法]
- 使用WinSCP软件在windows和Linux中进行文件传输
- 线程安全的Generic Dictionary
- Python 项目实践三(Web应用程序)第五篇
- CentOS 6.3下 安装 Mono 3.2 和Jexus 5.4
- Python 项目实践三(Web应用程序)第四篇
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux ss命令详解
- 如何在Linux中设置快捷方式图标
- foreman ubuntu16 快速安装
- Three.js教程(2):工具篇
- Linux系统多网卡环境下的路由配置详解
- 前端3D文字效果
- Bash中尖括号的更多使用方法
- linux mpstat命令使用详解
- CentOS7安装调试Mysql数据库的步骤详解【实例】
- 深入理解Bash中的尖括号(适合初学者)
- linux安装php7的方法详解
- centos7.2搭建nginx的web服务器部署uniapp项目
- 通过 SSH 在远程 Linux 系统上运行命令的方法
- 详解Linux Namespace之User
- Centos7.0安装ceph(JEWEL)及以上版本的实例解析