Java9リリース記念!今ここで、Java8の新機能を振り返ろう【後半】
INDETAIL Advent Calendar 2017 24日目の記事です。
2017年も、残すところあと一週間となりましたね。年末年始の準備はお早めに。
今回のテーマについて
前回の記事では、Java8で追加された機能の中から「ラムダ式」「デフォルトメソッド」「Optional」について、簡単にご紹介しました。
今回は後半戦。予告どおり、以下の機能について触れていきます。
・型アノテーション
・型推論の強化
・メソッド、パラメータのリフレクション
・Date and Time API
型アノテーション
Javaのアノテーションは、今までクラスやメソッドの宣言時にしか指定できませんでしたが、型アノテーションの導入により「型が指定される任意の場所」(ジェネリクスの型パラメータや、メソッドの戻り値の型など)にアノテーションを指定できるようになりました。
型アノテーションを活用することで、コンパイル時に、条件を満たさないコードや潜在的なエラーを事前に検出することができます。
以下の例では、メソッド引数に対してChecker Frameworkライブラリが提供する@NonNull
アノテーションを付与しています。コンパイラは、このメソッドがnullを受け取る可能性があるかどうかを検証します。
1 2 3 |
private String getName(@NonNull String key){ // ... } |
この場合、呼び出し元に対して「getNameメソッドの引数にnullは許容しない」という事を明示できるメリットもあるかと思います。
型アノテーションについては、以下URLが詳しいので、興味のある方はぜひ読んでみてください。
JSR 308の解説:Javaの型アノテーション
型推論の強化
プログラミング言語の性質のひとつに「動的型付け」「静的型付け」というものがあります。
・動的型付け・・・変数に対して、データ型を指定する必要がない。整合性チェックは実行時に行われる。(Ruby、JavaScriptなど)
・静的型付け・・・変数に対して、データ型を指定する必要がある。整合性チェックはコンパイル時に行われる。(Java、C#など)
今回ご紹介する「型推論」とは、この静的型付けにおいて、データ型の指定を省略できるというものです。
実は前回の記事で、こっそり登場していました。
1 2 3 4 5 6 7 8 |
Test t = (name) -> { // 引数の型は省略可能(型推論) if (name.isEmpty()) { return "Hello,nobody."; } else { return "Hello," + name; } }; System.out.println(t.getGreeting("suzy")); |
これはString型の引数を取るメソッドを実装したラムダ式ですが、1行目にあるように、引数name
の型を省略しています。なぜ省略可能かというと、コンパイラが、引数の型をインタフェース定義から推論してくれるためです。
型推論をはじめ、Java8ではラムダ式を扱いやすくするための様々な機能追加がされているようですね。
メソッド、パラメータのリフレクション
リフレクションで、コンストラクタやメソッドの引数名を取得できるようになりました。
以下は、コンストラクタの引数名を取得するサンプルコードです。期待結果は「param1 param2」だったのですが...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Test { public static void main(String[] args) throws Exception { Constructor<Test2> c = Test2.class.getConstructor(String.class, String.class); for (Parameter param : c.getParameters()) { System.out.println(param.getName()); } } } class Test2 { public Test2(String param1) {}; public Test2(String param1, String param2) {}; } |
実行結果が「arg0 arg1」となってしまいました。
リフレクションで引数名を取得するには、classファイル内に名前を保持している必要があり、コンパイル時に-parameters
オプションを付けるか、Eclipseを利用している場合、プロジェクトのコンパイル設定を変更する必要があるようです。
参考:Javaリフレクションメモ(Hishidama's Java Reflection Memo)
Date and Time API
今までは、Javaで日付や時刻を扱う際にはjava.util.Date
やjava.util.Calendar
などのクラスを使うことが多かったと思います。
ただし意外と使いにくい。月が0〜11で定義されていたり、Calendarを扱う場合はいちいちインスタンスを生成する必要があったり、日付操作の後でget()
等を実行しないと再計算されなかったり。私自身、仕様を忘れてハマった事も何度かあります。
Date and Time API
は、このような問題を解消すべく追加された、日付や時刻を扱うためのAPI群です。
特徴のひとつとして、保持する値の種類(例えば年月日・月のみ・時刻、タイムゾーンの有無など)によって、様々なクラスが用意されている点が挙げられます。
現在年を取得するプログラムで比較してみると、以下のような違いがあります。
1 2 3 4 5 6 |
// 従来 Calendar cal = Calendar.getInstance(); System.out.println(cal.get(Calendar.YEAR)); // Date and Time API System.out.println(Year.now()); |
従来はCalendar
クラスにフィールド定数を指定する形で、様々な値を扱っていたのに対し、Date and Time API
の場合は、年のみ扱う場合はYear
、時刻のみ扱う場合はLocalTime
など、役割が各クラスに分割されています。それぞれのクラスの役割が明確なので、以前よりも直感的に扱えるのではないでしょうか?
その他、よく使いそうな処理について、以下URLに分かりやすくまとめられています。
導入時の参考にしてみてください。
Qiita - Java8の日時APIはとりあえずこれだけ覚えとけ
まとめ
Java8の新機能の中から「型アノテーション」「型推論の強化」「メソッド、パラメータのリフレクション」、最後に「Date and Time API」をご紹介しました。
この機能はこう使うと便利!というところまでは踏み込めませんでしたが、気になった新機能があれば、ぜひ調べて理解を深めたり、現場で活用してみてください。