Java5～Java23で気になった変更点

20年前のJ-POPをまだ最近の曲だと思うぐらい、最近のJavaを詳細に追うことができていなかったので、変更内容を項目だけでもピックアップし、私なりに整理しました。

私が気になったもののみをピックアップしています。プレビューでの導入は除外し、正式導入されたもののみを対象にしています。

# Java 5 (2004年)

大きな変更。Javaのバージョン番号の付け方が変わり、今までのバージョンでいう1.5相当。

- Generics (総称型)
- Enhanced for Loop (拡張for)
- Autoboxing
- enum (列挙型)
    - switch文でのenumの利用
- varargs (可変長引数)
- annoations: `@Override`, `@Deprecated`, `@SuppressWarnings`
- Covariant return type (共変戻り値型; オーバーライドの際に戻り値をサブクラスにできるようになった)
- `StringBuilder` (`StringBuffer`の非スレッドセーフ版)
- `String.format()`
- static import (staticなメソッドやフィールドをクラス名なしに参照できる)
- 十六進浮動小数点リテラル

# Java 6 (2006年)

- インターフェースを実装したメソッドに対しても `@Override` を使えるようになった
- chmod

# Java 7 (2011年)

- switch文に文字列型を使えるようになった
- Catching Multiple Exception Types (こういうの: `catch (IOException | SQLException e)`)
    - Safe Rethrow
- try-with-resources
    - `AutoCloseable`
    - `Throwable#addSuppressed()`
- 二進数リテラル (`0b0101` みたいな)
- 数値リテラルの中にアンダースコアが使えるようになった
- diamond operator (`<>`)
- `Objects`クラス

# Java 8 LTS (2014年)

ラムダ式の導入など大きな変更。

- static methods in interfaces
- interface default methods (インターフェースにメソッドを実装できるようになった。インターフェースがScalaのtraitに似てきている気がする)
- functional interfaces and lambda expressions (メソッド宣言が1つのみのインターフェースを関数型インターフェースと呼ぶようになった。関数型インターフェースを実装する無名クラスのインスタンスとしてラムダ式の記法が使えるようになった。ラムダ式は `() -> {}` のように書く)
- effectively final (finalをつけなくても、実質的にfinalな変数を推定してくれ、内側のラムダからアクセスできる)
- メソッド参照 (クラス名::メソッド名、クラス名::new、インスタンス変数名::メソッド名)
- explicit receiver parameters
- `Optional`クラス (Scalaの`Option`相当)
- `java.util.stream.Stream`インターフェース (Scalaの`TraversableOnce`相当。ラムダ式と合わせてメソッドチェーンで処理が書けるようになる)
- `java.io.UncheckedIOException`クラス
- `java.time`パッケージ

# Java 9 (2017年)

このバージョンから半年サイクルでのバージョンアップとなる。高頻度となる代わりに変更内容は少なくなる。

- module-info.java (Project Jigsaw)
- private methods in interfaces
- try-with-resources with effectively final variables (finalまたは実質finalな宣言済みの変数をtryの中で指定できるようになった)
- `_` という1文字の変数名が禁止になった (Java 22で導入される無名変数の布石か)
- Compact Strings (ISO-8859-1/Latin-1に収まる文字列に限り、JVM内部での文字列の保持がUTF-16からISO-8859-1/Latin-1に変更。メモリ効率が改善)

# Java 10 (2018年)

- var (ローカル変数の型推論)
- 単一ソースコードの場合に `java Hello.java` のようなコマンドで直接実行できるようになった

# Java 11 LTS (2018年)

- ラムダ式の引数にvarを使えるようになった

Java 12 (2019年)

- 特記事項なし

Java 13 (2019年)

- 特記事項なし

# Java 14 (2020年)

- switch式 (Scalaのmatch式に相当)
    - yield
    - アロー構文
- caseにコンマ区切りで複数の値を指定できるようになった

# Java 15 (2020年)

- テキストブロック (Pythonのトリプルクォートに相当だが、インデントをいい具合に直してくれる。変数展開はできない)

# Java 16 (2021年)

- record (Scalaのcase class相当。Java 21のPattern Matching導入準備に見える)
- Pattern Matching for instanceof (`if (x instanceof T t)` みたいな書き方ができるようになった)
- 内部クラスにstaticフィールドやstaticメソッドを定義できるようになった (いままでできなかったのか)

# Java 17 LTS (2021年)

- sealed class (Scalaのsealed class相当。Java 21のPattern Matching導入準備に見える)
    - permits
    - non-sealed class

# Java 18 (2022年)

- デフォルトの文字エンコーディングがUTF-8になった (いままではOS依存だった)

Java 19 (2022年)

- 特記事項なし

Java 20 (2023年)

- 特記事項なし

# Java 21 LTS (2023年)

パターンマッチングを中心とする大きな変更。

- Pattern Matching for switch (全体的にScalaのmatch式っぽくなってきた)
    - caseに型を指定できるようになった
    - sealed classの網羅性チェックが入った (Java 17のsealedがここに生きてくる)
    - nullが使えるようになった
    - Record Patterns (Java 16のrecordがここで生きてくる)
    - guards (`case ... when ...` の書き方ができるようになった)
    - `case default` の書き方ができるようになった
- Record Patterns (`if (x instanceof Point(var x, var y))` みたいな書き方ができるようになった)
- Virtual Threads

# Java 22 (2024年)

- `_` という1文字の変数名が無名変数として使えるようになった
    - Record Patterns、for文、catch句、ラムダ式の引数にも使える (Scalaみたいになった)
- 複数ソースコードの場合でも `java Hello.java` のようなコマンドで直接実行できるようになった

# Java 23 (2024年)

- MarkdownでのJavadoc (コメントを書きやすくなった)

---

Java 5の総称型、8のラムダ式、10のvar、21のPattern Matching、23のMarkdownでのJavadocは、特に大きな機能強化ですね。