1. 序章

このチュートリアルでは、Java12に付属するいくつかの新機能の概要を簡単に説明します。 すべての新機能の完全なリストは、公式ドキュメントで入手できます。

2. 言語の変更と機能

Java 12には、多くの新しい言語機能が導入されています。 このセクションでは、理解を深めるために、いくつかの最も興味深いものとコード例について説明します。

2.1. 文字列クラスの新しいメソッド

Java 12には、Stringクラスに2つの新しいメソッドが付属しています。

最初のもの– indent は、整数パラメーターに基づいて各行のインデントを調整します。 パラメータがゼロより大きい場合、各行の先頭に新しいスペースが挿入されます。 一方、パラメータがゼロ未満の場合は、各行の先頭からスペースが削除されます。 特定の行に十分な空白が含まれていない場合、先頭の空白文字はすべて削除されます。

それでは、基本的な例を見てみましょう。 まず、テキストを4つのスペースでインデントし、次にインデント全体を削除します。

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

出力は次のようになります。

    Hello Baeldung!
    This is Java 12 article.

Hello Baeldung!
This is Java 12 article.

インデント数を超える値-10を渡しても、影響を受けるのはスペースだけであることに注意してください。 他の文字はそのまま残されます。

2番目の新しいメソッドはtransformです。 文字列に適用されるパラメータとして単一の引数関数を受け入れます。

例として、transformメソッドを使用して文字列を元に戻しましょう。

@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メソッド

Java 12では、nio.file.Filesユーティリティクラスに新しいmismatchメソッドが導入されました。

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

このメソッドは、2つのファイルを比較し、それらの内容の最初の不一致バイトの位置を見つけるために使用されます。

戻り値は、小さいファイルのバイトサイズまでの0Lの範囲、またはファイルが同一の場合は-1Lの範囲になります。

次に、2つの例を見てみましょう。 最初のファイルでは、2つの同一のファイルを作成し、不一致を見つけようとします。 戻り値は-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);
}

2番目の例では、「Java12Article」と「Java12Tutorial」の内容の2つのファイルを作成します。 不一致メソッドは、最初の異なるバイトであるため、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コレクターは、Collectorsクラスへの追加としてJava12に導入されました。

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

これは、2つのダウンストリームコレクターの複合体です。 すべての要素は、両方のダウンストリームコレクターによって処理されます。 次に、それらの結果がマージ関数に渡され、最終結果に変換されます。

ティーコレクターの使用例は、一連の数値から平均を数えることです。 最初のコレクターパラメーターは値を合計し、2番目のパラメーターはすべての数値のカウントを提供します。 マージ関数はこれらの結果を取得し、平均をカウントします。

@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. コンパクトな数値フォーマット

Java 12には、新しい数値フォーマッタCompactNumberFormatが付属しています。 特定のロケールで提供されるパターンに基づいて、数値を短い形式で表すように設計されています。

そのインスタンスは、NumberFormatクラスのgetCompactNumberInstanceメソッドを介して取得できます。

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

前述のように、localeパラメーターは適切なフォーマットパターンを提供する役割を果たします。 フォーマットスタイルは、SHORTまたはLONGのいずれかです。 フォーマットスタイルをよりよく理解するために、米国ロケールの1000番を考えてみましょう。 SHORTスタイルは「10K」としてフォーマットし、LONGスタイルは「10,000」としてフォーマットします。

次に、この記事のいいねの数を取得し、2つの異なるスタイルで圧縮する例を見てみましょう。

@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. プレビューの変更

一部の新機能は、プレビューとしてのみ利用できます。 それらを有効にするには、IDEで適切な設定を切り替えるか、プレビュー機能を使用するようにコンパイラーに明示的に指示する必要があります。

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

3.1. 式の切り替え(プレビュー)

Java 12で導入された最も人気のある機能は、スイッチ式です。

デモンストレーションとして、古いswitchステートメントと新しいswitchステートメントを比較してみましょう。 これらを使用して、DayOfWeek列挙型とLocalDateインスタンスに基づいて、営業日と週末を区別します。

まず、古い構文を見てみましょう。

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

そして今、同じ論理魔女スイッチ式を見てみましょう:

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

新しいswitchステートメントは、よりコンパクトで読みやすいだけではありません。 また、breakステートメントの必要性を排除します。 最初の一致後、コードの実行は失敗しません。

もう1つの注目すべき違いは、switchステートメントを変数に直接割り当てることができることです。 以前は不可能でした。

値を返さずにスイッチ式でコードを実行することもできます。

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

より複雑なロジックは中括弧で囲む必要があります。

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

古い構文と新しい構文のどちらかを選択できることに注意してください。 Java 12スイッチ式は単なる拡張であり、置き換えではありません。

3.2. instanceof のパターンマッチング(プレビュー)

Java 12で導入されたもう1つのプレビュー機能は、instanceofのパターンマッチングです。

以前のJavaバージョンでは、たとえば、ifステートメントを instanceof、と一緒に使用する場合、その機能にアクセスするには、オブジェクトを明示的に型キャストする必要がありました。

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

Java 12では、新しいタイプキャスト変数をステートメントで直接宣言できます。

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

コンパイラーは、タイプキャストされた Strings変数を自動的に挿入します。

4. JVMの変更

Java 12には、いくつかのJVM拡張機能が付属しています。 このセクションでは、いくつかの最も重要なものを簡単に見ていきます。

4.1. Shenandoah:低休止時間のガベージコレクター

Shenandoahは実験的なガベージコレクション(GC)アルゴリズムであり、現在のところデフォルトのJava12ビルドには含まれていません。

実行中のJavaスレッドと同時に退避作業を行うことにより、GCの一時停止時間を短縮します。 つまり、Shenandoahでは、一時停止時間はヒープのサイズに依存せず、一貫している必要があります。 200GBのヒープまたは2GBのヒープを収集するガベージは、同様の低ポーズ動作をする必要があります。

Shenandoahは、バージョン15以降のメインラインJDKビルドの一部になります。

4.2. マイクロベンチマークスイート

Java 12は、約100のマイクロベンチマークテストのスイートをJDKソースコードに導入します。

これらのテストにより、JVMでの継続的なパフォーマンステストが可能になり、JVM自体で作業したり、新しいマイクロベンチマークを作成したりするすべての開発者にとって役立ちます。

4.3. デフォルトのCDSアーカイブ

クラスデータ共有(CDS)機能は、複数のJava仮想マシン間の起動時間とメモリフットプリントを削減するのに役立ちます。 選択されたコアライブラリクラスを含む、ビルド時に生成されたデフォルトのクラスリストを使用します。

Java 12に伴う変更は、CDSアーカイブがデフォルトで有効になっていることです。 CDSをオフにしてプログラムを実行するには、Xshareフラグをオフに設定する必要があります。

java -Xshare:off HelloWorld.java

これにより、プログラムの起動時間が遅れる可能性があることに注意してください。

5. 結論

この記事では、Java12に実装されているほとんどの新機能について説明しました。 また、その他の注目すべき追加と削除をいくつかリストアップしました。 いつものように、ソースコードはGitHubから入手できます。