effective java 輪読会 第6章 項目35-37

28
Effective Java 輪読会 第5(項目35372014/1/29 開発部 野口

Upload: appresso-engineering-team

Post on 11-Jul-2015

428 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Effective Java 輪読会 第6章 項目35-37

Effective Java 輪読会 第5回(項目35~37)

2014/1/29

開発部 野口

Page 2: Effective Java 輪読会 第6章 項目35-37

項目35

命名パターンよりアノテーションを選ぶ

Page 3: Effective Java 輪読会 第6章 項目35-37

命名パターン

何らかのプログラム要素がツールやフレームワークによる特別な処理を要求していることを示すためのテクニック

例)JUnit テストフレームワークのテストメソッドは「test」で始まることが要求されていた

Page 4: Effective Java 輪読会 第6章 項目35-37

命名パターンの短所1

誤字に気づかない

tsetSafetyOverride と名付けてしまっても、JUnit

は何も言わない

黙って、実行しないだけ 余談: CppUnit-x では(命名パターンとはちょっと違いますが)関数ポインタを TestSuite に登録するコードが必要で、書き忘れると何も起こらなかったので、うっかりミスがないように、必ず最初はテストを fail させるようにしていました

Page 5: Effective Java 輪読会 第6章 項目35-37

命名パターンの短所2

適切なプログラム要素にだけそれらが使用されることを保証する方法がない

「testSafetyMechanisms クラス」を定義したとき、そのクラスのメソッドがテストとして実行されるかな?と期待するかもしれないが、されない

Page 6: Effective Java 輪読会 第6章 項目35-37

命名パターンの短所3

プログラム要素にパラメータ値を関連付ける良い方法を提供していない

「特定の例外をスローした場合にだけ成功する種類のテスト」をスマートに書けない

たとえばtestThrowsException_throws_DataSpiderException()

のように命名規則を用いることもできるが、脆弱 他の型が適切な場所では、文字列を避ける(項目50)

実行時にしか間違いに気づけない

Page 7: Effective Java 輪読会 第6章 項目35-37

アノテーション

これらの問題をすべて上手く解決します!

// マーカーアノテーション型宣言import java.lang.annotation.*;

/**

* このアノテーションが付けられたメソッドがテストメソッドであることを示す。* パラメータなしの static のメソッドに対してだけ使用すること。*/

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface Test {

}

Page 8: Effective Java 輪読会 第6章 項目35-37

解説(1/3)

@Retention / @Target

メタアノテーション

アノテーション型の宣言に対するアノテーション

Page 9: Effective Java 輪読会 第6章 項目35-37

解説(2/3)

@Retention(RetentionPolicy.RUNTIME)

Test アノテーションを実行時に保持すべきことを示す

このメタアノテーションがないと、Test アノテーションはテストツールから見えなくなる

@Target(ElementType.METHOD)

Test アノテーションがメソッド宣言に対してのみ許されていることを示す

クラス宣言、フィールド宣言、その他のプログラム要素には @Test を適用できない

Page 10: Effective Java 輪読会 第6章 項目35-37

解説(3/3)

「パラメータなしの static のメソッドに対してだけ使用すること」

これを強制する方法はない

コードを書く人がこれを守らなかった場合、実行時に失敗する

JUnit 4 では、java.lang.Exception がスローされます

(動かしてみましょう)

Page 11: Effective Java 輪読会 第6章 項目35-37

パラメータを持つアノテーション型(1/2)

import java.lang.annotation.*;

/**

* アノテーションが付けられたメソッドは、成功するには指定された例外を

* スローしなければならないテストメソッドであることを示す。

*/

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface ExceptionTest {

Class<? extends Exception> value();

}

Page 12: Effective Java 輪読会 第6章 項目35-37

パラメータを持つアノテーション型(2/2)

パラメータ型は、Class<? extends Exception>

Exception を拡張した何らかのクラスに対するClass オブジェクト

境界型トークンの使用例

(サンプルコードを実際に動かしてみましょう)

Page 13: Effective Java 輪読会 第6章 項目35-37

まとめ

ソースファイルに情報を追加するためのプログラミングを必要とするツールを書くのであれば、適切なアノテーション型の集合を定義する

今やアノテーションを利用できるので、命名パターンを使用するのは論外

すべてのプログラマは Java プラットフォームが提供している事前に定義されたアノテーション型を使用すべき 例)@Override(項目36)、@SuppressWarnings(項目24)、@Deprecated

IDE や静的解析ツールが提供しているアノテーションを使用することを検討する

Page 14: Effective Java 輪読会 第6章 項目35-37

項目36

常に Override アノテーションを使用する

Page 15: Effective Java 輪読会 第6章 項目35-37

Override アノテーション

メソッド宣言にだけ使用できる

アノテーションが付けられたメソッド宣言がスーパータイプの宣言をオーバーライドしていることを示す

非道なバグの多くから保護してくれる

例)Bigram クラス(pp.170)の equals メソッド

Page 16: Effective Java 輪読会 第6章 項目35-37

Override アノテーションを付けるとき、付けないとき(1/3)

スーパークラスの宣言をオーバーライドしているすべてのメソッド宣言に付けるべき

抽象ではないクラスで、抽象メソッドをオーバーライドしているときは、不要

@Override を付けなくても、オーバーライドしていないときにはコンパイルエラーになるため

付けても問題はない

Page 17: Effective Java 輪読会 第6章 項目35-37

Override アノテーションを付けるとき、付けないとき(2/3)

コードインスペクション

Override アノテーションが付いていなくてスーパークラスのメソッドをオーバーライドしているメソッドがあれば、IDE によっては警告を出してくれるものがある

Page 18: Effective Java 輪読会 第6章 項目35-37

Override アノテーションを付けるとき、付けないとき(3/3)

インタフェースへの @Override

リリース 1.6 以降では、インタフェースからの宣言をオーバーライドしているメソッド宣言にもOverride アノテーションを付けることが可能

前述の抽象クラスと同様、具象クラスでのオーバーライドに関しては、不要ただし、抽象クラスやインタフェースにおいては必ず付けるようにする価値はある 例)Set インタフェースは Collection インタフェースに新たなメソッドを追加していない。すべてのメソッドに@Override を付けることで、それを保証できる(誤って新たなメソッドを追加してしまうことがない)

Page 19: Effective Java 輪読会 第6章 項目35-37

まとめ

スーパータイプの宣言をオーバーライドしているすべてのメソッド宣言に Override アノテーションを使用することで、コンパイラの保護が得られる

具象クラスでは、抽象メソッド宣言をオーバーライドしているメソッドにアノテーションを付ける必要はない

が、付けても害はない

Page 20: Effective Java 輪読会 第6章 項目35-37

項目37 型を定義するためにマーカーインタフェースを使用する

Page 21: Effective Java 輪読会 第6章 項目35-37

マーカーインタフェース

メソッド宣言を含んでいないインタフェース

そのインタフェースを実装しているクラスが何らかの特性を持っていると単に指定している

例)Serializable インタフェース

Page 22: Effective Java 輪読会 第6章 項目35-37

マーカーインタフェースのマーカーアノテーションに対する長所1 マーカーインタフェースは、マークされたクラスのインスタンスが実装している型を定義する

例)ObjectOutputStream.write(Object) がObjectOutputStream.write(Serializable) ならよかったが……。

マーカーアノテーションは型を定義しない

Page 23: Effective Java 輪読会 第6章 項目35-37

マーカーインタフェースのマーカーアノテーションに対する長所2 より正確に対象を特定できる

そのマーカーが適用可能な唯一のインタフェースをマーカーに拡張させることができる

すべてのマークされた型が、そのマーカーが適用可能な唯一のインタフェースのサブタイプであることも保証される

例)Set インタフェース

Page 24: Effective Java 輪読会 第6章 項目35-37

マーカーアノテーションのマーカーインタフェースに対する長所1 デフォルトを持つアノテーション型要素を 1

つ以上追加することで、すでに使用された後でもアノテーション型に情報を追加できる

インタフェースの場合、一旦実装された後にメソッドを追加することは一般に不可能

Page 25: Effective Java 輪読会 第6章 項目35-37

マーカーアノテーションのマーカーインタフェースに対する長所2 大きなアノテーション機構の一部

フレームワークの一貫性に寄与する

Page 26: Effective Java 輪読会 第6章 項目35-37

マーカーアノテーションとマーカーインタフェースの使い分け(1/2) クラスやインタフェース以外のプログラム要素に対してマーカーが適用される

→マーカーアノテーション

マーカーがクラスとインタフェースだけに適用される

かつ、このマークを持つオブジェクトだけを受け付ける 1 個以上のメソッドを書きたい

→マーカーインタフェース

Page 27: Effective Java 輪読会 第6章 項目35-37

マーカーアノテーションとマーカーインタフェースの使い分け(2/2) マーカーがクラスとインタフェースだけに適用される

かつ、このマーカーの使用を、特定のインタフェースの要素に永久に制限したい

→マーカーインタフェース

それ以外

→マーカーアノテーション

Page 28: Effective Java 輪読会 第6章 項目35-37

まとめ

関連付けられた新たなメソッドを持たない型を定義したいのであれば、マーカーインタフェースを使用する

クラスとインタフェース以外のプログラム要素をマークしたいのであれば、マーカーアノテーションを使用する

対象が ElementType.TYPE であるマーカーアノテーションは要注意

要するに、型を定義したいのであれば、インタフェースを使用すること