Java Platform Standard Edition

Java言語更新

リリース12

F17330-01(原本部品番号:F13631-01)

2019年3月

Java SE 12のJava言語の変更

Java SE 12では、switch式に加え、フォール・スルーを防ぐ新しい種類のcaseラベルが導入されています。これらの機能はプレビュー機能として使用できます。

プレビュー機能

プレビュー機能とは、設計、仕様および実装は完了しているが、永続的でない新機能のことであり、将来のJDKリリースでは別の形式で存在するか、完全になくなる可能性があることを意味します。

メインラインのJDKリリースで機能をプレビュー機能として導入すると、可能なかぎり多くの開発者に、その機能を実際の環境で試用してフィードバックを提供してもらうことができます。また、ツール・ベンダーは、Java開発者がその機能を本番環境で使用する前に、機能のサポートを構築することができます。開発者のフィードバックは、その機能に設計ミスがあるかどうか、たとえば、ハード面での技術的エラー(タイプ・システムの欠陥など)、ソフト面での操作性の問題(従来の機能との意外な相互作用など)、または不適切なアーキテクチャの選択(将来の機能の方向性を妨げるような選択)などを確認する上で役立ちます。このフィードバックを通じて機能の長所と短所が評価され、その機能がJava SE Platformで長期的な役割を担うかどうか、担う場合は調整が必要かどうかを判断します。その結果、機能は、(調整あり、または調整なしで)最終かつ永続的なステータスが付与されるか、(調整あり、または調整なしで)プレビュー期間をさらに継続するか、あるいは削除されます。

すべてのプレビュー機能はJDK Enhancement Proposal (JEP)に記載され、そこでは機能の範囲の定義と設計の概略が説明されています。たとえば、JEP 325はプレビュー機能のSwitch式について説明しています。プレビュー機能の役割とライフサイクルの背景情報は、JEP 12を参照してください。

プレビュー機能の使用

現在のプログラムでプレビュー言語機能を使用するには、その機能をコンパイラとランタイム・システムで明示的に有効化する必要があります。そうしないと、コードでプレビュー機能が使用されていることと、プレビュー機能はデフォルトで無効になっていることを通知するエラー・メッセージが表示されます。

JDKリリースnのプレビュー機能を使用するソース・コードをjavacでコンパイルするには、--enable-previewコマンド行オプションを--release nまたは-source nコマンド行オプションと組み合せて指定して、JDKリリースnjavacを実行します。

たとえば、MyApp.javaという名前のアプリケーションで、JDK 12のプレビュー言語機能であるswitch式を使用すると仮定します。これを、次のようにJDK 12でコンパイルします。

javac --enable-preview --release 12 MyApp.java

注意:

プレビュー機能を使用するアプリケーションをコンパイルすると、次のような警告メッセージが表示されます。

Note: MyApp.java uses preview language features.
Note: Recompile with -Xlint:preview for details

プレビュー機能は変更される可能性があり、その目的はフィードバックの獲得であることに注意してください。

JDKリリースnのプレビュー機能を使用するアプリケーションを実行するには、--enable-previewオプションを指定して、JDKリリースnjavaを使用します。先の例に続けて、MyAppを実行するには、次のようにJDK 12のjavaを実行します。

java --enable-preview MyApp

注意:

旧リリースのJava SE Platformのプレビュー機能を使用するコードは、必ずしも新しいリリースでコンパイルまたは実行する必要はありません。

jshellおよびjavadocツールも--enable-previewコマンド行オプションをサポートしています。

フィードバックの送信

プレビュー機能のフィードバックやJava SE Platformに関するその他の意見は、次のようにして提供できます。

  • バグを見つけたら、その内容をJava Bug Databaseに送信します。
  • プレビュー機能の操作性に関する重要なフィードバックを提供する場合は、その機能が議論されているOpenJDKのメーリング・リストに投稿します。特定の機能のメーリング・リストを見つけるには、その機能のJEPページを確認して、ラベル「Discussion」を探します。たとえば、ページ『JEP 325: Switch Expressions (Preview)』には、ページの先頭付近に「Discussion amber dash dev at openjdk dot java dot net」と表示されています。
  • オープン・ソース・プロジェクトの場合は、OpenJDK Wikiの「Quality Outreach」を参照してください。

Switch式

Java SE 12ではswitch式が導入されており、この式は(すべての式と同様に)単一の値として評価され、文で使用することができます。また、Java SE 12では新しい種類のcaseラベルも導入され、これによりフォール・スルーを防ぐためのbreak文は必要なくなりました。

注意:

これは、設計、仕様および実装は完了しているが、永続的でないプレビュー機能であり、将来のJDKリリースでは別の形式で存在するか、完全になくなる可能性があることを意味します。プレビュー機能が含まれているコードをコンパイルして実行するには、追加のコマンド行オプションを指定する必要があります。「プレビュー機能」を参照してください。switch式の設計に関する背景情報は、JEP 325を参照してください。

曜日の文字数を出力する次のswitch文について検討してみます。

public enum Day { SUNDAY, MONDAY, TUESDAY,
    WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; }

// ...

    int numLetters = 0;
    Day day = Day.WEDNESDAY;
    switch (day) {
        case MONDAY:
        case FRIDAY:
        case SUNDAY:
            numLetters = 6;
            break;
        case TUESDAY:
            numLetters = 7;
            break;
        case THURSDAY:
        case SATURDAY:
            numLetters = 8;
            break;
        case WEDNESDAY:
            numLetters = 9;
            break;
        default:
            throw new IllegalStateException("Invalid day: " + day);
    }
    System.out.println(numLetters);

曜日名の長さは、変数numLettersに格納するかわりに値を戻せた方が便利で、これはswitch式を使用して行うことができます。また、フォール・スルーを防ぐのに、記述が面倒で付け忘れがちなbreak文が必要がなくなれば、さらに便利です。これは、新しい種類のcaseラベルで実現できます。次のswitch式では、新しい種類のcaseラベルを使用して、曜日の文字数を出力します。

    Day day = Day.WEDNESDAY;    
    System.out.println(
        switch (day) {
            case MONDAY, FRIDAY, SUNDAY -> 6;
            case TUESDAY                -> 7;
            case THURSDAY, SATURDAY     -> 8;
            case WEDNESDAY              -> 9;
            default -> throw new IllegalStateException("Invalid day: " + day);
        }
    );    

新しい種類のcaseラベルの形式は次のとおりです。

case label_1, label_2, ..., label_n -> expression;|throw-statement;|block 

Javaランタイムが矢印の左側にある任意のラベルに一致すると、矢印の右側にあるコードが実行されて、フォール・スルーしません。つまり、switch式(または文)内の他のコードは実行されません。矢印の右側のコードが式である場合、その式の値はswitch式の値になります。

新しい種類のcaseラベルをswitch文で使用できます。次の例は最初の例と同様ですが、「コロンcase」ラベルのかわりに「矢印case」ラベルが使用されています。

    int numLetters = 0;
    Day day = Day.WEDNESDAY;
    switch (day) {
        case MONDAY, FRIDAY, SUNDAY -> numLetters = 6;
        case TUESDAY                -> numLetters = 7;
        case THURSDAY, SATURDAY     -> numLetters = 8;
        case WEDNESDAY              -> numLetters = 9;
        default -> throw new IllegalStateException("Invalid day: " + day);
    };
    System.out.println(numLetters);

「コロンcase」ラベルは、次のようにswitch式で使用できます。

    int numLetters = switch (day) {
        case MONDAY:
        case FRIDAY:
        case SUNDAY:
            System.out.println(6);
            break 6;
        case TUESDAY:
            System.out.println(7);
            break 7;
        case THURSDAY:
        case SATURDAY:
            System.out.println(8);
            break 8;
        case WEDNESDAY:
            System.out.println(9);
            break 9;
        default:
            throw new IllegalStateException("Invalid day: " + day);
    };

Java SE 12ではbreak文が拡張されて、引数(caseラベルがswitch式で生成する値)を取れるようになっています。

注意:

「矢印case」ラベルの使用をお薦めします。「コロンcase」ラベルの使用時は、break文の挿入を忘れがちです。これを忘れると、コード内で思いがけないフォール・スルーが発生する場合があります。

「矢印case」ラベルで、複数の文または式でないコード、あるいはthrow文を指定するには、それらをブロック内に囲みます。caseラベルが生成する値をbreak文で指定します。

    int numLetters = switch (day) {
        case MONDAY, FRIDAY, SUNDAY -> {
            System.out.println(6);
            break 6;
        }
        case TUESDAY -> {
            System.out.println(7);
            break 7;
        }
        case THURSDAY, SATURDAY -> {
            System.out.println(8);
            break 8;
        }
        case WEDNESDAY -> {
            System.out.println(9);
            break 9;
        }
        default -> {
            throw new IllegalStateException("Invalid day: " + day);
        }
    };  

Java SE 11のJava言語の変更

Java SE 11では、暗黙的に型指定されるラムダ式の仮パラメータをvar識別子で宣言できます(「ローカル変数の型推論」を参照)。

Java SE 10のJava言語の変更

Java SE 10では、コンテキストからローカル変数の型を推論するためのサポートが導入され、これにより、コードの可読性が向上し、必要なボイラープレート・コードの量が削減されます。

ローカル変数の型推論

JDK 10以降では、nullでない初期化子を持つローカル変数をvar識別子で宣言できるため、読みやすいコードを記述できます。

次に、冗長で読みにくいコードの例を示します。

URL url = new URL("http://www.oracle.com/"); 
URLConnection conn = url.openConnection(); 
Reader reader = new BufferedReader(
    new InputStreamReader(conn.getInputStream()));

この例は、var識別子でローカル変数を宣言することにより、次のように書き直すことができます。変数の型はコンテキストから推論されます。

var url = new URL("http://www.oracle.com/"); 
var conn = url.openConnection(); 
var reader = new BufferedReader(
    new InputStreamReader(conn.getInputStream()));

varはキーワードではなく予約された型名であるため、変数、メソッドまたはパッケージ名としてvarを使用する既存のコードは影響を受けません。ただし、クラス名またはインタフェース名としてvarを使用するコードは影響を受けるため、クラスやインタフェースの名前を変更することが必要となります。

varは次のタイプの変数に使用できます。

  • 初期化子を伴うローカル変数宣言:

    var list = new ArrayList<String>();    // infers ArrayList<String>
    var stream = list.stream();            // infers Stream<String>
    var path = Paths.get(fileName);        // infers Path
    var bytes = Files.readAllBytes(path);  // infers bytes[]
    
  • 拡張forループのインデックス:

    List<String> myList = Arrays.asList("a", "b", "c");
    for (var element : myList) {...}  // infers String
  • 従来のforループで宣言されるインデックス変数:

    for (var counter = 0; counter < 10; counter++)  {...}   // infers int
  • try-with-resources変数:

    try (var input = 
         new FileInputStream("validation.txt")) {...}   // infers FileInputStream
    
  • 暗黙的に型指定されるラムダ式の仮パラメータの宣言: 仮パラメータが推論型のラムダ式は、暗黙的に型指定されます

    BiFunction<Integer, Integer, Integer> = (a, b) -> a + b;

    JDK 11以降では、暗黙的に型指定されるラムダ式の各仮パラメータをvar識別子で宣言できます。

    (var a, var b) -> a + b;

    その結果、暗黙的に型指定されるラムダ式の仮パラメータ宣言の構文は、ローカル変数宣言の構文と一致します。暗黙的に型指定されるラムダ式の各仮パラメータにvar識別子を適用する場合、その結果はvarをまったく使用しない場合と同じになります。

    推論される仮パラメータとvarで宣言される仮パラメータを暗黙的に型指定されるラムダ式内で混在させたり、varで宣言される仮パラメータとマニフェスト型を明示的に型指定されるラムダ式内で混在させることはできません。次の例は使用できません。

    (var x, y) -> x.process(y)      // Cannot mix var and inferred formal parameters
                                    // in implicitly typed lambda expressions
    (var x, int y) -> x.process(y)  // Cannot mix var and manifest types
                                    // in explicitly typed lambda expressions

ローカル変数の型推論のスタイル・ガイドライン

ローカル変数宣言は、冗長な情報を排除することによって、コードの可読性を向上させることができます。ただし、有用な情報が省略されて、コードがわかりにくくなる可能性もあります。したがって、この機能はよく考えて使用してください。使用の可否に関する厳格なルールはありません。

ローカル変数宣言は単独で存在しているのではありません。周囲のコードによってvar宣言の効果が影響を受けたり、無効化される可能性があります。『Style Guidelines for Local Variable Type Inference in Java』では、周囲のコードがvar宣言に与える影響について検討し、明示的型宣言と暗黙的型宣言のトレードオフについて説明し、var宣言の効果的な使用に関するガイドラインが示されています。

Java SE 9のJava言語の変更

Java Platform, Standard Edition (Java SE) 9の大きな変更点は、Java Platformモジュール・システムの導入です。

Java Platformモジュール・システムでは、モジュールという新しい種類のJavaプログラミング・コンポーネントが導入されています。モジュールは名前付きで自己記述型のコードとデータのコレクションです。タイプ(Javaのクラスとインタフェース)を含むパッケージのセットとしてコードが編成されており、リソースおよび他の種類の静的情報がデータに含まれます。モジュールはパッケージをエクスポートまたはカプセル化でき、他のモジュールに対する依存関係を明示的に表現できます。

Java Platformモジュール・システムの詳細は、OpenJDKのProject Jigsawに関する項を参照してください。

新しいモジュール・システム以外にも、いくつかの変更がJava言語に加えられました。このガイドの残りの部分では、これらの変更について説明します。

さらに簡潔になったtry-with-resources文

finalとしてのリソースがすでにあるか、実質的にfinalの変数がある場合、新しい変数を宣言せずにその変数をtry-with-resources文で使用できます。「事実上final」の変数とは、初期化された後に値が変更されることがない変数のことです。

たとえば、次の2つのリソースを宣言したとします。

        // A final resource
        final Resource resource1 = new Resource("resource1");
        // An effectively final resource
        Resource resource2 = new Resource("resource2");

Java SE 7または8では、次のように新しい変数を宣言します。

        try (Resource r1 = resource1;
             Resource r2 = resource2) {
            ...
        }

Java SE 9では、r1およびr2を宣言する必要はありません。

// New and improved try-with-resources statement in Java SE 9
        try (resource1;
             resource2) {
            ...
        }

the try-with-resources文の詳細な説明は、Javaチュートリアル(Java SE 8以前)を参照してください。

Java SE 9の言語の軽微な変更

Java SE 9には、言語の軽微な変更がいくつかあります。

@SafeVarargsの注釈がプライベート・インスタンスのメソッドで許可されます。

@SafeVarargsの注釈は、オーバーライドできないメソッドのみに適用できます。これらには、静的メソッド、finalインスタンスのメソッド、およびプライベート・インスタンスのメソッド(Java SE 9の新機能)が含まれます。

匿名内部クラスと一緒にダイアモンド構文(山カッコが含まれた構文)を使用できます。

Javaプログラムで記述できる型(intStringなど)は型指定型と呼ばれます。Javaプログラムに記述できないコンパイラ内部の型は非型指定型と呼ばれます。

非型指定型は、ダイアモンド演算子で使用される推論の結果として発生する場合があります。匿名クラスのコンストラクタを指定したダイアモンドを使用する推論型はクラス・ファイルの署名属性の型セット以外になる可能性があるため、匿名クラスが指定されたダイアモンドの使用はJava SE 7では許可されていませんでした。

Java SE 9では、推論型が型指定であるかぎり、匿名内部クラスを作成する際にダイアモンド演算子を使用できます。

アンダースコア文字は有効な名前ではありません。

アンダースコア文字("_")を識別子として使用すると、ソース・コードをコンパイルできなくなります。

プライベート・インタフェースのメソッドがサポートされます。

プライベート・インタフェースのメソッドがサポートされます。このサポートにより、インタフェースの非抽象メソッド間でコードを共有できるようになります。

ドキュメントのアクセシビリティについて

Oracleのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracleサポートへのアクセス

サポートを購入したオラクル社のお客様は、My Oracle Supportを介して電子的なサポートにアクセスできます。詳細情報はhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=infoか、聴覚に障害のあるお客様はhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=trsを参照してください。


Java Platform, Standard Edition Java言語更新, リリース12

F17330-01

Copyright © 2017, 2019, Oracle and/or its affiliates. All rights reserved.

Java SE 9と後続のリリースで更新された言語機能について説明します。

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、このソフトウェアまたはハードウェアを安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。