Java 12 ~ 13 新特性概览

Guide
  • Java
  • Java新特性
2022年3月1日约 1768 字大约 6 分钟

Java12

String 增强

Java 11 增加了两个的字符串处理方法,如以下所示。

indent() 方法可以实现字符串缩进。

String text = "Java";
// 缩进 4 格
text = text.indent(4);
System.out.println(text);
text = text.indent(-10);
System.out.println(text);

输出:

     Java
Java

transform() 方法可以用来转变指定字符串。

String result = "foo".transform(input -> input + " bar");
System.out.println(result); // foo bar

Files 增强(文件比较)

Java 12 添加了以下方法来比较两个文件:

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

mismatch() 方法用于比较两个文件,并返回第一个不匹配字符的位置,如果文件相同则返回 -1L。

代码示例(两个文件内容相同的情况):

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

代码示例(两个文件内容不相同的情况):

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

数字格式化工具类

NumberFormat 新增了对复杂的数字进行格式化的支持

NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
String result = fmt.format(1000);
 System.out.println(result); 

输出:

1K

Shenandoah GC

Redhat 主导开发的 Pauseless GC 实现,主要目标是 99.9% 的暂停小于 10ms,暂停与堆大小无关等

和 Java11 开源的 ZGC 相比(需要升级到 JDK11 才能使用),Shenandoah GC 有稳定的 JDK8u 版本,在 Java8 占据主要市场份额的今天有更大的可落地性。

G1 收集器优化

Java12 为默认的垃圾收集器 G1 带来了两项更新:

  • 可中止的混合收集集合 :JEP344 的实现,为了达到用户提供的停顿时间目标,JEP 344 通过把要被回收的区域集(混合收集集合)拆分为强制和可选部分,使 G1 垃圾回收器能中止垃圾回收过程。 G1 可以中止可选部分的回收以达到停顿时间目标
  • 及时返回未使用的已分配内存 :JEP346 的实现,增强 G1 GC,以便在空闲时自动将 Java 堆内存返回给操作系统

预览新特性

作为预览特性加入,需要在javac编译和java运行时增加参数--enable-preview

增强 Switch

传统的 switch 语法存在容易漏写 break 的问题,而且从代码整洁性层面来看,多个 break 本质也是一种重复。

Java12 增强了 switch 表达式,使用类似 lambda 语法条件匹配成功后的执行块,不需要多写 break 。

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

instanceof 模式匹配

instanceof 主要在类型强转前探测对象的具体类型。

之前的版本中,我们需要显示地对对象进行类型转换。

Object obj = "我是字符串";
if(obj instanceof String){
   String str = (String) obj;
	System.out.println(str);
}

新版的 instanceof 可以在判断是否属于具体的类型同时完成转换。

Object obj = "我是字符串";
if(obj instanceof String str){
	System.out.println(str);
}

Java13

增强 ZGC(释放未使用内存)

在 Java 11 中是实验性的引入的 ZGC 在实际的使用中存在未能主动将未使用的内存释放给操作系统的问题。

ZGC 堆由一组称为 ZPages 的堆区域组成。在 GC 周期中清空 ZPages 区域时,它们将被释放并返回到页面缓存 ZPageCache 中,此缓存中的 ZPages 按最近最少使用(LRU)的顺序,并按照大小进行组织。

在 Java 13 中,ZGC 将向操作系统返回被标识为长时间未使用的页面,这样它们将可以被其他进程重用。

SocketAPI 重构

Java Socket API 终于迎来了重大更新!

Java 13 将 Socket API 的底层进行了重写, NioSocketImpl 是对 PlainSocketImpl 的直接替代,它使用 java.util.concurrent 包下的锁而不是同步方法。如果要使用旧实现,请使用 -Djdk.net.usePlainSocketImpl=true

并且,在 Java 13 中是默认使用新的 Socket 实现。

public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl {
}

FileSystems

FileSystems 类中添加了以下三种新方法,以便更容易地使用将文件内容视为文件系统的文件系统提供程序:

  • newFileSystem(Path)
  • newFileSystem(Path, Map<String, ?>)
  • newFileSystem(Path, Map<String, ?>, ClassLoader)

动态 CDS 存档

Java 13 中对 Java 10 中引入的应用程序类数据共享(AppCDS)进行了进一步的简化、改进和扩展,即:允许在 Java 应用程序执行结束时动态进行类归档,具体能够被归档的类包括所有已被加载,但不属于默认基层 CDS 的应用程序类和引用类库中的类。

这提高了应用程序类数据共享(AppCDSopen in new window)的可用性。无需用户进行试运行来为每个应用程序创建类列表。

$ java -XX:ArchiveClassesAtExit=my_app_cds.jsa -cp my_app.jar
$ java -XX:SharedArchiveFile=my_app_cds.jsa -cp my_app.jar

预览新特性

文本块

解决 Java 定义多行字符串时只能通过换行转义或者换行连接符来变通支持的问题,引入三重双引号来定义多行文本。

Java 13 支持两个 """ 符号中间的任何内容都会被解释为字符串的一部分,包括换行符。

未支持文本块之前的 HTML 写法:

String json ="{\n" +
              "   \"name\":\"mkyong\",\n" +
              "   \"age\":38\n" +
              "}\n";

支持文本块之后的 HTML 写法:

 String json = """
                {
                    "name":"mkyong",
                    "age":38
                }
                """;

未支持文本块之前的 SQL 写法:

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";

支持文本块之后的 SQL 写法:

String query = """
               SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
               WHERE `CITY` = 'INDIANAPOLIS'
               ORDER BY `EMP_ID`, `LAST_NAME`;
               """;

另外,String 类新增加了 3 个新的方法来操作文本块:

  • formatted(Object... args) :它类似于 Stringformat()方法。添加它是为了支持文本块的格式设置。
  • stripIndent() :用于去除文本块中每一行开头和结尾的空格。
  • translateEscapes() :转义序列如 “\\t” 转换为 “\t”

由于文本块是一项预览功能,可以在未来版本中删除,因此这些新方法被标记为弃用。

@Deprecated(forRemoval=true, since="13")
public String stripIndent() {
}
@Deprecated(forRemoval=true, since="13")
public String formatted(Object... args) {

}
@Deprecated(forRemoval=true, since="13")
public String translateEscapes() {
}

增强 Switch(引入 yield 关键字到 Switch 中)

Switch 表达式中就多了一个关键字用于跳出 Switch 块的关键字 yield,主要用于返回一个值

yieldreturn 的区别在于:return 会直接跳出当前循环或者方法,而 yield 只会跳出当前 Switch 块,同时在使用 yield 时,需要有 default 条件

 private static String descLanguage(String name) {
        return switch (name) {
            case "Java": yield "object-oriented, platform independent and secured";
            case "Ruby": yield "a programmer's best friend";
            default: yield name +" is a good language";
        };
 }

参考