String
Java では不変です。次のスニペットは、大まかに言えば「間違っています」。
String s = "hello world!";
s.toUpperCase(); // "wrong"!!
System.out.println(s); // still "hello world!"!!!
これは「間違っている」にもかかわらず、コードはコンパイルされて実行されます。おそらく多くの初心者は、間違いが何であるかを説明するか、ドキュメントを参照して自分で調べる必要があるため、混乱します。
ドキュメントを読むことは API を理解する上で不可欠ですが、コンパイル時のチェックを追加することでこれを補うことができるかどうか疑問に思っています。特に、Java の注釈フレームワークを使用して、特定のメソッドによって返される値が無視されないようにすることができるのではないかと考えています。API 設計者/ライブラリ作成者は、メソッドでこの注釈を使用して、どの戻り値を無視してはならないかを文書化します。
API がこの注釈 (またはおそらく別のメカニズム) で補足されると、ユーザーが上記のようなコードを記述しても、コンパイルされません (または厳しい警告が表示されます)。
それで、これを行うことができますか?
付録: 動機
一般的なケースでは、Javaがメソッドの戻り値を無視できるようにする必要があることは明らかです。List.add
( always true
)、 (previous value)などのメソッドの戻り値はSystem.setProperty
、ほとんどの場合、おそらく安全に無視できます。
ただし、戻り値を無視してはならないメソッドも多数あります。そうすることは、ほとんどの場合、プログラマーのエラーであるか、API の適切な使用法ではありません。これらには次のようなものが含まれます。
- 呼び出されたインスタンスを変更するのではなく、操作の結果を返す不変型 (
String
、BigInteger
など) のメソッド。 - 戻り値が動作の重要な部分であり、無視されるべきではないメソッドですが、とにかく無視する人もいます (たとえば
InputStream.read(byte[])
、読み取られたバイト数を返します。これは、配列の全長であると想定されるべきではありません)。
現在、これらの戻り値を無視するコードを記述して、警告なしでコンパイルおよび実行することができます。静的分析チェッカー / バグ ファインダー / スタイル エンフォーサー / などは、ほぼ確実にこれらをコードの匂いの可能性としてフラグを立てることができますが、これが API 自体によって、おそらく注釈を通じて強制される場合は、適切/理想的であるように思われます。
クラスが常に「適切に」使用されることを保証することはほとんど不可能ですが、クライアントを適切に使用するように導くためにできることはあります (効果的な Java 2nd Edition、項目 58: 回復可能な条件にはチェック済みの例外を使用し、プログラミング エラーの実行時例外と項目 62: 各メソッドによってスローされたすべての例外を文書化します)。クライアントが特定のメソッドの戻り値を無視しないように強制する注釈を持ち、コンパイル時にエラーまたは警告の形でコンパイラによって強制されるようにすることは、この考えに沿っているようです。
付録 2: スニペット
以下は、私が達成したいことを簡潔に説明する予備的な試みです。
@interface Undiscardable { }
//attachable to methods to indicate that its
//return value must not be discarded
public class UndiscardableTest {
public static @Undiscardable int f() {
return 42;
}
public static void main(String[] args) {
f(); // what do I have to do so this generates
// compilation warning/error?
System.out.println(f()); // this one would be fine!
}
}
上記のコードは正常にコンパイルおよび実行されます ( ideone.com で見られるように)。そうならないようにするにはどうすればいいですか?必要なセマンティクスをどのように割り当てることができ@Undiscardable
ますか?