「Java 14の特徴」
6ヶ月サイクルの伝統を守るため、Java 13が2019年9月17日にリリースされた後、Java 14、もう1つの非LTSバージョンは2020年3月17日にリリース予定です。
Java 14の機能
以下にJava 14の機能のリストがあります。
- Switch Expressions (Standard) – JEP 361
- Pattern Matching for instanceof (Preview) – JEP 305
- Helpful NullPointerExceptions – JEP 358
- Records (Preview) – JEP 359
- Text Blocks (Second Preview) – JEP 368
- Packaging Tool (Incubator) – JEP 343
- NUMA-Aware Memory Allocation for G1 – JEP 345
- JFR Event Streaming – JEP 349
- Non-Volatile Mapped Byte Buffers – JEP 352
- ZGC on macOS – JEP 364
- ZGC on Windows – JEP 365
- Foreign-Memory Access API (Incubator) – JEP 370
マックOS上でのJava 14のインストール設定
- To get started with Java 14, download the JDK from here.
- Copy and extract the tar file in the /Library/Java/JavaVirtualMachines as shown below:
$ cd /Library/Java/JavaVirtualMachines
$ sudo cp ~/Downloads/openjdk-14_osx-x64_bin.tar.gz /Library/Java/JavaVirtualMachines
$ sudo tar xzf openjdk-14_osx-x64_bin.tar.gz
$ sudo rm openjdk-14_osx-x64_bin.tar.gz
それが終了したら、任意のテキストエディタを使用して bash_profile を開きます。私は vim ~/.bash_profile を使用しています。Java14のパスをJAVA_HOMEに設定し、変更を保存し、変更を反映するためにsource ~/.bash_profile を実行します。
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home
ついに、Java 14を使ったプログラムのコンパイルと実行準備が整いました。新しいJava 14の機能を迅速にテストするための対話型REPLコマンドラインツールであるJShellを使用します。
Java 14でリリースされた多くの機能はプレビュー版であることに注意することが重要です。つまり、現時点では完全に機能しているものの、将来的に変更される可能性があります。次のリリースサイクルでは、一部の機能が標準化されるか、単純に削除される可能性があります。プレビュー版の機能をテストするためには、以下に示すように、JShellやJavaプログラムを実行する際に明示的に `–enable-preview` を設定する必要があります。
jshell --enable-preview
javac --release 14 --enable-preview Author.java
次の数節では、言語とJVMのいくつかの機能について話し合いましょう。
おすすめの読み物: LinuxにJava 14をインストールする方法
1. スイッチ式の表現方法
直近の2つのリリースでプレビュー機能として提供されたスイッチ式は、ついにJava 14で正式な機能として追加されました。
- Java 12 introduced the lambda syntax for switch expressions thereby allowing multiple case labels for pattern matching as well as preventing fall-throughs which lead to verbose code. It also enforced exhaustive cases wherein a compilation error would be thrown if all the input cases aren’t covered.
- Java 13, the second preview introduced yield statements instead of break for returning values from an expression.
ついにJava 14では、これらの機能が標準となりました。
String result = switch (day) {
case "M", "W", "F" -> "MWF";
case "T", "TH", "S" -> "TTS";
default -> {
if(day.isEmpty())
yield "Please insert a valid day.";
else
yield "Looks like a Sunday.";
}
};
System.out.println(result);
注意:yieldはJavaで新しいキーワードではありません。それは単にswitch式で使用されます。
2. instanceofによるパターンマッチング(プレビュー)
Javaの開発者にコードベースを見せてもらえば、コード全体にはinstanceof条件をうまく活用した箇所が見られます。具体的には、instanceof条件のチェックの後には一般的に型キャストが続きます。
Java 14では、この冗長性を無くして、条件抽出をずっと簡潔にします。
Java 14以前:
if (obj instanceof Journaldev) {
Journaldev jd = (Journaldev) obj;
System.out.println(jd.getAuthor());
}
Java 14以降:
if (obj instanceof Journaldev jd) {
System.out.println(jd.getAuthor());
}
上記のコードでは、オブジェクトがJournaldevの型である場合にのみ、インスタンスjdが割り当てられます。変数のスコープは条件ブロックに限定されています。
3. 便利なNullPointerException
ヌルポインターエクセプションは、どんな開発者にとっても悪夢です。以前のJava 13までは、有名なNPEのデバッグが難しかったです。開発者は、スタックトレースに行番号しか表示されないため、他のデバッグツールを使うか、手動でヌルとなっている変数/メソッドを特定しなければなりませんでした。
Java 14以前では:
String name = jd.getBlog().getAuthor()
//Stacktrace
Exception in thread "main" java.lang.NullPointerException
at NullPointerExample.main(NullPointerExample.java:5)
以下に示すようなより詳細なスタック情報を提供する、Java 14で新たに導入されたJVMの新機能があります。
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Blog.getAuthor()" because the return value of "Journaldev.getBlog()" is null
at NullPointerExample.main(NullPointerExample.java:4)
上記の機能は言語の機能ではありません。それはランタイム環境の改良です。
4. レコード(プレビュー)
レコードは、純粋なデータを格納するデータクラスです。レコードを導入する目的は、冗長なコードのない、簡単で簡潔なクラスを迅速に作成することです。
通常、Javaのクラスではequals()、hashCode()、ゲッターとセッターのメソッドを実装する必要があります。一部のIDEは、そのようなクラスの自動生成をサポートしていますが、コードはまだ冗長です。recordを使用すると、次のようにクラスを簡単に定義するだけで済みます。
record Author(){}
//or
record Author (String name, String topic) {}
Javaコンパイラは、コンストラクタ、プライベートな最終フィールド、アクセッサ、equals/hashCode、およびtoStringメソッドを自動的に生成します。上記のクラスの自動生成されたゲッターメソッドは、name()とtopic()です。
javacを使用してプログラムをコンパイルした後、生成されたコードを調べるには、javap Authorを使用します。次のイラストは、レコードAuthor(String name、String topic){}の生成されたクラスを示しています。
レコードのセマンティクスは、Kotlinのデータクラスと似ています。
さらに、次のようにしてレコードに追加のフィールド、メソッド、およびコンストラクタを追加することもできます。
record Author (int id, String name, String topic) {
static int followers;
public static String followerCount() {
return "Followers are "+ followers;
}
public String description(){
return "Author "+ name + " writes on "+ topic;
}
public Author{
if (id < 0) {
throw new IllegalArgumentException( "id must be greater than 0.");
}
}
}
レコード内で定義された追加のコンストラクタは、コンパクトコンストラクタと呼ばれます。パラメータを持たず、カノニカルコンストラクタの拡張です。
コンパクトコンストラクタは、コンパイラによって別々のコンストラクタとして生成されません。代わりに、バリデーションケースで使用され、メインコンストラクタの開始時に呼び出されます。
レコードについて注意すべき重要な点はいくつかあります。
- A record can neither extend a class nor it can be extended by another class. It’s a final class.
- Records cannot be abstract
- Records cannot extend any other class and cannot define instance fields inside the body. Instance fields must be defined in the state description only
- Declared fields are private and final
- The body of a record allows static fields and methods
おすすめの読み物: Java Records
4.1) レコードの参照フィールド内の値は変更することができます。
オブジェクトとして定義されたフィールドに関しては、重要なことは、参照のみが変更不可能であるということです。内部の値は変更可能です。次の例では、ArrayListが変更されたときに値が変更されるレコードが示されています。ご覧のように、ArrayListが変更されるたびに値が変更されます。
4.2) レコードはインタフェースを実装することができます。
以下のコードは、レコードを使用したインターフェースの実装例を示しています。 (I will be providing a single option)
record Author(String name, String topic) implements Information {
public String getFullName() {
return "Author "+ name + " writes on " + topic;
}
}
interface Information {
String getFullName();
}
上記のコードを実行した結果は、JShellでの以下のような出力です。
4.3) レコードは複数のコンストラクタをサポートしています。
レコードは、以下のように、パラメータありまたはなしで複数のコンストラクタを宣言することができます。
record Author(String name, String topic) {
public Author() {
this("NA", "NA");
}
public Author(String name) {
this(name, "NA");
}
}
4.4) レコードによってアクセサメソッドの修正が可能になります。 (Rekōdo ni yotte akusesa mesoddo no shūsei ga kanō ni narimasu.)
データ定義に基づいてレコードが公開アクセサメソッドを生成するが、以下のように本体でアクセサメソッドを再定義することもできます。
record Author(String name, String topic) {
public String name() {
return "This article was written by " + this.name;
}
}
4.5) ランタイムでのレコードとその構成要素の確認
レコードは、isRecord()メソッドとgetRecordComponents()メソッドを提供しており、クラスがレコードかどうかを確認し、フィールドと型を調べることができます。以下の図は、その方法を示しています。
上記のコード例では、追加のフィールドとメソッドをレコードに追加しましたが、それを過度に行わないようにしてください。レコードは、単なるデータの運搬手段として設計されており、多くの追加メソッドを実装したい場合は、通常のクラスに戻る方が良いです。
5. テキストブロック(プレビュー)
テキストブロックは、Java 13のプレビュー機能として導入され、複数行の文字列リテラルの簡単な作成を可能にすることを目的としています。これにより、HTMLやJSON、SQLのクエリ文字列を簡単に作成するのに役立ちます。
Java 14では、テキストブロックはまだプレビューの状態ですが、いくつかの新しい機能が追加されています。以下のように使用することができます。
- Backslash for displaying nice-looking multiline string blocks.
- \s is used to consider trailing spaces which are by default ignored by the compiler. It preserves all the spaces present before it.
String text = """
Did you know \
Java 14 \
has the most features among\
all non-LTS versions so far\
""";
String text2 = """
line1
line2 \s
line3
""";
String text3 = "line1\nline2 \nline3\n"
//text2 and text3 are equal.
参考文献: OpenJDK 14