連載
» 2011年05月19日 00時00分 公開

いまさら聞けない「Javadoc」と「アノテーション」入門【改訂版】Eclipseではじめるプログラミング(22)(2/4 ページ)

[小山博史,株式会社ガリレオ]

よく使う3つの標準アノテーション型

 アノテーションをソースコードへ埋め込むためには、コンパイラがチェックできるように、どんなアノテーションを使うのかをアノテーション型として最初に定義しておく必要があります。開発者は定義されているアノテーション型を使って、注釈を付けたいクラス、メソッド、変数などにアノテーションを付けます。

 Javaには標準アノテーション型として、java.langパッケージに「Override」「Deprecated」「SuppressWarnings」が定義されています。これらは、よく使いますし、分かりやすいので、具体的にどういった使い方をすればいいのか、確認してみましょう。概要は、次の通りです(下記リストはインデックスになっています)

Override
スーパークラスのメソッドをオーバーライドするという注釈
Deprecated
クラスやメソッドが非推奨であるという注釈クラスやメソッドが非推奨であるという注釈
SuppressWarnings
コンパイル時の警告を抑制するという注釈コンパイル時の警告を抑制するという注釈

【1】Override

 Overrideは、スーパークラスのメソッドをオーバーライドするという注釈を付けたいときに使用します。次のクラスをコンパイルしてみましょう。「StandardPrinter」というクラスのtoStringメソッドを呼び出して、「StandardPrinter」という文字列をコンソール画面へ出力するプログラムです。

package sample22.app2;
 
public class StandardPrinter {
    public String toStrimg() {
        return "StandardPrinter";
    }
    public static void main(String[] args) {
        StandardPrinter app = new StandardPrinter();
        System.out.println(app.toString());
    }
}
sample22.app2.StandardPrinter@ca0b6
実行結果(例)

 このプログラム作成者は、「app.toString()」を使って「StandardPrinter」という文字列を表示したかったのですが、表示されません。なぜでしょうか。注意深い読者の皆さんは、すでにお気付きでしょう。

 StandardPrinterクラスのtoString()メソッドは、StandardPrinterクラスのスーパークラスであるObjectクラスのtoString()メソッドをオーバーライドしたつもりがタイピングミスにより、toStrimg()メソッドとなっています。toString()メソッドをオーバーライドするという情報はコードに含まれていませんから、コンパイラはコンパイルエラーを出しません。toStrimg()メソッドというtoString()メソッドとは別のメソッドが宣言されたものだとして扱います。

 慎重深い読者からすると、「こういったタイプミスは普通しないだろう」と思うでしょうが、実際の開発現場ではありがちなミスで、しかも記述した本人もタイプミスをしたとは思っていないものですから、なかなかこの間違いに気付けず、「なぜ、toString()メソッドのオーバーライドがされないのか?」と全然別のことを考えながら、バグがどこにあるか探すことになります。散々調査をした揚げ句、ようやくタイピングミスだということに気付き、脱力感を感じることになります。

 こういった単純ミスを防ぐために、Overrideアノテーション型のアノーテションを利用します。具体的には「@Override」をメソッドの修飾子へ付けます。これにより、開発者はコンパイラへ、このメソッドはスーパークラスのメソッドをオーバーライドすることを知らせます。

 次のように、StandardPrinterクラスをコピーして、StandardPrinter1クラスを作ってから、toStrimg()メソッドへ@Overrideと付けてみましょう。すると、コンパイルエラーとなります。Eclipseではエディタ上でtoStrimgの行に赤下線が表示されるので、開発者はすぐにエラーメッセージを確認してタイプミスに気付くことができます。

package sample22.app2;
 
public class StandardPrinter1 {
    @Override
    public String toStrimg() {
        return "StandardPrinter";
    }
    public static void main(String[] args) {
        StandardPrinter1 app = new StandardPrinter1();
        System.out.println(app.toString());
    }
}

 StandardPrinter1クラスを次のように修正しましょう。すると、コンパイルエラーは出なくなり、開発者の意図通り、StandardPrinter1でObjectクラスのtoString()メソッドをオーバーライドできたことになります。

package sample22.app2;
 
public class StandardPrinter1 {
    @Override
    public String toString() {
        return "StandardPrinter";
    }
    public static void main(String[] args) {
        StandardPrinter1 app = new StandardPrinter1();
        System.out.println(app.toString());
    }
}
StandardPrinter
実行結果(例)

【2】Deprecated

 Deprecatedは、クラスやメソッドが非推奨であるという注釈を付けてたいときに使用します。例えば、次のような「User」クラスと「App」クラスがあったとします。

package sample22.app3;
 
public class User {
    private String name;
    public User(String name) {
        this.name = name;
    }
    public String get_name() { return name; }  
}
sample22.app3.Userクラス
package sample22.app3;
 
public class App {
    public static void main(String[] args) {
        User user = new User("koyama");
        System.out.println(user.get_name());
    }
}
sample22.app3.Appクラス

 最初のバージョンではUesrクラスのnameを取得するためのメソッドとしてget_name()メソッドを用意しましたが、バージョンアップ時に、このメソッド名をgetName()メソッドという名前に変更することになったとします。ただし、既存のプログラムとの互換性は維持し、新しく作成するプログラムでは新しい名前しか使わないようにしたいとします。

 そんなときは、次のようにプログラムを変更することになるでしょう。ここでは、サンプルなのでパッケージを変更しています。

package sample22.app4;
 
public class User {
    private String name;
    public User(String name) {
        this.name = name;
    }
    @Deprecated
    public String get_name() { return getName(); }
    public String getName() { return name; }
}
sample22.app4.Userクラス
package sample22.app4;
 
public class App {
    public static void main(String[] args) {
        User user = new User("koyama");
        System.out.println(user.get_name());
        System.out.println(user.getName());
    }
}
sample22.app4.Appクラス

 これで互換性を維持することはできますが、新しく作成するプログラムでgetName()メソッドを使うようにするには、開発者がそのことに簡単に気が付くようにする必要があります。そのために、Userクラスでは、get_name()メソッドへアノテーション「@Deprecated」を指定しています。こうすると、get_name()メソッドを使っているクラスでは、警告が表示されるようになります。

 Eclipse上ではget_name()メソッドに取り消し線が付きますし、これを使用するクラスでは警告が表示されます。

【3】SuppressWarnings

 少し古いライブラリを使っていると、ジェネリックスを使っていないために、型について安全なプログラミングができない場合があります。そんなときは、キャストを行いますが、コンパイル時に警告が出てしまいます。意味を理解して対処している場合は、この警告を抑制して表示されないようにしたいときがあります。

 こういったときは、SuppressWarningsアノテーション型を使うと、コンパイラはコンパイル時の警告を抑制します。これは警告を抑制するために用意されているアノテーション型ですから、適切に使用しないと、本来修正が必要であるコードへの警告まで抑制してしまうことがあるので、適用範囲に気を付けましょう。つまり、むやみにclass全体へ適用しないようにしてください。

 ジェネリックスを使っていないsample22.app5.libパッケージがあったとして、この中にUserクラス、UserManagerクラスがあるとします。

package sample22.app5.lib;
  
import java.util.ArrayList;
import java.util.List;
  
public class UserManager {
    private List list = new ArrayList();
    public List getList() { return list; }
    public void add(Object user) { list.add(user); }
    public Object get(int index) { return list.get(index); }
    public void remove(int index) { list.remove(index); }
}
sample22.app5.lib.UserManagerクラス
package sample22.app5.lib;
public class User {
    private String name;
    public User(String name) {
        this.name = name;
    }
    public String getName() { return name; }
}
sample22.app5.lib.Userクラス

 このライブラリを使うsample22.app5.Appクラスを次のように作成したとします。すると、「List<User> list = (List<User>)um.getList();」でコンパイラが警告を出します。ここでは、UserManagerクラスでは、必ずUserクラスしか登録しないため、UserManagerクラスのgetListメソッドを呼び出すと、「List<User>」となっていることが分かっています。こういった場合は、コンパイラが出す警告の表示を抑制したくなります。

package sample22.app5;
  
import java.util.List;
import sample22.app5.lib.User;
import sample22.app5.lib.UserManager;
  
public class App {
    private UserManager um = new UserManager();
    public void exec() {
        User user = new User("koyama");
        um.add(user);
        List<User> list = (List<User>)um.getList();
        User u = list.get(0);
        System.out.println(u);
    }
    public static void main(String[] args) {
        App app = new App();
        app.exec();
    }
}
sample22.app5.Appクラス

 sample22.app6.Appクラスを次のように作成して、次のようにSuppressWarningsアノテーションを指定します。

 Eclipseでは「(List<User>)um.getList()」にマウスカーソルを近づけると、「@SuppressWarnings 'unchecked'を'exec()'に追加します」と修正案を表示しますが、ここではローカル変数「list」に対して指定します。「@SuppressWarnings 'unchecked'を追加すればいい」ということがEclipseのメッセージから分かるので、「@SuppressWarnings("unchecked")」と書きます。すると、警告の出力が抑制されます。

package sample22.app6;
  
import java.util.List;
import sample22.app5.lib.User;
import sample22.app5.lib.UserManager;
  
public class App {
    private UserManager um = new UserManager();
    public void exec() {
        User user = new User("koyama");
        um.add(user);
        @SuppressWarnings("unchecked")
        List<User> list = (List<User>)um.getList();
        User u = list.get(0);
        System.out.println(u);
    }
    public static void main(String[] args) {
        App app = new App();
        app.exec();
    }
}

 さて、Override、Deprecated、SuppressWarningsといったアノテーション型について説明をしました。これらを利用する分には、以上の知識で何となく使えてしまいますから、それほど難しくはないでしょう。Javaであらかじめ用意されているアノテーション型は使いたくなる場面が多いので、覚えておきましょう。

 次ページからは、独自のアノテーション型を作る方法を解説します。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。