Hello World

吞风吻雨葬落日 欺山赶海踏雪径

0%

Java 12 新特性

jdk 12 主要的新特性参考:
openjdk JDK 12

baeldung New Features in Java 12

JDK 12 的新特性

语法变动

String 类的新增方法

Java 12 为String 类引入了两个新方法 indenttransform

  • indent

indent 更具其int 参数调节了String 每一行的缩进。参数n大于0,则String 每行增加n个空格,参数n小于0则String 删除每行前面的空格。
如果每行前面的空格数小于参数n,则删除所有空格(其他内容完好无损的保留下来)

1
2
3
4
5
6
7
String text = "Hello Baeldung!\nThis is Java 12 article.";

text = text.indent(4);
System.out.println(text);

text = text.indent(-10);
System.out.println(text);

输出

1
2
3
4
5
    Hello Baeldung!
This is Java 12 article.

Hello Baeldung!
This is Java 12 article.

即时参数是 -10 也只会删除前面4个空格。

  • transform

transform只有一个参数Function,把自己通过 Function进行转换

1
2
3
public <R> R transform(Function<? super String, ? extends R> f) {
return f.apply(this);
}

比如倒置一个String

1
2
3
4
5
6
7
8
9
@Test
public void givenString_thenRevertValue() {
String text = "Baeldung";
String transformed = text.transform(value ->
new StringBuilder(value).reverse().toString()
);

assertEquals("gnudleaB", transformed);
}

File::mismatch 方法

Java 12 中在 nio.file.Files 工具类中新增了 mismatch 方法

1
public static long mismatch(Path path, Path path2) throws IOException

这个方法比较两个文件,并返回第一处内容不相等的字节位置(long)。 如果文件完全相等,返回-1L

看两个列子,第一个例子比较完全相同的两个文件,返回-1L

1
2
3
4
5
6
7
8
9
10
@Test
public void givenIdenticalFiles_thenShouldNotFindMismatch() {
Path filePath1 = Files.createTempFile("file1", ".txt");
Path filePath2 = Files.createTempFile("file2", ".txt");
Files.writeString(filePath1, "Java 12 Article");
Files.writeString(filePath2, "Java 12 Article");

long mismatch = Files.mismatch(filePath1, filePath2);
assertEquals(-1, mismatch);
}

第二个例子,两个文件内容分别是 Java 12 ArticleJava 12 Tutorial,应该返回8L表示第八个字节是不一样的(A and T)

1
2
3
4
5
6
7
8
9
10
@Test
public void givenDifferentFiles_thenShouldFindMismatch() {
Path filePath3 = Files.createTempFile("file3", ".txt");
Path filePath4 = Files.createTempFile("file4", ".txt");
Files.writeString(filePath3, "Java 12 Article");
Files.writeString(filePath4, "Java 12 Tutorial");

long mismatch = Files.mismatch(filePath3, filePath4);
assertEquals(8, mismatch);
}

Stream API 中的 Collectors.teeing()

Java 12中在 Collectors 类中新增了teeing 收集器:

1
2
Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2, BiFunction<? super R1, ? super R2, R> merger)

该收集器将其输入转发给其他两个收集器,然后将它们的结果使用函数合并。
下面例子使用利用 teeing处理一个数值 set, 第一个collector 求和,第二个collector 统计数值个数,最后通过 merger 合并结果计算平均值:

1
2
3
4
5
6
7
@Test
public void givenSetOfNumbers_thenCalculateAverage() {
double mean = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.teeing(Collectors.summingDouble(i -> i),
Collectors.counting(), (sum, count) -> sum / count));
assertEquals(3.0, mean);
}

紧凑的数字格式

Java 12 新增了一个新的数字格式 —— 紧凑数字格式 。因为较大的数字总是难以识别具体数值,紧凑的表示更容易阅读且占据更少的展示空间。
我们可以通过 NumberFormat 类的 getCompactNumberInstance 方法获取其实例:

1
public static NumberFormat getCompactNumberInstance(Locale locale, NumberFormat.Style formatStyle)

通过参数 locale 提供了一个合适的格式,formatStyle可以是 SHORT or LONG ,比如 US locale 中数字 1000
formatStyleSHORT则对应的就是 10K ,而 LONG 则是 10 thousand

具体使用两个 formatStyle的代码例子:

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void givenNumber_thenCompactValues() {
NumberFormat likesShort =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT);
likesShort.setMaximumFractionDigits(2);
assertEquals("2.59K", likesShort.format(2592));

NumberFormat likesLong =
NumberFormat.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.LONG);
likesLong.setMaximumFractionDigits(2);
assertEquals("2.59 thousand", likesLong.format(2592));
}

预览版的特性

有一些特性是作为预览版本在 java 12 中发布的,如果要使用他们需要在编译的时候增加额外的配置

1
javac -Xlint:preview --enable-preview -source 12 src/main/java/File.java

Switch表达式 (Preview)

Java 12中引入的最有名的特性就是 Switch 表达式

我们用一个例子(LocalDate 实例的DayOfWeek 枚举判断是否是工作日)看下新老 switch 表达式的区别,Java 12 之前的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
String typeOfDay = "";
switch (dayOfWeek) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
typeOfDay = "Working Day";
break;
case SATURDAY:
case SUNDAY:
typeOfDay = "Day Off";
}

同样的逻辑使用 switch 表达式

1
2
3
4
typeOfDay = switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Working Day";
case SATURDAY, SUNDAY -> "Day Off";
};

switch 表达式 更简洁易读,它取消了 break 语句,但不会再匹配后继续执行。另一个优势是现在可以把 switch表达式赋予一个变量, 这个在以前是不可能实现的。

同时,在switch 语句中可以直接代码且并不要求一定要有返回值:

1
2
3
4
switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> System.out.println("Working Day");
case SATURDAY, SUNDAY -> System.out.println("Day Off");
}

如果需要执行的逻辑比较复杂,可以使用 {}

1
2
3
4
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
// more logic
System.out.println("Working Day")
}

Java 12 中的switch 表达式只是一个可选的扩展语法,并不是说要直接代替了原来的 switch 。

switch Expressions 会在 Java 13 (转正了) 做更深入的说明。

instanceof 的匹配模式 (Preview)

另一个Preview 版本的特性就是 instanceof.

在之前的Java版本,当使用 instanceof 的时候通常都会需要额外写一个类型转化

1
2
3
4
5
Object obj = "Hello World!";
if (obj instanceof String) {
String s = (String) obj;
int length = s.length();
}

java 12 中我们可以直接声明一个新的类型变量代表转化后的值

1
2
3
if (obj instanceof String s) {
int length = s.length();
}

编译器自动帮我们转换成了 String s

JVM 相关的变化

Java 12 中引入了一系列 JVM的增强特性,这里只挑选了几个比较重要的说明。

Shenandoah 垃圾回收器

Shenandoah 是一个低延迟的垃圾回收器。Java 12中 Shenandoah 还是实验性质的 (在Java 15 中会正式启用)。

Shenandoah 通过与Java线程同时执行清理工作来减少GC暂停时间。这意味着使用 Shenandoah,无论堆有多大,垃圾回收200 GB堆或2 GB堆停顿的时间都是固定的(垃圾收集器的停顿时间限制在10ms以内)。

ps. Shenandoah 收集器是由 RedHat 公司开发的项目,Oracle 拒绝在 OracleJDK12 中支持该收集器,Shenandoah 只有在 OpenJDK 中才会包含,而 OracleJDK 中不包含的。

Microbenchmark Suite

Java 12 introduces a suite of around 100 microbenchmark tests to the JDK source code.
These tests will allow for continuous performance testing on a JVM and will become useful for every developer wishing to work on the JVM itself or create a new microbenchmark.

Java 12 新增了大概100个 套微基准测试,提供给JVM性能测试用的。

Default CDS Archives

The Class Data Sharing (CDS) feature helps reduce the startup time and memory footprint between multiple Java Virtual Machines. It uses a built-time generated default class list that contains the selected core library classes.

The change that came with Java 12 is that the CDS archive is enabled by default. To run programs with CDS turned off we need to set the Xshare flag to off:

1
java -Xshare:off HelloWorld.java

Note, that this could delay the startup time of the program.

就是 CDS 在Java 12 中默认就是开启的,需要通过 -Xshare:off 关闭(启动会变慢), CDS 的内容在 Java 10 新特性中提到过。

总结

就写这么多吧, 关于 G1 垃圾回收器还是以后单独写一篇吧。