いつ、どのように 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 は推奨されません。」という警告を太字で表示します。Javadoc はまた、非推奨項目を示すインデックスのエントリに対して「推奨されません。」と太字で表示します。

このタグを付けた段落に何も記述しないことも可能ですが、非推奨を示す段落を空白にするのは望ましくありません。何も記述されていないと、非推奨の機能を使用した場合に発行される警告にユーザーが対処できないからです。また、同じ機能を備えた新バージョンを参照する @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, 2013, Oracle and/or its affiliates. All rights reserved.