本記事は、Philipp Gysel氏による「From Java 8 to Java 15 in Ten Minutes」(2021年1月18日公開)の和訳を、著者の許可を得て掲載しているものです。
#【10分で分かる】Java8からJava15まで
Java 8からJava 15までの道のりには、朗報がたくさんだ。
##はじめに
この記事ではJava 7以降に追加された素晴らしい新機能を紹介します。2020年秋にリリースされたJava 15まで、Javaのバージョン毎に大きな改善点を見ていきます。Javaは今や、ラムダ式、関数型プログラミング、var
による型推論、単純なコンストラクタによる不変コレクション、複数行文字列を、完全にサポートするようになりました。さらに、データクラス(record
)やsealed
クラスなど、新しくて面白い実験的な機能があります。そして、時間対効果の高いJava REPLについて説明します。
##1. 関数型プログラミング (Java 8)
Java 8は、関数型プログラミングとラムダ式を言語機能として追加しました。関数型プログラミングの2つのコアパラダイムは、不変の値と関数の重要性向上です。データは変換処理のパイプラインを通過します。各ステップで入力を受け取り、それを新しい出力にマッピングします。関数型プログラミングは、以下に示すように、JavaのStream
とnull安全モナド(Optional
)で使えます。
##2. Streams (Java 8)
一般的なコンピュータプログラムでは、値のリストを操作して、各値に対して所定の変換を実行することがよくあります。Java 8以前は、この変換にfor
ループを使う必要がありましたが、これからは次のようにStreamを使えます。
Stream.of("hello", "great")
.map(s -> s + " world")
.forEach(System.out::println);
> hello world
> great world
map
関数は、stream内のすべての要素に適用されるラムダを入力として受け取ります。
Stream
は(変換を介して)List
、Set
、Map
で動作します。Streamのおかげで、コードのループをほとんどなくせます!👌
##3. Optional (Java 8)
Javaでよくあるもう1つの問題は、Nullポインタ例外でした。そこで JavaはOptionalを導入しました。これは、Nullの場合もNullでない場合も、参照をラップするモナドです。Optionalにアップデートするには、関数の形を使います。
Optional.of(new Random().nextInt(10))
.filter(i -> i % 2 == 0)
.map(i -> "number is even: " + i)
.ifPresent(System.out::println);
> number is even: 6
上の例では、乱数を作成し、それをOptionalオブジェクトでラップし、偶数の場合にのみ値を出力しています。
##4. JShell (Java 9)
いよいよJavaのREPL、JShellです!😊簡単に言うと、JShellを使えば、Javaの完全なクラスを書いてコンパイルしなくても、スニペットを試せます。1度に1つのコマンドを実行して、すぐに結果を見られます。簡単な例はこちら。
$ <JDK>/bin/jshell
jshell> System.out.println("hello world")
hello world
JavaScriptやPythonのようなインタプリタ型言語に精通している人は、長い間REPLを楽しんできましたが、Javaには今までこの機能がありませんでした。JShellでは変数だけでなく、複数行の関数、クラス、ループの実行など、より複雑なエンティティも定義できます。さらに、オートコンプリートもサポートしており、所定のJavaクラスが提供する正確なメソッドを知らない場合に便利です。
##5. 不変コレクションのファクトリメソッド (Java 9)
List
の単純な初期化は、Javaでは長い間欠落していましたが、そんな時代は終わりました。😅以前はこんなことをしなければなりませんでした。
jshell> List<Integer> list = Arrays.asList(1, 2, 3, 4)
list ==> [1, 2, 3, 4]
これが次のように簡略化されました。
jshell> List<Integer> list = List.of(1, 2, 3, 4)
b ==> [1, 2, 3, 4]
このしゃれたof(...)
メソッドはList、Set、Mapにあります。どれも、たった1行のシンプルなコードで不変オブジェクトを作成してくれます。
##6. var
による型推論 (Java 10)
Java 10では、変数の型を省略できる新しいvarキーワードを導入しました。
jshell> var x = new HashSet<String>()
x ==> []
jshell> x.add("apple")
$1 ==> true
上の例では、コンパイラによって x
の型が HashSet と推測できます。
この機能は、ボイラープレートコードを減らし、可読性を向上させるのに便利です。でも、いくつかの制限があります。var
はメソッド本体の中でしか使用できません。コンパイラはコンパイル時に型を推測するため、すべて静的に型付けされています。
##7. 単一ソースファイルの起動 (Java 11)
以前は、ファイルが1つのシンプルなJavaプログラムを書いたら、まずそのファイルをjavac
でコンパイルしてからjava
で実行しなければなりませんでした。Java 11では、1つのコマンドで両方のステップを実行できます。
まず、単一ソースファイルMain.java
を定義します。
public class Main {
public static void main(String[] args) {
System.out.println("hello world");
}
}
これで、1ステップでコンパイルと実行ができるようになりました。
$ java ./Main.java
hello world
シンプルなスタータープログラムや1つのJavaクラスだけのテストの場合、この機能で単一ソースファイルを起動する作業がもっと楽になります。
##8. Switch式 (Java 12)
Java 12では、Switch式が登場しました。ここでは、この式が古いswitch文とどう違うかを簡単に紹介します。
古いswitch文はプログラムの流れを定義します。
jshell> var i = 3
jshell> String s;
jshell> switch(i) {
...> case 1: s = "one"; break;
...> case 2: s = "two"; break;
...> case 3: s = "three"; break;
...> default: s = "unknown number";
...> }
jshell> s
s ==> "three"
対照的に、新しいSwitch式は値を返します。
jshell> var i = 3;
jshell> var x = switch(i) {
...> case 1 -> "one";
...> case 2 -> "two";
...> case 3 -> "three";
...> default -> "unknown number";
...> };
x ==> "three"
この新しいswitch式は一種のマッピング関数であることに注目してください。1つの入力(ここではi
)と1つの出力(ここではx
)があります。これは実はパターンマッチング機能であり、Javaを関数型プログラミングの原則とより互換性のあるものにするのに便利です。同様のswitch文はしばらくScalaでも使えました。
注意すべき点がいくつかあります。
-
コロンの代わりに、矢印
->
を使っています。 -
break
は必要ありません。 -
考え得るすべてのcaseを考慮すれば、defaultは省略できます。
-
Java 12でこの機能を有効にするには、
--enable-preview -source 12
を使用します。
##9. 複数行文字列 (Java 13)
JSONやXMLのような長い複数行文字列を定義したことはありますか?これまでは、すべてを1行にまとめて改行文字\n
を使うことが多かったと思いますが、これでは文字列が読みにくくなってしまいます。Java 13では複数行文字列が使えるようになりました!💪
例:
public class Main {
public static void main(String [] args) {
var s = """
{
"recipe": "watermelon smoothie",
"duration": "10 mins",
"items": ["watermelon", "lemon", "parsley"]
}""";
System.out.println(s);
}
}
さて、単一ファイル起動でMainメソッドを実行してみましょう。
java --enable-preview --source 13 Main.java
{
"recipe": "watermelon smoothie",
"duration": "10 mins",
"items": ["watermelon", "lemon", "parsley"]
}
結果として得られるStringは複数行にまたがり、引用符""
はそのままで、タブ\t
も保持しています!
##10. データクラスrecord
(Java 14)
この記事の新機能すべての中で、私が最も興奮しているのはたぶんこれです。ついにJavaにデータクラスが登場しました!このクラスはrecordキーワードで宣言され、自動Getter、コンストラクタ、equalsメソッドなどがあります。要するに、膨大なボイラープレートコードの塊を取り除くことができるのです!🙌🎉
jshell> record Employee (String name, int age, String department) {}
| created record Employee
jshell> var x = new Employee("Anne", 25, "Legal");
x ==> Employee[name=Anne, age=25, department=Legal]
jshell> x.name()
$2 ==> "Anne"
Scalaには同様のケースクラス、Kotlinにはデータクラスがあります。Javaでは多くの開発者が、Java 14のrecord
に影響を与えた機能のほとんどを提供するLombokを使っていました。詳細についてはBaeldungの記事を見てください。
##11. キャストなしinstanceof
(Java 14)
instanceof
キーワードは、すでにJava の以前のバージョンでありました。
Object obj = new String("hello");
if (obj instanceof String) {
System.out.println("String length: " + ((String)obj).length());
}
残念な部分は、まず、obj
がString
型であることを確認してから、もう一度キャストして長さを取得するところです。
Java 14では、コンパイラがinstanceofチェック後に自動で型推論するようになりました。
Object obj = new String("hello");
if (obj instanceof String mystr) {
System.out.println("String length: " + mystr.length());
}
##12. Sealedクラス (Java 15)
sealed キーワードで、所定のクラスやインターフェイスを拡張できるクラスを制限できます。
例:
public sealed interface Fruit permits Apple, Pear {
String getName();
}
public final class Apple implements Fruit {
public String getName() { return "Apple"; }
}
public final class Pear implements Fruit {
public String getName() { return "Pear"; }
}
これがどのように役立つのでしょうか?Fruit
が何個あるかわかりましたね。これは、完全にサポートされたパターンマッチングへの重要な一歩です。列挙型のようにクラスを扱うことができます。このsealed
機能は、上で説明した新しいswitch
式と相性が良いです。
##おまけ:Java 8以降のライセンス条項の更新
この記事の最後の話題は、ライセンスです。OracleがJava 8(無料の商用版)のアップデートを停止したことを聞いたことがあると思います。そこで、次のような選択肢があります。
-
新しいOracle JDKバージョンを使用する(Oracleは各リリース後6ヶ月間だけ無料のセキュリティアップデートを提供)。
-
自己責任で古いJDKバージョンを使用する。
-
古いOpenJDKのJavaバージョンを使用する。これは引き続き、オープンソースコミュニティやサードパーティベンダーからセキュリティアップデートを取得する。
-
プレミアムサポートのためOracleに支払う(例:Java 8は2030年までサポート)。
次は、JDKごとの暫定的なOracleサポート期間です。
JDKごとのOracleサポート予定
Oracleの新しいライセンスモデルは、新しいリリースサイクルの影響を受けます。Oracleは6ヶ月ごとに新しいJavaバージョンを発表します。これにより、Oracleはより速いペースでJavaを改善し、実験的な機能を通じてより迅速なフィードバックを取得し、Scala、Kotlin、Pythonなどの最新の言語に追いつくことができます。
ライセンスの詳細については、この記事を見てください。
##まとめ
Javaはこの6年間で長い道のりを歩んできて、新しいJavaリリースが8つありました!🚀この素晴らしい新機能はすべて、他のJVMベースのライバル(ScalaやKotlin)と比べて、Javaを競争力のあるオプションにするのに役立ちます。
この記事を書くのはとても楽しかったです🔥 読んでくれてありがとう😊最近のJavaリリースでお気に入りの機能は何ですか?感想を待っています!
DEV.toで初公開。
##翻訳協力
この記事は以下の方々のご協力により公開する事ができました。改めて感謝致します。
Original Author: Philipp Gysel
Original Article: From Java 8 to Java 15 in Ten Minutes
Thank you for letting us share your knowledge!
選定担当: @gracen
翻訳担当: @gracen
監査担当: -
公開担当: @gracen
##ご意見・ご感想をお待ちしております
今回の記事はいかがでしたか?
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に
コメント欄にてご投稿ください。Twitterでもご意見を受け付けております。
皆様のメッセージをお待ちしております。