New Features in Java 12 – Java 12的新功能

最后修改: 2021年 1月 2日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

In this tutorial, we’ll have a quick, high-level overview of some of the new features that came with Java 12. A full list of all new features is available in the official documentation.

在本教程中,我们将对 Java 12 中的一些新功能进行快速、高层次的概述。所有新功能的完整列表可在官方文档中找到。

2. Language Changes and Features

2.语言变化和特点

Java 12 introduces a lot of new language features. In this section, we’ll discuss a few most interesting ones with code examples for better understanding.

Java 12 引入了很多新的语言特性。在本节中,我们将讨论几个最有趣的功能,并附上代码实例,以便更好地理解。

2.1. String Class New Methods

2.1.字符串类新方法

Java 12 comes with two new methods in the String class.

Java 12在String中提供了两个新方法。

The first one – indent adjusts the indentation of each line based on the integer parameter. If the parameter is greater than zero, new spaces will be inserted at the beginning of each line. On the other hand, if the parameter is less than zero, it removes spaces from the begging of each line. If a given line does not contain sufficient white space, then all leading white space characters are removed.

第一个–indent根据整数参数来调整每行的缩进。如果该参数大于零,将在每行的开头插入新的空格。另一方面,如果该参数小于零,它将从每行的开头删除空格。如果一个给定的行不包含足够的空白空间,那么所有领先的空白字符都会被删除。

Now, let’s take a look at a basic example. Firstly, we’ll indent the text with four spaces, and then we’ll remove the whole indentation:

现在,让我们来看看一个基本的例子。首先,我们将用四个空格缩进文本,然后我们将删除整个缩进。

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);

The output looks like the following:

输出结果看起来如下。

    Hello Baeldung!
    This is Java 12 article.

Hello Baeldung!
This is Java 12 article.

Note that even if we passed value -10, which exceeds our indent count, only the spaces were affected. Other characters are left intact.

请注意,即使我们通过了值-10,超过了我们的缩进计数,也只有空格受到影响。其他字符则保持不变。

The second new method is transform. It accepts a single argument function as a parameter that will be applied to the string.

第二个新方法是transform。它接受一个单参数函数作为参数,将被应用于字符串。

As an example, let’s use the transform method to revert the string:

作为一个例子,让我们使用转换方法来还原字符串。

@Test
public void givenString_thenRevertValue() {
    String text = "Baeldung";
    String transformed = text.transform(value ->
      new StringBuilder(value).reverse().toString()
    );

    assertEquals("gnudleaB", transformed);
}

2.2. File::mismatch Method

2.2.File::mismatch方法

Java 12 introduced a new mismatch method in the nio.file.Files utility class:

Java 12在nio.file.Files实用类中引入了一个新的mismatch方法。

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

The method is used to compare two files and find the position of the first mismatched byte in their contents.

该方法用于比较两个文件并找到其内容中第一个不匹配的字节的位置。

The return value will be in the inclusive range of 0L up to the byte size of the smaller file or -1L if the files are identical.

返回值将在0L到较小文件的字节大小的范围内,如果文件相同,则为-1L。

Now let’s take a look at two examples. In the first one, we’ll create two identical files and try to find a mismatch. The return value should be -1L:

现在让我们看一下两个例子。在第一个例子中,我们将创建两个相同的文件,并试图找到一个不匹配的文件。返回值应该是-1L。

@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);
}

In the second example, we’ll create two files with “Java 12 Article” and “Java 12 Tutorial” contents. The mismatch method should return 8L as it’s the first different byte:

在第二个例子中,我们将创建两个具有 “Java 12文章 “和 “Java 12教程 “内容的文件。错配方法应该返回8L,因为它是第一个不同的字节。

@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);
}

2.3. Teeing Collector

2.3.三通收集器

A new teeing collector was introduced in Java 12 as an addition to the Collectors class:

Java 12中引入了一个新的teeing收集器,作为Collectors的补充。

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

It is a composite of two downstream collectors. Every element is processed by both downstream collectors. Then their results are passed to the merge function and transformed into the final result.

它是两个下游收集器的组合。每个元素都被两个下游采集器处理。然后,它们的结果被传递给合并函数,并转化为最终的结果。

The example usage of teeing collector is counting an average from a set of numbers. The first collector parameter will sum up the values, and the second one will give us the count of all numbers. The merge function will take these results and count the average:

采集器的使用实例是计算一组数字的平均值。第一个收集器参数将对这些数值进行求和,第二个参数将给我们所有数字的计数。合并函数将采取这些结果并计算出平均数。

@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);
}

2.4. Compact Number Formatting

2.4.紧凑型数字格式化

Java 12 comes with a new number formatter – the CompactNumberFormat. It’s designed to represent a number in a shorter form, based on the patterns provided by a given locale.

Java 12 提供了一个新的数字格式CompactNumberFormat。它被设计成以较短的形式来表示一个数字,基于给定的地区设置所提供的模式。

We can get its instance via the getCompactNumberInstance method in NumberFormat class:

我们可以通过NumberFormat类中的getCompactNumberInstance方法获得其实例。

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

As mentioned before, the locale parameter is responsible for providing proper format patterns. The format style can be either SHORT or LONG. For a better understanding of the format styles, let’s consider number 1000 in the US locale. The SHORT style would format it as “10K”, and the LONG one would do it as “10 thousand”.

如前所述,locale参数负责提供正确的格式样式。格式样式可以是SHORT或LONG。为了更好地理解这些格式样式,让我们考虑美国地区的数字1000。SHORT风格会将其格式化为 “10K”,而LONG风格会将其格式化为 “10 thousand”。

Now let’s take a look at an example that’ll take the numbers of likes under this article and compact it with two different styles:

现在让我们看看一个例子,将这篇文章下的喜欢的数字,用两种不同的风格来压缩。

@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));
}

3. Preview Changes

3.预览变化

Some of the new features are available only as a preview. To enable them, we need to switch proper settings in the IDE or explicitly tell the compiler to use preview features:

有些新功能只能作为预览版使用。要启用它们,我们需要在IDE中切换适当的设置,或明确告诉编译器使用预览功能。

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

3.1. Switch Expressions (Preview)

3.1.切换表达式(预览)

The most popular feature introduced in Java 12 is the Switch Expressions.

Java 12中引入的最受欢迎的功能是切换表达式

As a demonstration, let’s compare the old and new switch statements. We’ll use them to distinguish working days from weekend days based on the DayOfWeek enum from the LocalDate instance.

作为演示,让我们比较一下新旧切换语句。我们将根据LocalDate实例中的DayOfWeek枚举,使用它们来区分工作日和周末。

Firstly, let’s look and at the old syntax:

首先,让我们看一下旧的语法。

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";
}

And now, let’s see the same logic witch switch expressions:

现在,让我们看看同样的逻辑巫师切换表达。

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

New switch statements are not only more compact and readable. They also remove the need for break statements. The code execution will not fall through after the first match.

新的switch语句不仅更加紧凑和可读。它们还消除了对break语句的需要。代码的执行不会在第一次匹配后出现中断。

Another notable difference is that we can assign a switch statement directly to the variable. It was not possible previously.

另一个值得注意的区别是,我们可以直接给变量分配一个开关语句。这在以前是不可能的。

It’s also possible to execute code in switch expressions without returning any value:

也可以在switch表达式中执行代码而不返回任何值。

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

More complex logic should be wrapped with curly braces:

更复杂的逻辑应该用大括号来包装。

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

Note that we can choose between the old and new syntax. Java 12 switch expressions are only an extension, not a replacement.

请注意,我们可以在新旧两种语法之间进行选择。Java 12的切换表达式只是一种扩展,而不是一种替代。

3.2. Pattern Matching for instanceof (Preview)

3.2.instanceof的模式匹配 (预览)

Another preview feature introduced in Java 12 is pattern matching for instanceof.

Java 12中引入的另一个预览功能是针对instanceof的模式匹配

In previous Java versions, when using, for example, if statements together with instanceof, we would have to explicitly typecast the object to access its features:

在以前的Java版本中,当与instanceof一起使用if语句时,我们必须明确地对对象进行类型转换以访问其功能。

Object obj = "Hello World!";
if (obj instanceof String) {
    String s = (String) obj;
    int length = s.length();
}

With Java 12, we can declare the new typecasted variable directly in the statement:

在Java 12中,我们可以直接在语句中声明新的类型转换变量。

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

The compiler will automatically inject the typecasted String s variable for us.

编译器将自动为我们注入类型化的String s变量。

4. JVM Changes

4.JVM的变化

Java 12 comes with several JVM enhancements. In this section, we’ll have a quick look at a few most important ones.

Java 12带有几个JVM的增强功能。在本节中,我们将快速浏览几个最重要的增强。

4.1. Shenandoah: A Low-Pause-Time Garbage Collector

4.1.Shenandoah:一个低脉冲时间的垃圾收集器

Shenandoah is an experimental garbage collection (GC) algorithm, for now not included in the default Java 12 builds.

Shenandoah是一种实验性的垃圾收集(GC)算法,目前不包括在默认的Java 12构建中。

It reduces the GC pause times by doing evacuation work simultaneously with the running Java threads. This means that with Shenandoah, pause times are not dependent on the heap’s size and should be consistent. Garbage collecting a 200 GB heap or a 2 GB heap should have a similar low pause behavior.

它通过与运行中的Java线程同时进行疏散工作来减少GC的暂停时间。这意味着使用Shenandoah,暂停时间不依赖于堆的大小,应该是一致的。对200GB的堆或2GB的堆进行垃圾收集,应该有类似的低暂停行为。

Shenandoah will become part of mainline JDK builds since version 15.

Shenandoah将从15版开始成为JDK主线构建的一部分。

4.2. Microbenchmark Suite

4.2 微观基准测试套件

Java 12 introduces a suite of around 100 microbenchmark tests to the JDK source code.

Java 12为JDK源代码引入了一套约100个微基准测试。

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.

这些测试将允许在JVM上进行连续的性能测试,并对每个希望在JVM本身上工作或创建一个新的微基准的开发人员变得有用。

4.3. Default CDS Archives

4.3.违约CDS档案

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.

类数据共享(CDS)功能有助于减少多个Java虚拟机之间的启动时间和内存占用。它使用一个内置时生成的默认类列表,其中包含选定的核心库类。

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:

Java 12带来的变化是,CDS存档默认是启用的。要在关闭CDS的情况下运行程序,我们需要将Xshare标志设置为关闭。

java -Xshare:off HelloWorld.java

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

注意,这可能会延迟程序的启动时间。

5. Conclusion

5.总结

In this article, we saw most of the new features implemented in Java 12. We also listed down some other notable additions and deletions. As usual, source code is available over on GitHub.

在这篇文章中,我们看到了Java 12中实现的大部分新功能。我们还列举了其他一些值得注意的增删内容。像往常一样,源代码可在GitHub上获得。