まえがき
ずっとJava11を使っていました。そのためすっかりラムダ式やStreamAPIでの書き方に慣れていたのですが、最近Java7を使って稼働しているプロジェクトに異動したので、何ができて何ができないのか、ちょっと調べてみました。
Javaの変遷
私見ですが主要だと思う仕様変更を並べてみました。アプリ実装に関係する部分のみピックアップしています。
このバージョンのこれは入れておいたほうが良いよ!との意見がありましたらコメントにぜひお願いします。
Java8
2014/03/18 正式リリース(GA)
https://openjdk.java.net/projects/jdk8/
ラムダ式
https://openjdk.java.net/projects/lambda/
https://qiita.com/sano1202/items/64593e8e981e8d6439d3
public static void main(String[] args) {
Runnable runner = () -> { System.out.println("Hello Lambda!"); };
runner.run(); //Hello Lambda!
}
無名関数を簡潔に呼び出せる。
StreamAPIと合わせてすごくよく使う。
StreamAPI
Java Stream APIをいまさら入門 - Qiita
コレクション(から作ったStream)に対して中間処理、終端処理を実行できる。
メソッドチェーンで様々な処理を簡潔に書くことができてよい。
Optional
nullを許容し、nullチェックの仕組みを持ったクラス。
Date and Time API
https://openjdk.java.net/jeps/150
DateTimeFormatter
とかZonedDateTime
とか、日時を扱うのに便利なクラスがたくさん。
Java9
2017/09/21 正式リリース(GA)
https://openjdk.java.net/projects/jdk9/
なんとJava8から3年半も経っていたのですね。以降は半年に1回のペースでバージョンアップしているようです。
モジュール化が可能に
https://openjdk.java.net/jeps/261
java 9のmodule機能を試してみる - Qiita
JShellの追加
https://openjdk.java.net/jeps/222
あまりアプリで使わないから上には載せませんでしたが、対話型のJava実行環境JShellが追加されたのはここでした。
$>jshell
| JShellへようこそ -- バージョン15.0.2
| 概要については、次を入力してください: /help intro
jshell> System.out.println("Hello, JShell.");
Hello, JShell.
Java10
2018/03/20 正式リリース(GA)
https://openjdk.java.net/projects/jdk/10/
varによる型推論
https://openjdk.java.net/jeps/286
右辺から明確に型がわかる場合は型の定義はvar
で済ませることができるように。
メソッドの戻す型を変えたりしたとき、それを受け取る変数の型を変えずに済むのはすごく楽だと思います。
var list = new ArrayList<String>(); // infers ArrayList<String>
var stream = list.stream(); // infers Stream<String>
Java11
2018/09/25 正式リリース(GA)
https://openjdk.java.net/projects/jdk/11/
型推論のラムダ式対応
(var x, var y) -> x.process(y)
// is equivalent to:
(x, y) -> x.process(y)
HTTP Client
HTTP2にも対応したHTTP Client.
これがあればもうHttpURLConnection
で頑張らなくてよくなる。
// Sync
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
.authenticator(Authenticator.getDefault())
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
Java14
2020/03/17 正式リリース(GA)
https://openjdk.java.net/projects/jdk/14/
Switch式
https://openjdk.java.net/jeps/361
Switch文を式として扱えて、戻り値を受け取れる。
Switch文の前にインスタンスを作っておく必要がなくなって幾分かコードをシンプルにできそう。
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
Java15
2020/09/15 正式リリース(GA)
https://openjdk.java.net/projects/jdk/15/
テキストブロック
【Modern Java】Java15で正式リリースとなったテキストブロック(JEP 378: Text Blocks)
"""
で囲うことで複数行の文字列を表現できるリテラル。
"
をエスケープさせることなく扱えたり、インデントをいい感じに扱えたりする。
以下の例ではネストの一番浅いところを基準として、インデントを保持してくれる。
HTML example
Using "one-dimensional" string literals
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
Using a "two-dimensional" block of text
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
Java16
2021/03/16 正式リリース(GA)予定
https://openjdk.java.net/projects/jdk/16/
Records
https://openjdk.java.net/jeps/395
レコード(Java14プレビュー版)メモ(Hishidama's record Java14 preview Memo)
// as-is
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() {
return this.x;
}
public int y() {
return this.y;
}
@Override
public int hashCode() {
~
}
@Override
public boolean equals(Object other) {
~
}
@Override
public String toString() {
return "Point[x=" + this.x + ", y=" + this.y + "]";
}
}
// to-be
public record Point(int x, int y) { } // 簡潔に定義できる
instanceOfパターンマッチング
https://openjdk.java.net/jeps/394
instanceOf
で型のチェックと同時に、その型の変数を使えるようにできる。
// as-is
if (obj instanceof String) {
String s = (String)obj;
...
}
// to-be
if (obj instanceof String s) {
// sがStringとして扱える
...
}
(2nd Preview) Sealed Class
まだJava16時点では正式版となりませんが、シールクラスも追加される予定。
このまま順当にいけばJava17でGAでしょうか。
継承可能なサブクラスを絞る機能で、
クラスやインターフェースの頭にsealed
とつけ、permitsの後に継承・実装を許可するクラスを指定可能。
sealed interface Shape
permits Circle, Rectangle { ... }
上記例だとCircle
Rectangle
以外はShape
インターフェースを実装できません。
クラス設計における使いどころ・考え方は以下の記事がよいです。
https://www.infoq.com/jp/articles/java-sealed-classes/
あとがき
こうして並べてみるとJava8でいかに大きく変わったかわかります。
Java11のHTTP周りのクラス追加と、型推論もかなり大きいと思っています。
おまけ
ほぼ同じ内容を勉強会で話したので、そのPDF資料も載せておきます。DLはご自由にどうぞ。
https://speakerdeck.com/sivertigo/javaharegasiyan-yu-karamodannayan-yu-he-dokomadezhi-tuteru-javazui-xin-shi-qing