📜  Java 12 的新特性

📅  最后修改于: 2022-05-13 01:55:47.394000             🧑  作者: Mango

Java 12 的新特性

Oracle 于 2019 年 3 月 19 日发布了Java SE(标准版)12,之后他们计划每六个月发布一个新版本。 JDK 12 比 JDK 11 有很多改进。这个最新版本提供了一系列新功能,例如 Switch Expressions、默认 CDS Archives、Shenandoah、Microbenchmark Suite 等。下面将讨论这些新功能。

1. Switch 表达式的变化

Switch 表达式现在将用作语句和表达式。这使得交换机的代码简化和模式匹配成为可能。

  • 在早期版本中,缺少 break 语句会导致默认失败,这很容易出错。
  • 默认情况在 switch 表达式中是强制性的。

现在,新的 switch 箭头语法引入为

case X -> {} 

表示只有标签匹配,才会执行箭头右侧的语句。

Java 11 和Java 12 的 Switch 表达式可以比较如下:

Java11

Java
// Java program to demonstrate the
// classic switch statement
  
import java.io.*;
  
class Java11switchStatement {
  
    static int getMealNumber(String meal)
    {
        // stores mealNumber
        int mealNumber;
  
        // classic switch statement
        switch (meal) {
  
        case "SOUP":
            mealNumber = 1;
            break;
  
        case "BURGER":
  
        case "CHIPS":
  
        case "SANDWICH":
            mealNumber = 2;
            break;
  
        case "SPAGETTI":
  
        case "MACRONI":
            mealNumber = 3;
            break;
  
        default:
            throw new IllegalStateException(
                "Cannot prepare " + meal);
        }
  
        return mealNumber;
    }
    public static void main(String[] args)
    {
  
        // define meal
        String meal = "BURGER";
  
        // print mealNumber
        System.out.println("The mealNumber is : "
                           + getMealNumber(meal));
    }
}


Java
// Java program to demonstrate the
// new switch expression
  
import java.io.*;
  
class Java11switchStatement {
  
      // returns mealNumber
    static int getMealNumber(String meal)
    {
  
        // stores mealNumber using
        // new switch expression
        int mealNumber = switch (meal)
        {
  
           case "SOUP" -> 1;
  
           case "BURGER", "CHIPS", "SANDWICH" -> 2;
  
           case "SPAGETTI", "MACRONI" -> 3;
              
           default -> throw new IllegalException("");
        }
  
        return mealNumber;
    }
    
    public static void main(String[] args)
    {
  
        // define meal
        String meal = "BURGER";
  
        // print mealNumber
        System.out.println("The mealNumber is : "
                           + getMealNumber(meal));
    }
}


Java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
  
public class FilesCompareExample {
  
    public static void main(String[] args)
        throws IOException
    {
        Path path1 = Files.createTempFile("file1", ".txt");
        Path path2 = Files.createTempFile("file2", ".txt");
        Files.writeString(path1, "Geeks for geeks");
        Files.writeString(path2, "Geeks for geeks");
  
        long mismatch1 = Files.mismatch(path1, path2);
  
        System.out.println(
            "File Mismatch position or -1 is returned if there is no mismatch");
  
        System.out.println(
            "Mismatch position in file1 and file2 is : "
            + mismatch1);
  
        path1.toFile().deleteOnExit();
        path2.toFile().deleteOnExit();
  
        System.out.println();
  
        Path path3 = Files.createTempFile("file3", ".txt");
        Path path4 = Files.createTempFile("file4", ".txt");
        Files.writeString(path3, "Geeks for geeks");
        Files.writeString(path4, "Geeks for the geeks");
  
        long mismatch2 = Files.mismatch(path3, path4);
  
        System.out.println(
            "Mismatch position in file3 and file4 is : "
            + mismatch2);
  
        path3.toFile().deleteOnExit();
        path4.toFile().deleteOnExit();
    }
}


Java
import java.text.NumberFormat;
import java.util.Locale;
  
public class CompactFormatExample {
    public static void main(String[] args)
    {
        NumberFormat fmtLong
            = NumberFormat.getCompactNumberInstance(
                Locale.US, NumberFormat.Style.LONG);
  
        System.out.println(fmtLong.format(100));
        System.out.println(fmtLong.format(1000));
        System.out.println(fmtLong.format(10000));
  
        NumberFormat fmtShort
            = NumberFormat.getCompactNumberInstance(
                Locale.US, NumberFormat.Style.SHORT);
  
        System.out.println(fmtShort.format(100));
        System.out.println(fmtShort.format(1000));
        System.out.println(fmtShort.format(10000));
    }
}


Java
import java.io.*;
import java.util.*;
  
class TeeingCollectorsExample {
    public static void main(String[] args)
    {
        double mean
            = Stream.of(2, 3, 4, 5, 6)
                  .collect(Collectors.teeing(
                      summingDouble(i -> i), counting(),
                      (sum, n) -> sum / n));
  
        System.out.println(mean);
    }
}


输出
The mealNumber is : 2



Java12

Java

// Java program to demonstrate the
// new switch expression
  
import java.io.*;
  
class Java11switchStatement {
  
      // returns mealNumber
    static int getMealNumber(String meal)
    {
  
        // stores mealNumber using
        // new switch expression
        int mealNumber = switch (meal)
        {
  
           case "SOUP" -> 1;
  
           case "BURGER", "CHIPS", "SANDWICH" -> 2;
  
           case "SPAGETTI", "MACRONI" -> 3;
              
           default -> throw new IllegalException("");
        }
  
        return mealNumber;
    }
    
    public static void main(String[] args)
    {
  
        // define meal
        String meal = "BURGER";
  
        // print mealNumber
        System.out.println("The mealNumber is : "
                           + getMealNumber(meal));
    }
}

输出

The mealNumber is : 2

2. Shenandoah(一个新的和改进的垃圾收集器)

这是一项实验性功能,并引入了一种新的垃圾回收 (GC) 算法 Shenandoah。它通过与运行的Java线程并发执行疏散工作来提供低暂停时间。这样,暂停时间与堆大小无关。例如,5MB 的堆与 10GB 的堆具有相同的暂停时间。

3. JVM 常量 API :这个 API 帮助那些操作类和方法的程序。这些程序需要对字节码指令进行建模并处理可加载的常量。 String 或 Integer 类型的常量工作正常。但是,将常量类型作为类变得棘手。如果 Class 不可访问或不存在,则加载类可能会失败。使用新的 API,ClassDesc、MethodTypeDesc、MethodHandleDesc 和 DynamicConstantDesc 等接口以符号方式处理常量值,从而消除了复杂性。

4. G1 的可中止混合收集:默认垃圾收集器 Garbage First (G1) 使用分析引擎来确定收集集,一旦收集开始,所有活动对象都应在不停止的情况下收集。这会导致超过目标暂停时间。为了解决这个问题,G1 集合集合通过将集合分解为可选部分和强制部分来中止。通过对强制设置进行优先级排序,可以经常实现暂停时间目标。

5. 默认 CDS 档案:创建类数据共享 (CDS) 档案以使 JDK 构建过程更高效,从而提高开箱即用的启动时间。

6. Microbenchmark 套件:开发人员可以通过添加到 JDK 源代码中的 microbenchmark 套件轻松运行现有或新的基准测试。

7. 及时从 G1 返回未使用的已提交内存:有了这个改进的功能,当 G1 空闲时,垃圾收集器会自动将未使用的堆内存返回给操作系统。这是通过 G1 并发检查Java堆来完成的。

8) Files.mismatch() 方法:这个新方法比较两个文件。

方法签名

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

返回: -1L如果没有不匹配 else第一个不匹配的位置

在两种情况中的任何一种情况下,它都会返回不匹配的位置。

  • 情况 1 :如果文件的大小不匹配。这里,返回较小文件的大小。
  • 情况 2 :如果字节不匹配。在这里,返回第一个不匹配的字节。

例子:

Java

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
  
public class FilesCompareExample {
  
    public static void main(String[] args)
        throws IOException
    {
        Path path1 = Files.createTempFile("file1", ".txt");
        Path path2 = Files.createTempFile("file2", ".txt");
        Files.writeString(path1, "Geeks for geeks");
        Files.writeString(path2, "Geeks for geeks");
  
        long mismatch1 = Files.mismatch(path1, path2);
  
        System.out.println(
            "File Mismatch position or -1 is returned if there is no mismatch");
  
        System.out.println(
            "Mismatch position in file1 and file2 is : "
            + mismatch1);
  
        path1.toFile().deleteOnExit();
        path2.toFile().deleteOnExit();
  
        System.out.println();
  
        Path path3 = Files.createTempFile("file3", ".txt");
        Path path4 = Files.createTempFile("file4", ".txt");
        Files.writeString(path3, "Geeks for geeks");
        Files.writeString(path4, "Geeks for the geeks");
  
        long mismatch2 = Files.mismatch(path3, path4);
  
        System.out.println(
            "Mismatch position in file3 and file4 is : "
            + mismatch2);
  
        path3.toFile().deleteOnExit();
        path4.toFile().deleteOnExit();
    }
}

输出

Mismatch position in file1 and file2 is : -1 
Mismatch position in file3 and file4 is : 10 

9) Compact Number Formatting : 它是应用于通用数字的格式,例如小数、货币、百分比,以使其由于空间限制而变得紧凑。在下面的示例中,1000 在短样式中将被格式化为“1K”,在长样式中将被格式化为“1000”。

Java

import java.text.NumberFormat;
import java.util.Locale;
  
public class CompactFormatExample {
    public static void main(String[] args)
    {
        NumberFormat fmtLong
            = NumberFormat.getCompactNumberInstance(
                Locale.US, NumberFormat.Style.LONG);
  
        System.out.println(fmtLong.format(100));
        System.out.println(fmtLong.format(1000));
        System.out.println(fmtLong.format(10000));
  
        NumberFormat fmtShort
            = NumberFormat.getCompactNumberInstance(
                Locale.US, NumberFormat.Style.SHORT);
  
        System.out.println(fmtShort.format(100));
        System.out.println(fmtShort.format(1000));
        System.out.println(fmtShort.format(10000));
    }
}

输出

100
1 thousand
10 thousand
100
1K
10K

10) Stream API 中的Teeing 收集器:Collectors.teeing() 是新的辅助函数,有助于将两步函数合并为一个步骤。这会减少冗长的代码。

方法签名

public static Collector teeing​ (Collector downstream1, Collector downstream2, BiFunction merger);

在这里,我们在两个不同的收集器上执行两个不同的流操作,并使用提供的BiFunction合并结果。

例子:

Java

import java.io.*;
import java.util.*;
  
class TeeingCollectorsExample {
    public static void main(String[] args)
    {
        double mean
            = Stream.of(2, 3, 4, 5, 6)
                  .collect(Collectors.teeing(
                      summingDouble(i -> i), counting(),
                      (sum, n) -> sum / n));
  
        System.out.println(mean);
    }
}

输出

4.0

11) Java String 新方法: Java 12 在 String 类中引入了以下新方法:

i) indent(int n) :它根据传递的参数调整给定字符串的每一行的缩进。

根据传递的n值,我们可以有以下几种情况:

  • 如果n > 0 ,则在每行开头插入空格
  • 如果n < 0 ,则在每行的开头删除空格
  • 如果n < 0n < 可用空格,则删除所有前导空格
  • 如果n = 0 ,行保持不变
String str = "**********\n  Welcome\n  Good Morning\n**********";
System.out.println(str.indent(0));
System.out.println(str.indent(3));

输出

**********
  Welcome
  Good Morning
**********
   **********
     Welcome
     Good Morning
   **********
**********
Welcome
Good Morning
********** 

ii) transform(函数 f) :它用于调用一个需要字符串参数并产生结果 R 的函数。

String s = "Java,Python,Angular";
List result = s.transform(s1 -> {return Arrays.asList(s1.split(","));});
System.out.println(result);

输出

[Java, Python, Angular]

iii) Optional describeConstable() :此方法将返回一个包含 String 实例描述符的 Optional 对象。

String message = "Welcome!";
Optional opOfMessage = message.describeConstable();
System.out.println(opOfMessage);

输出

Optional[Welcome!]

iv) String resolveConstantDesc (MethodHandles.Lookup lookup) :此方法将返回一个 String 对象,它是调用 String 实例的描述符。

String message = "Welcome!";
String constantDesc = message.resolveConstantDesc(MethodHandles.lookup());
System.out.println(constantDesc);

输出

Welcome!

尽管与Java 8 相比, Java 12 尚未普及,但更频繁地添加新功能仍然使Java可以与其他语言的更好功能相媲美,从而保持其在市场上的受欢迎程度。