终于,作为六个月发布周期的一部分,JDK 12来了。这是继上一个Java LTS版本11之后的一次更新。我们之前对Java 11的特性进行了详细讨论。今天我们将讨论Java 12的特性,看看它为开发者们准备了什么。Java 12于2019年3月19日发布,属于非LTS版本,因此不提供长期支持。
Java 12的特性
其中一些重要的Java 12特性包括:
- JVM变更 – JEP 189、JEP 346、JEP 344和JEP 230。
- Switch表达式
- 文件mismatch()方法
- 紧凑型数字格式
- 在Stream API中使用的Teeing Collectors
- Java字符串新方法 – indent()、transform()、describeConstable()和resolveConstantDesc()。
- JEP 334:JVM常量API
- JEP 305:instanceof的模式匹配
- 从JDK 12中移除了原始字符串文字。
让我们逐个查看所有这些Java 12的特性。
JVM变更
1. JEP 189 – Shenandoah:低暂停时间垃圾收集器(实验性)
RedHat启动了Shenandoah垃圾收集器,以减少GC暂停时间。其理念是与正在运行的Java线程并发地运行GC。它旨在实现一致且可预测的短暂停,与堆大小无关。因此,无论堆大小是15 MB还是15GB都无关紧要。这是Java 12中的一个实验性特性。
2. JEP 346 – G1迅速返回未使用的已分配内存
自Java 12起,G1现在将在应用程序不活动期间检查Java堆内存并将其返回给操作系统。这是一项预防性措施,用于保存和利用空闲内存。
3. JEP 344:G1中可中止的混合收集
G1 效率的改进包括使 G1 混合收集可中止,如果它们可能超过定义的暂停目标。这是通过将混合收集集合分成强制和可选两部分来实现的。因此,G1 收集器可以优先收集强制集合,以满足暂停时间目标。
4. JEP 230 和 344
微基准套件,JEP 230功能将一组基本微基准添加到 JDK 源代码中。这使得开发人员可以轻松运行现有的微基准并创建新的微基准。一个 AArch64 端口,不是两个,JEP 344,移除了所有与 arm64 端口相关的源代码,同时保留了 32 位 ARM 端口和 64 位 aarch64 端口。这使得贡献者可以将精力集中在单个 64 位 ARM 实现上。
5. JEP 341 默认 CDS 存档
这增强了 JDK 构建过程,以在 64 位平台上使用默认类列表生成类数据共享(CDS)存档。目标是改善启动时间。从 Java 12 开始,默认情况下启用了 CDS。要禁用 CDS 运行程序,请执行以下操作:
java -Xshare:off HelloWorld.java
现在,这将延迟程序的启动时间。
语言变更和特性
Java 12引入了许多语言特性。让我们看一些具体的实现。
1. Switch 表达式(预览版)
Java 12为模式匹配增强了Switch表达式。作为预览语言特性,它在JEP 325中被引入,新的语法是L ->
。以下是关于Switch表达式的一些注意事项:
- 新的语法去除了防止穿透的break语句的需要。
- Switch表达式不再发生穿透。
- 此外,我们可以在同一标签中定义多个常量。
default
情况现在在Switch表达式中是强制的。break
用于在Switch表达式中从一个case中返回值。
经典的switch语句:
String result = "";
switch (day) {
case "M":
case "W":
case "F": {
result = "MWF";
break;
}
case "T":
case "TH":
case "S": {
result = "TTS";
break;
}
};
System.out.println("Old Switch Result:");
System.out.println(result);
有了新的Switch表达式,我们不再需要到处设置break,从而避免逻辑错误!
String result = switch (day) {
case "M", "W", "F" -> "MWF";
case "T", "TH", "S" -> "TTS";
default -> {
if(day.isEmpty())
break "Please insert a valid day.";
else
break "Looks like a Sunday.";
}
};
System.out.println(result);
让我们运行包含新Switch表达式的下面程序,使用JDK 12。
public class SwitchExpressions {
public static void main(String[] args)
{
System.out.println("New Switch Expression result:");
executeNewSwitchExpression("M");
executeNewSwitchExpression("TH");
executeNewSwitchExpression("");
executeNewSwitchExpression("SUN");
}
public static void executeNewSwitchExpression(String day){
String result = switch (day) {
case "M", "W", "F" -> "MWF";
case "T", "TH", "S" -> "TTS";
default -> {
if(day.isEmpty())
break "Please insert a valid day.";
else
break "Looks like a Sunday.";
}
};
System.out.println(result);
}
}
由于这是一个预览功能,请确保已选择语言级别为 Java 12 预览。要编译上述代码,请运行以下命令:
javac -Xlint:preview --enable-preview -source 12 src/main/java/SwitchExpressions.java
运行编译程序后,我们在控制台得到以下结果:

Switch 表达式是一个预览语言功能。这意味着即使它是完整的,未来的 Java 版本可能不会确认它。
2. File.mismatch 方法
Java 12 添加了以下方法来比较两个文件:
public static long mismatch(Path path, Path path2) throws IOException
此方法返回第一个不匹配的位置,如果没有不匹配,则返回 -1L。两个文件可能在以下情况下不匹配:
- 如果字节不相同。在这种情况下,返回第一个不匹配字节的位置。
- 文件大小不相同。在这种情况下,返回较小文件的大小。
下面是从 IntelliJ Idea 给出的示例代码片段:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileMismatchExample {
public static void main(String[] args) throws IOException {
Path filePath1 = Files.createTempFile("file1", ".txt");
Path filePath2 = Files.createTempFile("file2", ".txt");
Files.writeString(filePath1,"JournalDev Test String");
Files.writeString(filePath2,"JournalDev Test String");
long mismatch = Files.mismatch(filePath1, filePath2);
System.out.println("File Mismatch position... It returns -1 if there is no mismatch");
System.out.println("Mismatch position in file1 and file2 is >>>>");
System.out.println(mismatch);
filePath1.toFile().deleteOnExit();
filePath2.toFile().deleteOnExit();
System.out.println();
Path filePath3 = Files.createTempFile("file3", ".txt");
Path filePath4 = Files.createTempFile("file4", ".txt");
Files.writeString(filePath3,"JournalDev Test String");
Files.writeString(filePath4,"JournalDev.com Test String");
long mismatch2 = Files.mismatch(filePath3, filePath4);
System.out.println("Mismatch position in file3 and file4 is >>>>");
System.out.println(mismatch2);
filePath3.toFile().deleteOnExit();
filePath4.toFile().deleteOnExit();
}
}
上述 Java 程序编译并运行时的输出为:

3. 紧凑型数字格式化
import java.text.NumberFormat;
import java.util.Locale;
public class CompactNumberFormatting {
public static void main(String[] args)
{
System.out.println("Compact Formatting is:");
NumberFormat upvotes = NumberFormat
.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT);
upvotes.setMaximumFractionDigits(1);
System.out.println(upvotes.format(2592) + " upvotes");
NumberFormat upvotes2 = NumberFormat
.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.LONG);
upvotes2.setMaximumFractionDigits(2);
System.out.println(upvotes2.format(2011) + " upvotes");
}
}

4. 分流收集器
分流收集器是Streams API中引入的新收集器实用程序。该收集器有三个参数 – 两个收集器和一个双函数。所有输入值都传递给每个收集器,并且结果在双函数中可用。
double mean = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.teeing(
summingDouble(i -> i),
counting(),
(sum, n) -> sum / n));
System.out.println(mean);
输出为3.0。
5. Java字符串新方法
Java 12中引入了4种新方法,分别是:
- indent(int n)
- transform(Function f)
- Optional describeConstable()
- String resolveConstantDesc(MethodHandles.Lookup lookup)
要详细了解上述方法及其实现,请参阅我们的Java 12字符串方法教程。
6. JEP 334:JVM常量API
A new package java.lang.constant
is introduced with this JEP. This is not that useful for those developers who don’t use constants pool.
7. JEP 305: instanceof 的模式匹配(预览)
另一个预览语言特性!以前将一种类型强制转换为另一种类型的旧方法是:
if (obj instanceof String) {
String s = (String) obj;
// 从这里开始在你的代码中使用 s
}
新方法是:
if (obj instanceof String s) {
// 可以直接在这里使用 s
}
这样可以节省一些不必要的类型转换。
JDK 12 中移除了原始字符串文字。
这就结束了关于 Java 12 特性的文章。
Source:
https://www.digitalocean.com/community/tutorials/java-12-features