いつ、どのようにAPIを非推奨とするか

「非推奨」の意味すること

「自虐的(self-deprecating)ユーモア」という言葉を聞いたことがあるかもしれません。つまり、自分自身の重要性を低く評価するユーモアのことです。非推奨(deprecated)のクラスまたはメソッドは、それに似ています。もはや重要ではなくなったのです。つまり、そのクラスやメソッドの重要性は著しく低下しており、現在では他のクラスやメソッドに置き換えられていたり、将来は存在しなくなったりする可能性もあるため、今後は使用するべきでないことを意味しています。

Javaでは、非推奨を表現する手段を提供しています。それは、クラスの発展に伴い、そのAPI (アプリケーション・プログラミング・インタフェース)も必然的に変化するからです。一貫性を保つためにメソッドの名前が変更されたり、新しいメソッドや改良版のメソッドが追加されたり、フィールドが変更になったりします。しかし、このような変更により別の問題も生じます。開発者が新しいAPIに移行するまで、古いAPIを維持する必要がある一方で、今後は古いAPIを使ってプログラミングを行わないよう伝えなければなりません。

クラス、メソッド、またはメンバー・フィールドを非推奨とすることにより、この問題は解決されます。Javaでは、非推奨のための2つのメカニズムがサポートされています。1つは注釈(J2SE 5.0からサポートされるようになった)で、もう1つはJavadocタグ(バージョン1.1以降サポートされている)です。古いAPIに対する既存の呼出しも引き続き機能しますが、注釈により、コンパイラは非推奨のプログラム要素を参照している箇所を見つけたときに警告を発行します。Javadocタグとそれに関連したコメントは、非推奨の項目を使用しないようユーザーに警告するとともに、代わりに何を使用したらよいかを伝えます。

いつ非推奨とするか

APIを設計する際には、そのAPIが古いAPIに置き換わるものとなるかどうかを注意深く検討します。もし置き換わるものであり、新しいAPIに移行するよう開発者(APIのユーザー)に推奨する場合には、古いAPIを非推奨にします。あるAPIを非推奨にする適切な理由としては、次のようなことが考えられます。

前述のいずれの場合にも、非推奨という処置は合理的な選択です。新しいAPIに変更するよう開発者たちを促している間、「下位互換性」が保たれるからです。また、開発者たちがいつ新しいAPIへ移行するかを決定する助けとして、非推奨になった技術的理由をコメントに簡潔に含めることもできます。

非推奨にするクラスの個別のメンバー・フィールド(プロパティ)については、あるプロパティについて具体的な説明を加える場合を除いて、非推奨タグを付ける必要はありません。

非推奨とする方法

J2SE 5.0からは、クラス、メソッド、またはフィールドを非推奨にするために、@Deprecated注釈を使用できるようになりました。さらに、@deprecated Javadocタグを使用して、代わりに使用すべきものを開発者に指示することもできます。

注釈を使用すると、コンパイラは非推奨のクラス、メソッド、またはフィールドが使用されている場合に警告を生成します。非推奨項目を推奨されていないエンティティ内で使用した場合、同じもっとも外側のクラス内で使用した場合、あるいは警告を表示しないように注釈が付けられたエンティティ内で使用した場合、コンパイラは非推奨に関する警告を表示しません。

Javadocの@deprecatedタグを使用するときは、新しいAPIの使用方法を説明したコメントを添えることを強くお薦めします。これは、開発者が古いAPIから新しいAPIへの効果的な移行方法を決定する助けになります。詳細は、「@deprecated Javadocタグの使用」を参照してください。

: Java言語仕様では、@Deprecated注釈が記されたクラス、メソッド、またはフィールドが使用されたときには、コンパイラが警告を発行するよう定められています。一方、@deprecated Javadocタグでマークされたクラス、メソッド、またはフィールドが使用されたときにコンパイラが警告を発行するべきことはJava言語仕様では定められていません。もっとも、現行のSunコンパイラでは、このタグが使用されている場合でも警告は発行されます。ただし、今後もSunのコンパイラでこのような警告を発行するという保証はありません。

@Deprecated注釈の使用

J2SE 5.0では、注釈 (メタデータともいう)と呼ばれる新しい言語機能が導入されました。Java言語の組込み注釈の1つに@Deprecated注釈があります。この注釈を使用するには、クラス、メソッド、またはメンバーの宣言の前に「@Deprecated」を置くだけです。

@Deprecated注釈を使用すると、クラス、メソッド、またはフィールドが非推奨になり、コード内でそのプログラム要素が使用されている場合に、すべてのコンパイラで警告が発行されます。それに対して、@deprecated Javadocタグを使用した場合、すべてのコンパイラがそのタグに基づいて警告を発行するとはかぎりませんが、現行のSunのコンパイラは警告を発行します。他のコンパイラではそのような警告が発行されない場合もあります。したがって、@Deprecated注釈を使用して警告を生成すれば、@deprecated Javadocタグに依存するより、移植性が高くなります。

さらに、@Deprecated注釈を使用すれば、プログラム要素が表示される場所にかかわらず、javadocによって生成されたドキュメントに「Deprecated」マークが付きます。

注: 非推奨はクラスや個々のメソッドまたはプロパティに適用されるものであって、それらのプログラム要素の名前に適用されるものではありません。1つのメソッドが、非推奨のオーバーロードと「非推奨でない」オーバーロードの両方を持つことも可能です。また、「非推奨でない」プロパティが非推奨メンバーを隠したりオーバーライドしたりすることにより、非推奨を外すことも可能です。あるメソッドを非推奨にする必要がある場合、そのメソッドのオーバーライドを非推奨にすることはAPIの開発者の責任です。

次に示すのは@Deprecated注釈の簡単な使用例で、java.lang.Threadからの抜粋です。

public
class Thread implements Runnable {
...
@Deprecated
    public final void stop() {
  synchronized (this) {
...

@deprecated Javadocタグの使用

@deprecatedタグを使用すると、Javadocにより、あるプログラム要素が非推奨であることを明記できます。@deprecatedタグのあとにはスペースまたは改行を置く必要があります。@deprecatedタグに続く段落では、その項目が非推奨になった理由と、その代わりに使用すべき項目について説明します。

Javadocは、@deprecatedタグに基づいて、特別なHTMLを生成します。まず、@deprecatedタグに続く段落を説明の前に移動してイタリック体で表示し、その直前に「注: fooは非推奨です」という警告を太字で表示します。また、非推奨項目を示すインデックスのエントリに対して「非推奨です」と太字で表示します。

このタグを付けた段落に何も記述しないことも可能ですが、非推奨を示す段落を空白にするのは望ましくありません。何も記述されていないと、非推奨の機能を使用した場合に発行される警告にユーザーが対処できないからです。また、@linkタグまたは@seeタグでマークされた、同じ機能を備えた新バージョンを参照する段落を含めるようにしてください。非推奨APIの段階的廃止の予定期日を具体的に説明するのは適切ではありません。これは、他の方法で伝達するべきビジネス上の決定だからです。

@deprecated Javadocタグの使用方法の詳細は、「javadoc - Java APIドキュメント・ジェネレータ」を参照してください。

このあとの例はそれぞれ、@deprecated Javadocタグの使用方法を示しています。また、@Deprecated注釈の使用例も含まれており、この2つを一緒に使用するべきであることを強調しています。

次の例は、非推奨メソッドのもっとも一般的な記述方法です(Javadoc 1.2以降の場合)。

/**
 * @deprecated  As of release 1.3, replaced by {@link #getPreferredSize()}
 */
@Deprecated public Dimension preferredSize() {
return getPreferredSize();
}

APIの再構成が名前の変更だけではなかった場合、非推奨はより複雑になります。次に示す例では、メソッドの取消しを行なっています。

/**
 * Delete multiple items from the list.
 *
 * @deprecated  Not for public use.
 *    This method is expected to be retained only as a package
 *    private method.  Replaced by
 *    {@link #remove(int)} and {@link #removeAll()}
 */
@Deprecated public synchronized void delItems(int start, int end) {
...
}

Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.