ひびのログ

日々ではないけどログを出力していくブログ

Java10 が発表されたので Java8 から乗り換えてみる

基本的に、「コードを書く」という視点で新機能を試します。 使用しているのは OpenJDK10 です。

主な新機能一覧

Java9 の新機能を試してみる

JShell

$ jshell
|  JShellへようこそ -- バージョン10
|  概要については、次を入力してください: /help intro

jshell> "string"
$1 ==> "string"

便利!

特徴

  • セミコロン不要
  • 事前コンパイル不要(実行時に自動でコンパイルされる)
  • メインクラス・メインメソッド不要
  • 一部クラスがインポート済み(java.util 等の使用頻度が高いもの)
  • 戻り値が表示される(わざわざSystem.out.printlnとか書かなくていい)
  • 外部ファイルの実行もできる(下記参照)
  • タブ補完ができる
// hello-world.java
String h = "Hello"
String w = "World"
System.out.println(h + " " + w)
jshell> /open hello-world.java
Hello World

外部ファイル実行の例です。 セミコロンは不要ですが、戻り値の表示はされないようです。 returnを書いてもダメみたいです。

使いどころ

  • ちょっとした動作確認
  • Java 以外使用できない Linux などにおいて、シェルスクリプトではやりづらい・書きたくないときに、スクリプト言語として使用
  • Java 入門に

不変コレクションのファクトリメソッド

Java8 では……

// List の生成
Arrays.asList("a", "b");

// Map の生成(可変)
new HashMap<String, String>() {{
    put("key1", "value1");
    put("key2", "value2");
}};

Java9 からは……

List.of("a", "b");

Map.of(
    "key1", "value1",
    "key2", "value2"
);

Map#ofに関しては、タプルがあればもうちょっと良くなったかもしれませんね……
とはいえ、これまで面倒だった Map の初期化も、これでかなり楽になりそうです。

List については、Arrays#asListがありますが、なにか違いはあるのでしょうか……?
調べてみたいと思います。

匿名クラスでのダイヤモンド演算子

↑の「不変コレクションのファクトリメソッド」の Java8 版で書いたような、匿名クラスを使用するときの型引数を、ダイヤモンド演算子で書けるようになりました。

new HashMap<>() {{
    put("key1", "value1");
    put("key2", "value2");
}};
// => HashMap<String, String>

Map#ofが追加されたのであまり使い所はなさそうですが、 強いて言えば、ミュータブルな Map の生成にはまだ使うかも……?

インターフェース内の Private メソッド

public interface A {
    default void defaultMethod() {
        privateMethod();
    }
    private void privateMethod() {
        System.out.println("privateMethod!");
    }
}

たまーーーにほしかったやつ。 デフォルトメソッドやスタティックメソッドと併用して、処理を見やすくするときに使う感じです。

staticもいけます。

モジュールシステム(Project Jigsaw)

散々取り上げられているので、いまさらここには書きません。

べっ、別に、試すのが面倒だからってわけじゃないんだからねっ///

もし後々試したらリンクを張ります。

try-with-resource の改善

private method(ResultSet rs) {
    try (rs) {
        while (rs.next()) {
            System.out.println(rs.getString("name"));
        }
    }
    // rs is closed
}

try-with-resource で、かっこのなかで変数の定義をしなくて良くなりました。 処理順の関係で try-with-resource できなかったコードも、これからはできるようになるかもしれません。

ただ、例のようにメソッドに closable を渡すのはアンチパターンかな、とは思います。

Stream#takeWhileStream#dropWhile

List<Integer> list = List.of(1, 2, 3, 4, 5, 6);

list.stream().takeWhile((x) -> x < 4).forEach(System.out::print);
// => 123
list.stream().dropWhile((x) -> x < 4).forEach(System.out::print);
// => 456

地味にほしかったやつ。 Stream を使っていて、途中まで処理したい or 途中から処理したいということがあった人もいるはず。 それが簡単に書けるようになりました。

条件を満たしている間、takeWhileは処理、dropWhileはスキップします。

Java10 の新機能を試してみる

var

var str = "string";
var num = 3;
var list = List.of("a", 1);

神。

Java10 は以上でーす。

さすがに雑すぎるので追記します。

変数の型の代わりにvarを書くことによって、ローカル変数の型推論がされ、適切な型になります。 最初のうちは型名を書くのに慣れているのであまり使うことはないかもしれませんが、newで代入する変数などはこれでいいかもしれませんね。

私? もちろん、ローカルはほぼ全部varで置き換えます。

まとめ

Java9 は、大きな変更としてはモジュールシステムがありますが、それ以外にも細かい改善が多いですね。 「これがなきゃやってられない!」ではなく、「これがあるとかなり便利!」という方向だと感じました。

Java10 は内部の改善が主なので上に書いてある内容は少ないですが、varの導入という神アップデートがありました。 これは今後のJavaの書き方を考えさせられる内容です。 個人的には、「これがなきゃやってられない」です。

モジュールシステムは、大きめのJavaプロジェクトを管理する際に、 今後必須になってくるくらい影響があると思われます。 そういうプロジェクトにがっつり関わったことはないんですけどね。悲しいことに。

これからの Java のリリースサイクルは半年とだいぶ短くなりますが、 2018/9 リリース予定の Java11 が LTS のようなので、そこまで徐々にアップデートしていきたいですね。

参考