はじめに
こんにちは、もんすんです。
前回のJava9→10編では var(ローカル変数型推論)をメインに取り上げました。「この回、var だけで終わった……」と感じた方、正解です。Java10はそういうリリースです。
今回は Java10→11編です!
Java11はLTS(Long-Term Support)、つまり長期サポートバージョンです。
機能もそれ相応に増えています。ひとつひとつ見ていきましょう。
対象読者
- Java9→10編を読んだ方(または
varを知っている方) - Java11の新機能を手を動かして確認したい方
そもそもLTSとは?
Java9以降、Javaは6ヶ月ごとにリリースされるようになりました。機能を小刻みに出すためです。ただし、すべてのバージョンが長期サポートされるわけではありません。
LTS(Long-Term Support)バージョンは、一定期間(数年単位)セキュリティパッチやバグ修正が提供されるバージョンです。
| バージョン | LTS | 主なLTSリリース間隔 |
|---|---|---|
| Java 8 | ✅ LTS | (旧来の長期サポート) |
| Java 9 | ❌ 短命 | ← 6ヶ月で終了 |
| Java 10 | ❌ 短命 | ← 6ヶ月で終了 |
| Java 11 | ✅ LTS | ← ここが次の長期サポート |
| Java 12〜16 | ❌ 短命 | |
| Java 17 | ✅ LTS | |
| Java 18〜20 | ❌ 短命 | |
| Java 21 | ✅ LTS |
実務では「LTSで止める」のが基本戦略です。「Java12にしたけど半年でサポート切れた」という事態を避けるためです。
Java10からJava11へのレベルアップ
1. 文字列メソッドの大幅強化
地味に見えて、毎日使うと効いてくる変化です。
isBlank() — 空白チェックが Unicode 対応に
// Java10以前の空白チェック
" ".isEmpty(); // false(半角スペースは空じゃない)
" ".trim().isEmpty(); // true(trimしてから確認)
// Java11以降
" ".isBlank(); // true(空白文字のみなら true)
" ".isBlank(); // true(全角スペースも!)
"hello".isBlank(); // false
trim() は ASCII の空白(スペース・タブ等)しか除去しませんが、isBlank() は Unicode の空白文字も考慮します。日本語を扱うアプリでは結構助かります。
strip() / stripLeading() / stripTrailing() — Unicode対応のtrim
var s = " こんにちは "; // 全角スペースを含む
s.trim(); // " こんにちは "(全角スペースは取れない)
s.strip(); // "こんにちは"(全角スペースも除去)
s.stripLeading(); // "こんにちは "(前だけ)
s.stripTrailing(); // " こんにちは"(後ろだけ)
Java11以降を使うなら、trim() より strip() を優先しましょう。
日本語入力が絡む画面では特に。
lines() — 文字列を行ごとのStreamに
var text = "1行目\n2行目\n3行目";
// Java10以前(split で処理)
for (var line : text.split("\\n")) {
System.out.println(line);
}
// Java11以降(lines() でStream処理)
text.lines()
.filter(line -> !line.isBlank())
.forEach(System.out::println);
CSVや複数行テキストを処理するときに便利です。
repeat(int) — 文字列の繰り返し
"Java".repeat(3); // "JavaJavaJava"
"-".repeat(20); // "--------------------"(区切り線など)
「ログに区切り線を引きたい」というような地味なシーンで役立ちます。
ちなみに私はつかったことはありません。。
2. Files の読み書きメソッド追加
ファイルを1行でテキストとして読み書きできるメソッドが増えました。
var path = Path.of("/tmp/sample.txt");
// Java11以前(煩雑)
var content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
// Java11以降(シンプル)
var content = Files.readString(path); // UTF-8読み込み
var content2 = Files.readString(path, StandardCharsets.ISO_8859_1); // 文字コード指定も可
// 書き込み
Files.writeString(path, "書き込む内容");
Files.writeString(path, "追記内容", StandardOpenOption.APPEND);
小さいファイルをさっと読み書きするなら、これで十分なケースが増えます。
3. HttpClient が標準ライブラリへ
Java9で試用段階として登場した HttpClient が、Java11で正式に標準ライブラリへ仲間入りしました。
Java8まで、HTTP通信には古くて使いにくい HttpURLConnectionか、Apache HttpClient などの外部ライブラリが必要でした。
Java11からは追加依存なしで書けます。
// Java11以降の標準 HttpClient
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api/users"))
.GET()
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body()); // レスポンスボディ(String)
非同期リクエストも書けます。
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
Spring Boot を使っている現場では RestTemplate や WebClient がすでにあるので、標準 HttpClient を直接使う機会は限られます。ただ「ライブラリなしで動くスクリプトを書きたい」という場面では出番があります。
4. 単一ファイルの直接実行
小さなプログラムのためにいちいちコンパイルしなくていい機能です。
// Hello.java
public class Hello {
public static void main(String[] args) {
System.out.println("こんにちは、Java11!");
}
}
# Java10以前(コンパイルしてから実行)
javac Hello.java
java Hello
# Java11以降(直接実行)
java Hello.java
「Javaで使い捨てスクリプトを書きたい」という需要に応えます。
本番コードで使うというより、学習・試し書きのハードルが下がるのが大きいと感じています。
5. ラムダ引数への var 適用
Java10で登場した var が、Java11でラムダ式の引数にも使えるようになりました。varが覇権を取ろうとしている感じが伝わってきますね。
// ラムダ引数に型推論を適用(Java11以降)
var list = List.of("apple", "banana", "cherry");
list.stream()
.filter((var s) -> s.startsWith("a"))
.forEach(System.out::println);
「それ今まで s -> って書けばよかったのでは?」と思った方、正解です。引数に型を書かない書き方(s -> ...)で同じことができます。var を使うメリットは、アノテーションを付けたいときです。
// アノテーションを付ける場合に var が役立つ
list.stream()
.filter((@NonNull var s) -> s.startsWith("a"))
.forEach(System.out::println);
アノテーションなしの通常のラムダでは var を使う必要性は薄いです。
Java8から11に上げるときの注意点
Java8→11の移行は「LTS間の移行」としてよく行われますが、いくつか注意点があります。
JavaEE/CORBAモジュールの削除
Java8まで JDK に含まれていた以下のモジュールが Java11 で完全に削除されました。
| 削除されたモジュール | 代替 |
|---|---|
javax.xml.bind.* (JAXB) |
jakarta.xml.bind 等を依存に追加 |
javax.activation.* |
jakarta.activation を追加 |
javax.transaction.* |
jakarta.transaction を追加 |
Spring Boot 2→3 の移行でも同様の問題が出ます(Spring Boot 3 は jakarta.* 名前空間)。古いコードに import javax.xml.bind.* があればマーカーです。
私も一度経験しており、苦戦した思い出があります。
sun.* 内部APIへのアクセス制限
Java9のモジュールシステム導入以降、段階的に sun.* の内部APIへのアクセスが制限されています。古いライブラリが sun.* に依存している場合、Java11で動かなくなる可能性があります。
おわりに
Java11は「LTSにふさわしい充実ぶり」です。
文字列メソッドの強化、標準HttpClient、単一ファイル実行——どれも地に足の着いた変化です。
次回は Java11→17編。Java12〜16の短命バージョンをまとめて見ていきます。switch式、テキストブロック、record クラス、sealed クラスと、書き方が大きく変わる機能が一気に登場する回です。一緒にレベルアップを目指しましょう。