Scala ひと巡り : アノテーション (Annotations)
アノテーションは、定義にメタ情報を関連づけます。 単純なアノテーション節は、@C あるいは @C(a1,...,an) の形です。ここで、C はクラス C のコンストラクタで、scala.Annotation [31]に適合しなくてはなりません。
All given constructor_arguments a1,...,an must be constant_expressions (i.e., expressions on numeral literals, strings, class_literals, Java enumerations and one-dimensional arrays of them) .
与えられたコンストラクタ引数 a1,...,an はすべて、定数式(すなわち、数値リテラル、文字列、クラスリテラル、Java enumとそれらの 1 次元配列上の式)でなければなりません。
アノテーション節は、その後に続く、最初の定義または宣言に適用されます。1 つ以上のアノテーション節が定義や宣言に先行するかもしれません。それら節の与えられた順番は重要ではありません。
アノテーション節の意味は処理系依存です。Java プラットフォームでは、次の Scala アノテーションは標準的な意味を持っています。
Scala Java
scala.SerialVersionUID [32] serialVersionUID [33] (フィールド)
scala.cloneable [34] java.lang.Cloneable [35]
scala.deprecated [36] java.lang.Deprecated [37]
scala.inline [38] (2.6.0から) 等価なもの無し
scala.native [39] (2.6.0から) native [40] (キーワード)
scala.remote [41] java.rmi.Remote [42]
scala.serializable [43] java.io.Serializable [44]
scala.throws [45] throws [40] (キーワード)
scala.transient [46] transient [40] (キーワード)
scala.unchecked [47] (2.4.0から) 等価なもの無し
scala.volatile [48] volatile [40] (キーワード)
scala.reflect.BeanProperty [49] Design pattern [50]
次の例では、Java main プログラム中で例外送出をキャッチするために、メソッド read の定義に throws アノテーションを加えています。
Java コンパイラは、どのチェック例外がメソッドあるいはコンストラクタの実行によって引き起こされるか分析し、プログラムがチェック例外 [51]用のハンドラを含むことを確認します。起きる可能性のある各チェック例外に対して、メソッドあるいはコンストラクタの throw 節では、その例外クラスあるいはその例外クラスのスーパークラスの 1 つに言及しなくてはなりません。
Scala にはチェック例外がないので、Java コードが Scala メソッドの送出する例外を捕えることができるように、Scala メソッドに 1 つ以上の throws アノテーションをつける必要があります。
package examples import java.io._ class Reader(fname: String) { private val in = new BufferedReader(new FileReader(fname)) @throws (classOf [IOException]) def read() = in.read() }
(訳注: thorws [45], classOf [52] )
次の Java プログラムはファイルの内容を印字します。ファイル名は main メソッドに最初の引数として渡されます。
package test; import examples.Reader; // Scala クラス !! public class AnnotaTest { public static void main(String[] args) { try { Reader in = new Reader(args[0]); int c; while ((c = in.read()) != -1) { System.out.print((char) c); } } catch (java.io.Exception e) { System.out.println(e.getMessage()); } } }
クラス Reader 中の throws アノテーションをコメントアウトすると、Java main プログラムのコンパイル時に、次のエラーメッセージが出力されます:
Main.java:11: Exception java.io.IOException is never thrown in body of corresponding try statement } catch (java.io.IOException e) { ^ 1 error
Java アノテーション
注意 : Java アノテーションの -target:jvm-1.5 オプションの使用を確認してください。
Java 1.5 は、アノテーション [53]の形でユーザー定義メタデータを導入しました。アノテーションの重要な特徴は、指定された名前と値の対を信頼して、それら要素を初期化することです。 例えば、もしあるクラスのソースを追跡するアノテーションが必要なら、次のように定義するかもしれません。
Java annotations @interface Source { public String URL(); public String mail(); }
それを次のように適用してください
@Source(URL = "http://coders.com/", mail = "support@coders.com") public class MyClass extends HisClass ...
Scala のアノテーション適用は、Java アノテーションのインスタンス化のために名前付き引数を使う必要があるので、コンストラクタ呼び出しのように見えます。
@Source(URL = "http://coders.com/", mail = "support@coders.com") class MyScalaClass ...
もしアノテーションが(デフォルト値をもたない) ただ 1 つの要素を含むだけなら、この構文はたいへんうんざりします。そこで、規約により(by convention)、もし名前を値として指定するなら、それをコンストラクタに似た構文を使って Java 中で適用できます。:
@interface SourceURL { public String value(); public String mail() default ""; }
それを次のように適用してください
@SourceURL("http://coders.com/") public class MyClass extends HisClass ...
In this case, Scala provides the same possiblity.
この場合、Scala は同じことを提供します。
@SourceURL("http://coders.com/") class MyScalaClass ...
mail 要素はデフォルト値を指定されているので、それに明示的に値を与える必要はありません。しかし、もしそうする必要があっても、Java 中で 2 つのスタイルを混ぜて適応させることはできません。:
@SourceURL(value = "http://coders.com/", mail = "support@coders.com") public class MyClass extends HisClass ...
Scala はこの点に関してより柔軟です。
@SourceURL("http://coders.com/", mail = "support@coders.com") class MyScalaClass ...
この拡張された構文は、.NET のアノテーションでも同じあり、それらアノテーションのフルの能力を引き出します。