LoginSignup
180
168

More than 3 years have passed since last update.

【10分で分かる】Java8からJava15まで

Last updated at Posted at 2021-02-08

本記事は、Philipp Gysel氏による「From Java 8 to Java 15 in Ten Minutes」(2021年1月18日公開)の和訳を、著者の許可を得て掲載しているものです。

【10分で分かる】Java8からJava15まで

Image for post

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

Streams.java

map関数は、stream内のすべての要素に適用されるラムダを入力として受け取ります。

Streamは(変換を介して)ListSetMapで動作します。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.java

上の例では、乱数を作成し、それをOptionalオブジェクトでラップし、偶数の場合にのみ値を出力しています。

4. JShell (Java 9)

いよいよJavaのREPLJShellです!😊簡単に言うと、JShellを使えば、Javaの完全なクラスを書いてコンパイルしなくても、スニペットを試せます。1度に1つのコマンドを実行して、すぐに結果を見られます。簡単な例はこちら。

$ <JDK>/bin/jshell
jshell> System.out.println("hello world")
hello world

JShell.sh

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]

CollectionsOld.sh

これが次のように簡略化されました。

jshell> List<Integer> list = List.of(1, 2, 3, 4)
b ==> [1, 2, 3, 4]

CollectionsNew.sh

このしゃれたof(...)メソッドはListSetMapにあります。どれも、たった1行のシンプルなコードで不変オブジェクトを作成してくれます。

6. varによる型推論 (Java 10)

Java 10では、変数の型を省略できる新しいvarキーワードを導入しました。

jshell> var x = new HashSet<String>()
x ==> []

jshell> x.add("apple")
$1 ==> true

TypeInference.sh

上の例では、コンパイラによって 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");
    }
}

SingleSourceLaunch.java

これで、1ステップでコンパイルと実行ができるようになりました。

$ java ./Main.java
hello world

SingleSourceLaunch.sh

シンプルなスタータープログラムや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"

SwitchOld.sh

対照的に、新しいSwitch式は値を返します。

jshell> var i = 3;
jshell> var x = switch(i) {
    ...>    case 1 -> "one";
    ...>    case 2 -> "two";
    ...>    case 3 -> "three";
    ...>    default -> "unknown number";
    ...> };
x ==> "three"

SwitchNew.sh

この新しい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);
    }
}

MultiLineString.java

さて、単一ファイル起動でMainメソッドを実行してみましょう。

java --enable-preview --source 13 Main.java
{
    "recipe": "watermelon smoothie",
    "duration": "10 mins",
    "items": ["watermelon", "lemon", "parsley"]
}

MultiLineString.sh

結果として得られる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"

Record.sh

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

InstanceOfOld.java

残念な部分は、まず、objString型であることを確認してから、もう一度キャストして長さを取得するところです。

Java 14では、コンパイラがinstanceofチェック後に自動で型推論するようになりました。

Object obj = new String("hello");
if (obj instanceof String mystr) {
    System.out.println("String length: " + mystr.length());
}

InstanceOfNew.java

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

SealedClass.java

これがどのように役立つのでしょうか?Fruitが何個あるかわかりましたね。これは、完全にサポートされたパターンマッチングへの重要な一歩です。列挙型のようにクラスを扱うことができます。このsealed機能は、上で説明した新しいswitch式と相性が良いです。

おまけ:Java 8以降のライセンス条項の更新

この記事の最後の話題は、ライセンスです。OracleがJava 8(無料の商用版)のアップデートを停止したことを聞いたことがあると思います。そこで、次のような選択肢があります。

  • 新しいOracle JDKバージョンを使用する(Oracleは各リリース後6ヶ月間だけ無料のセキュリティアップデートを提供)。

  • 自己責任で古いJDKバージョンを使用する。

  • 古いOpenJDKのJavaバージョンを使用する。これは引き続き、オープンソースコミュニティやサードパーティベンダーからセキュリティアップデートを取得する。

  • プレミアムサポートのためOracleに支払う(例:Java 8は2030年までサポート)。

次は、JDKごとの暫定的なOracleサポート期間です。

Image for post

JDKごとのOracleサポート予定

Oracleの新しいライセンスモデルは、新しいリリースサイクルの影響を受けます。Oracleは6ヶ月ごとに新しいJavaバージョンを発表します。これにより、Oracleはより速いペースでJavaを改善し、実験的な機能を通じてより迅速なフィードバックを取得し、ScalaKotlinPythonなどの最新の言語に追いつくことができます。

ライセンスの詳細については、この記事を見てください。

まとめ

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でもご意見を受け付けております。
皆様のメッセージをお待ちしております。

180
168
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
180
168