TOP

このエントリーをはてなブックマークに追加

Java 14で最低限押さえておきたい新機能をEclipseで使ってみた


はじめに

2020/3/17にJava 14がリリースされました。以下の機能が追加されたようです。下の表の「本記事の対象」列に〇がついているものを少し触ってみたので後で紹介します。

JEP(※1)概要本記事の対象
305Pattern Matching for instanceof (Preview)
343Packaging Tool (Incubator)×
345NUMA-Aware Memory Allocation for G1×
349JFR Event Streaming×
352Non-Volatile Mapped Byte Buffers×
358Helpful NullPointerExceptions
359Records (Preview)
361Switch Expressions (Standard)
362Deprecate the Solaris and SPARC Ports×
363Remove the Concurrent Mark Sweep (CMS) Garbage Collector×
364ZGC on macOS×
365ZGC on Windows×
366Deprecate the ParallelScavenge + SerialOld GC Combination×
367Remove the Pack200 Tools and API×
368Text Blocks (Second Preview)
370Foreign-Memory Access API (Incubator)×

公式はこちら

※1 JEP JDK Enhancement Proposalsの略。 JDKに対する変更の提案を管理する番号。

※2 Preview プレビュー版のこと。 機能としては保証されているが、どのように使うべきかは議論の余地があるもの。開発者が実際に使ってみて、フィードバックを受けて今後もJava SEの基本機能として提供し続けるかどうかが決まる。

※3 Incubator 開発者からのフィードバックを得るために、Java SEに含めた実験的なAPI。

参考:https://xtech.nikkei.com/it/atcl/column/15/120700278/080700044/

Java 14をEclipseで使えるようにするための設定

私はEclipse使いなので、JDK 14のインストールとEclipseの設定から始めます。

JDKダウンロード

以下のサイトからJDK14をダウンロードします。 https://www.oracle.com/java/technologies/javase-downloads.html

Eclipseインストール

Eclipseの最新版をインストールします。 https://www.eclipse.org/eclipseide/

EclipseでJDK14を扱えるようにする

EclipseでJDK14を扱えるようにする手順は以下の通り。

①Eclipse Marketplaceを選択 Eclipse Marketplaceを選択

②Java 14 Support for Eclipse をインストール Java 14 Support for Eclipse をインストール

※こういったEclipse本体やプラグインのリリース情報は公式のtwitterからも流れてくるので興味ある方はフォローすることをお勧めします。


③Compiler compliance levelを14に設定 ※Java 14 Support for Eclipse をインストールしないと14が選択肢に出ません。 ccc

④Installed JREに、インストールしたJDK14を設定 ddd

⑤Execution emvironmentにJDK14を設定 eee

⑥今回はプレビューの機能も使うので、プレビューを有効化します。 fff

これでJava 14を使ったJavaアプリケーションをEclipseで開発・実行できるようになります。

Java 14の新機能を触ってみる

早速触ってみました。

JEP 305:Pattern Matching for instanceof (Preview)

まずはJEP 305のPattern Matching for instanceofです。 instanceof と同時に変数を定義できるようになりました。 実際の書き方の例は以下の通りです。 前半がこれまでの書き方、後半がPattern Matching for instanceofを使用した書き方になっています。

まずはこれまでの書き方。

public class NotPatternMatchingTest {
    public static void main(String... args) {
        patternMatch("literal");
        patternMatch(1);

    }

    private static void patternMatch(Object obj) {
        // これまでの書き方
        if (obj instanceof String) {
            String str = (String) obj;
            System.out.println("No Pattern Matching:" + str);
        } else if (obj instanceof Integer) {
            Integer inte = (Integer) obj;
            System.out.println("No Pattern Matching:" + inte);
        }
    }
}

これがPattern Matching for instanceof を使用した書き方。

public class PatternMatchingTest {
    public static void main(String... args) {
        patternMatch("literal");
        patternMatch(1);
    }

    // previewなのでSuppressWarningsでワーニング抑止
    @SuppressWarnings("preview")
    private static void patternMatch(Object obj) {
        // Pattern Matching for instanceof
        if (obj instanceof String str) {
            System.out.println("Pattern Matching:" + str);
        } else if (obj instanceof Integer inte) {
            System.out.println("Pattern Matching:" + inte);
        }
    }
}

switch文での使用はJava 15以降に持ち越しになっているようです。 http://openjdk.java.net/jeps/8213076

JEP 358:Helpful NullPointerExceptions

NullPointerExceptionが発生した場合のメッセージが詳細になり、原因を特定しやすくなりました。 -XX:+ShowCodeDetailsInExceptionMessagesオプションをつけて実行することで、詳細なメッセージを得ることができます。 以下のサンプルコードで実験してみました。

public class HelpfulNullPo {
    public static void main(String... args) {
        String str = null;
        str.length();
    }
}

-XX:+ShowCodeDetailsInExceptionMessagesオプションを付けずに実行した結果がこちら。

Exception in thread "main" java.lang.NullPointerException
    at test.HelpfulNullPo.main(HelpfulNullPo.java:6)

-XX:+ShowCodeDetailsInExceptionMessagesオプションをつけて実行した結果がこちら。

ggg

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
    at test.HelpfulNullPo.main(HelpfulNullPo.java:6)

NullPointerExceptionの原因特定がしやすくなっています。

なお、JShellの場合は-R-XX:+ShowCodeDetailsInExceptionMessagesという指定になります。

JEP 359:Records (Preview)

データ保持用のクラスとしてrecordという機能がpreviewとして入りました。 以下のように書くだけでデータ保持用のクラスを作ることができます。 (record Person(String name, int age) の部分)

@SuppressWarnings("preview")
record Person(String name, int age) {}

public class RecordTest {
    public static void main(String... args) {
        Person person = new Person("taumax", 13);
        System.out.println("name:" + person.name());
        System.out.println("age:" + person.age());
        System.out.println(person);
    }
}
name:taumax
age:13
Person[name=taumax, age=13]

インスタンス生成後に値を変更することはできないようです。 厳密には違いますが、イメージ的にはイミュータブルなJavaBeansを簡単に作ることができるようになったという感覚ですかね。

JEP 361:Switch Expressions (Standard)

Switch文がアロー->を使って書けるようになり、かなり読みやすくなりました。また、breakの記載も不要になっています。 Switch ExpressionsはJava 12でプレビューとして導入されたものですが、今回のJava 14で正式機能として導入されます。 実際の書き方の例は以下の通りです。 前半がこれまでの書き方、後半がSwitch Expressionsを使用した書き方になっています。

まずはこれまでのswitch文

public class OldSwitchExpressions {
    public static void main(String... args) {
        for (Week day : Week.values()) {
            oldSwitch1(day);
        }
    }

    // これまでのswitch文
    private static void oldSwitch1(Week day) {
        System.out.print("old:");
        switch (day) {
            case MONDAY, FRIDAY, SUNDAY:
                System.out.println(6);
                break;
            case TUESDAY:
                System.out.println(7);
                break;
            case THURSDAY, SATURDAY:
                System.out.println(8);
                break;
            case WEDNESDAY:
                System.out.println(9);
                break;
        }
    }

    private enum Week {
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
        THURSDAY, FRIDAY, SATURDAY
    }
}

これがSwitch Expressions

public class SwitchExpressions {
    public static void main(String... args) {
        for (Week day : Week.values()) {
            newSwitch1(day);
        }
    }

    // 新しいswitch文
    private static void newSwitch1(Week day) {
        System.out.print("new:");
        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);
        }
    }

    private enum Week {
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
        THURSDAY, FRIDAY, SATURDAY
    }
}

アロー->を使い、breakがなくなったことでかなり可読性が高くなったことがわかります。

また、switch文の実行結果をそのまま変数に代入することができるようになりました。 実際の書き方の例は以下の通りです。 前半がこれまでの書き方、後半がSwitch Expressionsを使用した書き方になっています。

public class OldSwitchExpressions2 {
    public static void main(String... args) {
        for (Week day : Week.values()) {
            oldSwitch2(day);
        }
    }

    // これまでのswitch文
    private static void oldSwitch2(Week day) {
        System.out.print("old:");
        int numLetters;
        switch (day) {
            case MONDAY, FRIDAY, SUNDAY:
                numLetters = 6;
                break;
            case TUESDAY:
                numLetters = 7;
                break;
            case THURSDAY, SATURDAY:
                numLetters = 8;
                break;
            case WEDNESDAY:
                numLetters = 9;
                break;
            default:
                throw new IllegalStateException("Wat: " + day);
        }
        System.out.println(numLetters);
    }

    private enum Week {
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
        THURSDAY, FRIDAY, SATURDAY
    }
}

これがSwitch Expressionsを使用した書き方。

public class SwitchExpressions2 {
    public static void main(String... args) {
        for (Week day : Week.values()) {
            newSwitch2(day);
        }
    }

    // 新しいswitch文
    private static void newSwitch2(Week day) {
        System.out.print("new:");
        int numLetters = switch (day) {
            case MONDAY, FRIDAY, SUNDAY -> 6;
            case TUESDAY                -> 7;
            case THURSDAY, SATURDAY     -> 8;
            case WEDNESDAY              -> 9;
        };
        System.out.println(numLetters);
    }

    private enum Week {
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
        THURSDAY, FRIDAY, SATURDAY
    }
}

これの効果は一目瞭然ですね。素らしい!

JEP 368:Text Blocks (Second Preview)

改行などを含んだ文字列を定義できるようになりました。 文字列を定義する場合の"ではなく"""で囲みます。 開始の"""のあとには文字列を続けることができません。

public class TextBlocks {
    @SuppressWarnings("preview")
    public static void main(String... args) {
        // これまでは改行をエスケープする必要があった。
        String str1 = "I have a pen.
"
                + "I don't have a pen.";
        System.out.println(str1);

        // エスケープしなくても改行してくれる。
        String str2 = """
                I have a pen.
                I don't have a pen.
                """;
        System.out.println(str2);

        // 改行したくない場合は「」を付ける。
        String str3 = """
                I have a pen.                I don't have a pen.                """;
        System.out.println(str3);

        // 文字列に変数を埋め込む場合
        String str4 = """
                Hello %s.
                """.formatted("taumax");
        System.out.println(str4);
    }
}

I have a pen.
I don't have a pen.

I have a pen.
I don't have a pen.


I have a pen.I don't have a pen.

Hello taumax.

以上。

参考