IntelliJ IDEAとかAndroid Studioを使っている人は、メソッドの横の方に@
が書かれているのを見たことがあるかと思います。
(Android Studioで実際に表示されるのかは知らないけど、ツイッターで観測している限りアンドロイダーの人で「この@Contract
って何」ってツイートしている人がいたのでおそらく表示されている)
ここにカーソルを合わせると、メソッドの性質について情報が表示されます。
例1:次のようなメソッドの場合には@Contract("null -> fail; !null -> !null")
と表示されます。
null
を引数に渡すと例外が発生するnull
でない引数を渡すとnull
でない値が返される
例2:つぎのメソッドの場合には@NotNull
と表示されます。
- どのような引数を渡しても必ず
null
でない値が返される
この情報が表示されることで、あるクラスのあるメソッドの引数にnull
を渡すと例外が発生するとか、List<UserInformation>
を返すメソッドなんだけどnull
を返してくることがあるっぽいといった性質がわかるので、事前にそれらの対策を織り込んだコードを書くことができると思います。
チェッカーフレームワーク
IntelliJ IDEAで表示されているのはJetBrains製のチェッカーフレームワークのorg.jetbrains:annotations
に基いたメソッドの静的な性質についての情報です。
チェッカーフレームワークはJSR308で提案されたもので、コンパイル時にnull
安全性や副作用の有無などを検査するフレームワークです。
詳しくはこのあたりのサイトを読むといいと思います。
ワシントン大学のチェッカーフレームワークのサイト
で、そのレポジトリー
というか、日本語でかなり詳しく書かれた記事
ちなみにチェッカーフレームワーク自体はJava SE8で導入されているものです。
JetBrainsのチェッカーフレームワーク
で、JetBrainsのチェッカーフレームワークに戻ると、このアノテーションセットはmavenセントラルに登録されているので、取ってくることができます。
<dependency> <groupId>org.jetbrains</groupId> <artifactId>annotations</artifactId> <version>13.0</version> </dependency>
dependencies {
compile 'org.jetbrains:annotations:13.0'
}
そして、@
で表示されているのと同じ内容のアノテーションを記述すると、横にある@
が消えます。
実はこんな偉そうなことを書いている割には、全部のアノテーションを使ったことがあるわけではなく、@Contract
と@NotNull
くらいしかわかってないので、僕が知っている限りの書き方をメモしておきます。
@NotNull
- メソッドに付与された場合は、そのメソッドは
null
を返さないことが保証されることを意味するnull
を返すようなコードを書いていると、コードハイライトされる
- メソッドのパラメーターに付与された場合は、引数に
null
を渡すことはできない - フィールドの付与した場合は、フィールドに
null
値を設定することは許されない
@Contract
メソッドの性質に関する契約を記述するアノテーションで、boolean
型の値pure
とString
型の値value
を設定する
pure
は副作用に関する契約を記述するvalue
はメソッドの性質について記述する- メソッドの性質は
引数部 -> 作用 ; 引数部 -> 作用 ; ...
のような形で引数部 -> 作用
を;
で区切った形で記述する - 引数部は
引数 , 引数 , ...
のように引数をカンマで区切った形で記述する - 引数には渡される可能性のある値を記述する。なお、引数には次の文字列が使用できる
_
: 任意の引数null
:null
値!null
:null
でない値true
:boolean
のtrue
false
:boolean
のfalse
- 作用には返される値を記述する。なお、作用には次の文字列が使用できる
null
:null
値が返される!null
:null
でない値が返されるtrue
:boolean
のtrue
が返されるfalse
:boolean
のfalse
が返されるfail
: 例外が返されることを意味するany
: 任意の値 : 使うこともできるがあまり意味がない
- メソッドの性質は
例1. 二つの引数をとって、どちらともnull
でない場合にはnull
でない値が返され、いずれか一方がnull
だった場合には例外が発生する、副作用のないメソッドについては次のように記述する。
@Contract(value = "null, _ -> fail; _, null -> fail; !null, !null -> !null", pure = true)
例2. 一つの引数をとるが、どのような値が渡されても絶対にnull
が返されないメソッドの場合は次のように記述する。
@Contract("_ -> !null")
実はこれで良かったりもする。
@NotNull
例3. 引数なしのメソッドで、絶対にnull
が返されないメソッド
@Contract("-> !null")
例4. 二つの引数を取り、最初の引数がnull
の場合にはnull
が返されるメソッド
@Contract("null, _ -> null")
javadocを読んでいるとその他のアノテーションにこのようなものがあります。
@Nls
: 文字列がローカライズされる必要がある@NonNls
: 文字列がローカライズされる必要はない@Nullable
: 引数やフィールドにnull
を渡しても大丈夫@PropertyKey
: リソースにあるプロパティキーに必ず含まれている文字列@TestOnly
: テストコードにのみ使用することが許されるメソッドやコンストラクター/プロダクションコードでは使用してはいけない
使い方
ドキュメントとして使うのも、まあ、悪くはないんだけど、せっかくコードハイライトしてくれる(eclipseとnetbeansのことは忘れている)のだから、コードを書く前にそのメソッドに求める性質を記述してから書くというのが妥当な使い方だと思います。
まず、メソッドに求める性質を記述します。
そして、性質を満たすようにコードを書きます。
すると、あら不思議!null
とか例外レベルのコード品質が保証されたコードが出来上がります(「品質」という言葉をここで使うのは、かなりためらっている)。
これで、null
とか例外に関するテストコードを書く手間が少し省けますね(あるに越したことはない)。
さあ、あなたもチェッカーフレームワークでADD(Annotation Driven Development)な生活を!