资源
📁 JDK-downloads
内容详情
Java 9 ~ 11:
ZGC垃圾回收器
据说这是JDK11最为瞩目的特性,没有之一,是最重磅的升级,那么ZGC的优势在哪里呢?
- GC暂停时间不会超过10毫秒
- 既能处理几百兆的小堆,也能处理几个T的大堆
- 和G1相比,应用吞吐能力不会下降超过15%
- 为未来的GC功能和利用colord指针以及Load barriers优化奠定了基础
ZGC是一个并发、基于region、压缩型的垃圾收集器,只有root扫描阶段会STW(strop the world,停止所有线程),因此ZGC的停顿时间不会随着堆的增长和存活对象的增长而变长。用法:-XX:UnlockExperimentalVMOptions -XX:+UseZGC
字符串API增强
// 用来判断字符串是不是空字符"“或者trim()之后(” ")为空字符:
isBlank()
//将一个字符串按照行终止符(换行符\n或者回车符\r)进行分割,并将分割为Stream流:
lines()
//按照给定的次数重复串联字符串的内容:
repeat(n)
集合转对应类型的数组
之前想集合转对应的数组很麻烦,要么用迭代;要么用Stream流,现在你可以这样:
List<String> sampleList = Arrays.asList("张三", "java 11");
// array = {"张三", "java 11"};
String[] array = sampleList.toArray(String[]::new);
var可以用于修饰Lambda局部变量
在Java 10中引入的var来进行类型推断。在Java 10中它不能用于修饰Lambda表达式的入参,其实对于一个Lambda表达式来说它入参的类型其实是可以根据上下文推断出来的。拿上面的例子来说,s -> s.startsWith(“j”)中的s肯定是字符串类型,因此在Java 11中var可以用于修饰Lambda局部变量:
List<String> sampleList = Arrays.asList("张三", "java 11","jack");
List<String> result = sampleList.stream()
// 过滤以j开头的字符串
.filter((@NotNull var s) -> s.startsWith("j"))
// 同时不包含11的字符串
.filter(Predicate.not((@NotNull var s) -> s.contains("11")))
.collect(Collectors.toList());
文件中读写字符串内容更方便
Java 11中可以更轻松地从文件中读取和写入字符串内容了,我们可以通过Files工具类提供的新的静态方法readString和writeString分别进行读写文件的字符串内容,放在之前老麻烦了,特别是对IO流不熟悉的同学来说。现在简单几行就搞定了:
String dir= "C://yourDir/hello.txt";
// 写入文件
Path path = Files.writeString(Path.of(dir), "hello java 11");
// 读取文件
String fileContent = Files.readString(path);
// hello java 11
System.err.println(fileContent);
Java 12~17:
文本块
switch表达式
record关键字
sealed classes密封类
instanceof模式匹配
Helpful NullPointerExceptions
日期周期格式化
精简数字格式化支持
Stream.toList()简化
文本块 (Java17)
假设有这样一个场景,我们需要做一个工具。用来自动生成项目文档,文档可以通过浏览器查看,所以最后产出物肯定是一堆html文件。为了让这些html文件更容易读,良好的格式肯定要保持,该换行的换行、该缩进的缩进。
那么,在组织最后内容的时候,你可能就会这样子来写:
String html =
"<html>\n" +
"<body>\n"+
" <h1>Java 17新特性:文本块 -0xYGC</h1>\n"+
" <p>didispace.com</p>\n"+
"</body>\n"+
"</html>\n";
当然,也许你也会改进一下,用StringBuilder或者StringBuffer来优化,但不论用什么来写,都逃不了一些要转义的内容,比如上面拼接内容时候的换行\n。
一旦存在大量要转义内容的时候,也就增加了我们编写代码的复杂度。复杂度越高,我们就越容易犯错。所以,在Java 17中增加了一个新特性:文件块(Text Blocks),来帮助我们更便捷的实现多行字符串文字的处理。
对于上面的字符串内容,Java 17中,我们只需要这样写:
String html = """
<html>
<body>
<h1>Java 17新特性:文本块 -0xYGC</h1>
<p>didispace.com</p>
</body>
</html>
""";
像这种改进还是特别有用的,比如ES的最新客户端支持DSL部分脚本代码运行, Flink 也支持SQL脚本,以及 Sping Data JPA等等
switch表达式
Java 17版本中switch表达式将允许switch有返回值,并且可以直接作为结果赋值给一个变量,等等一系列的变化。下面有一个switch例子,依赖于给定的枚举值,执行case操作,故意省略break。
private static void lowVesion(Fruit fruit) {
switch (fruit) {
case APPLE, PEAR:
System.out.println("普通水果");
case MANGO, AVOCADO:
System.out.println("进口水果");
default:
System.out.println("未知水果");
}
}
我们调用这个方法传入一个APPLE,会输出以下结果: 普通水果进口水果未知水果
显然这不是期望的结果,因为我们需要在每个case里添加break防止所有的case都被执行。
Java17可以通过switch表达式来进行简化。将冒号(:)替换为箭头(->),并且switch表达式默认不会失败,所以不需要break。
private static void withReturnValue(Fruit fruit) {
String text = switch (fruit) {
case APPLE, PEAR -> "普通水果";
case MANGO, AVOCADO -> "进口水果";
default -> "未知水果";
};
System.out.println(text);
}
也可以直接省略赋值动作直接打印。
private static void withReturnValue(Fruit fruit) {
System.out.println(switch (fruit) {
case APPLE, PEAR -> "普通水果";
case MANGO, AVOCADO -> "进口水果";
default -> "未知水果";
});
}
如果你想在case里想做不止一件事,比如在返回之前先进行一些计算或者打印操作,可以通过大括号来作为case块,最后的返回值使用关键字yield进行返回。
private static void withYield(Fruit fruit) {
String text = switch (fruit) {
case APPLE, PEAR -> {
System.out.println("给的水果是: " + fruit);
yield "普通水果";
} case MANGO, AVOCADO -> "进口水果";
default -> "未知水果";
}; System.out.println(text);
}
Records关键字(Java14 添加)
record用于创建不可变的数据类。在这之前如果你需要创建一个存放数据的类,通常需要先创建一个Class,然后生成构造方法、getter、setter、hashCode、equals和toString等这些方法,或者使用Lombok来简化这些操作。
通过对类做这样的声明,编译器可以通过自动创建所有方法并让所有字段参与hashCode()等方法。这是JDK 14中的一个预览特性。
使用record关键字可以定义一个记录:
record Person (String firstName, String lastName) {}
假设有一些场景我们只需要对Person的name和age属性进行打印,在有record之后将会变得非常容易。
PersonRecord p1Record = new PersonRecord(p1.getName(), p1.getAge());
PersonRecord p2Record = new PersonRecord(p2.getName(), p2.getAge());
System.out.println(p1Record);
System.out.println(p2Record);
record 解决了使用类作为数据包装器的一个常见问题。纯数据类从几行代码显著地简化为一行代码。(详见: Java 14 发布了,不使用”class”也能定义类了?还顺手要干掉Lombok! )
封闭类 (Java15)
在Java 15之前,Java认为"代码重用"始终是一个终极目标,所以,一个类和接口都可以被任意的类实现或继承。但是,在很多场景中,这样做是容易造成错误的,而且也不符合物理世界的真实规律。
例如,假设一个业务领域只适用于汽车和卡车,而不适用于摩托车。在Java中创建Vehicle抽象类时,应该只允许Car和Truck类扩展它。通过这种方式,我们希望确保在域内不会出现误用Vehicle抽象类的情况。为了解决类似的问题,在Java 15中引入了一个新的特性——密闭。
想要定义一个密闭接口,可以将sealed修饰符应用到接口的声明中。然后,permit子句指定允许实现密闭接口的类:
public sealed interface Service permits Car, Truck { }
通过密闭特性,我们定义出来的Vehicle类只能被Car和Truck继承。
Sping Boot 3.0 已经最低要Java 17了,
2022-06-28 发布的 Jenkins 2.357 和即将发布的 9 月 LTS 版本开始,Jenkins 最低需要 Java 11
Kafka3.0弃用Java 8
- Sping官网 介绍说明
日期周期格式化
在Java 17中添加了一个新的模式B,用于格式化DateTime,它根据Unicode标准指示一天时间段。使用默认的英语语言环境,打印一天的几个时刻:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("B");
System.out.println(dtf.format(LocalTime.of(8, 0)));
System.out.println(dtf.format(LocalTime.of(13, 0)));
System.out.println(dtf.format(LocalTime.of(20, 0)));
System.out.println(dtf.format(LocalTime.of(23, 0)));
System.out.println(dtf.format(LocalTime.of(0, 0)));
- 输出结果:
in the morningin the afternoonin the eveningat nightmidnight
如果是中文语言环境,则输出结果为:
上午下午晚上晚上午夜
精简数字格式化支持
在NumberFormat中添加了一个工厂方法,可以根据Unicode标准以紧凑的、人类可读的形式格式化数字。
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.SHORT);
System.out.println(fmt.format(1000));
System.out.println(fmt.format(100000));
System.out.println(fmt.format(1000000));
输出格式为:1K100K1M
当然还有其他格式:比如Long类型线显示成数值可以为:1 thousand100 thousand1 million
Java 18~19:
JDK 18
JDK 19
参考资料 & 致谢
[1] Java 17 新特性:文本块