Java 12新特性全面解析:开发者必知的功能改进与应用技巧
最终,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。
- 切换表达式
- 文件mismatch()方法
- 紧凑数字格式
- 流API中的合并收集器
- 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,旨在无论堆大小如何保持一致且可预测的短暂暂停。因此,堆大小是15MB还是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源代码中添加了一个基本的微基准套件。这使开发人员能够轻松运行现有的微基准并创建新的基准。JEP 344只保留了与32位ARM端口和64位aarch64端口相关的源代码,移除了与arm64端口相关的所有源代码。这使得贡献者能够将精力集中在单个64位ARM实现上。
5. JEP 341 默认 CDS 归档
这个增强了JDK构建过程,用于在64位平台上生成一个使用默认类列表的类数据共享(CDS)存档。目标是提高启动时间。从Java 12开始,默认情况下CDS是开启的。如果要关闭CDS并运行程序,请按以下步骤操作。
java -Xshare:off HelloWorld.java
现在,这会延迟程序的启动时间。
语言的变化和特点
Java 12引入了许多语言特性,让我们来看一些具体的实现。
1. 开关表达式(预览版)
Java 12对模式匹配的Switch表达式进行了加强。这个新的语法是在JEP 325中引入的,作为一种预览语言特性。以下是关于Switch表达式需要注意的一些事项:
- 新语法消除了使用break语句来防止fallthroughs的需要。
- Switch表达式不再发生fallthrough。
- 此外,我们可以在同一标签中定义多个常量。
- 在Switch表达式中,default case现在是强制性的。
- 在Switch表达式中,break用于从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);
让我们运行包含新的 JDK 12 Switch 表达式的以下程序。
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. 文件不匹配方法
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("文件不匹配位置...如果没有不匹配则返回-1");
System.out.println("file1和file2中的不匹配位置是 >>>>");
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("file3和file4中的不匹配位置是 >>>>");
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("紧凑格式化是:");
NumberFormat upvotes = NumberFormat
.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.SHORT);
upvotes.setMaximumFractionDigits(1);
System.out.println(upvotes.format(2592) + " 个赞");
NumberFormat upvotes2 = NumberFormat
.getCompactNumberInstance(new Locale("en", "US"), NumberFormat.Style.LONG);
upvotes2.setMaximumFractionDigits(2);
System.out.println(upvotes2.format(2011) + " 个赞");
}
}

4. 划分收集器
Teeing Collector(分流收集器)是在 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 Constants API – JEP 334:JVM 常量 API
这个 JEP 引入了一个新包 java.lang.constant。对于不使用常量池的开发者来说,这并不是很有用。
7. JEP 305: instanceof的模式匹配(预览)
另一个预览语言功能!以前将一种类型转换为另一种类型的方法是:
if (obj instanceof String) {
String s = (String) obj;
// 从这里开始可以在代码中使用s
}
新的方式是:
if (obj instanceof String s) {
// 可以在这里直接使用s
}
这样做可以避免一些不必要的类型转换。
JDK 12 中已移除原始字符串字面值。
这篇文章介绍了Java 12的特性,到这里就结束了。