「API の設計はセックスのようなものです。1 つの間違いを犯すと、残りの人生をサポートすることができます」 ( Twitter の Josh Bloch )
Java ライブラリには多くの設計ミスがあります。Stack extends Vector
(ディスカッション)、破損を引き起こさずにそれを修正することはできません。廃止しようとすることはできますがInteger.getInteger
(議論)、おそらく永遠に残るでしょう。
それにもかかわらず、特定の種類のレトロフィットは、破損することなく行うことができます。
効果的な Java 2nd Edition、項目 18: 抽象クラスよりもインターフェイスを優先する: 既存のクラスは、新しいインターフェイスを実装するために簡単に改造できます。
例: String implements CharSequence
、Vector implements List
など
有効な Java 2nd Edition、項目 42: varargs を慎重に使用する: 既存のクライアントに影響を与えずに、最終パラメーターとして配列を受け取る既存のメソッドを改造して、代わりに varags を使用できます。
(悪名高い) 有名な例はArrays.asList
、混乱 (議論) を引き起こしましたが、破損は引き起こしませんでした。
この質問は、別の種類の改造に関するものです。
void
既存のコードを壊さずに何かを返すようにメソッドを改良できますか?
私の最初の予感はイエスです。
- 戻り値の型は、コンパイル時に選択されるメソッドには影響しません
- 参照: JLS 15.12.2.11 - 戻り型は考慮されない
- したがって、戻り値の型を変更しても、コンパイラによって選択されるメソッドは変更されません。
- を改造し
void
て何かを返すことは合法です (ただし、その逆はできません!)
- リフレクションを使っても
Class.getMethod
返り値の型が区別されないなど
ただし、Java/API 設計の経験が豊富な他の人による、より徹底的な分析を聞きたいと思っています。
付録: 動機
タイトルで示唆されているように、1 つの動機は流暢なインターフェイススタイルのプログラミングを容易にすることです。
シャッフルされた名前のリストを出力するこの単純なスニペットを考えてみましょう:
List<String> names = Arrays.asList("Eenie", "Meenie", "Miny", "Moe");
Collections.shuffle(names);
System.out.println(names);
// prints e.g. [Miny, Moe, Meenie, Eenie]
入力リストを返すCollections.shuffle(List)
ように宣言されていた場合、次のように記述できます。
System.out.println(
Collections.shuffle(Arrays.asList("Eenie", "Meenie", "Miny", "Moe"))
);
の代わりに、などCollections
の入力リストを返すと、はるかに快適に使用できるメソッドが他にもあります。実際、とreturnを持つことは特に不幸です。このように:void
reverse(List)
sort(List)
Collections.sort
Arrays.sort
void
// DOES NOT COMPILE!!!
// unless Arrays.sort is retrofitted to return the input array
static boolean isAnagram(String s1, String s2) {
return Arrays.equals(
Arrays.sort(s1.toCharArray()),
Arrays.sort(s2.toCharArray())
);
}
もちろん、流暢さを妨げているこのvoid
戻り値の型は、これらのユーティリティ メソッドだけに限定されているわけではありません。メソッドは、流暢さを促進するために(alaおよび) をjava.util.BitSet
返すように作成することもできます。this
StringBuffer
StringBuilder
// we can write this:
StringBuilder sb = new StringBuilder();
sb.append("this");
sb.append("that");
sb.insert(4, " & ");
System.out.println(sb); // this & that
// but we also have the option to write this:
System.out.println(
new StringBuilder()
.append("this")
.append("that")
.insert(4, " & ")
); // this & that
// we can write this:
BitSet bs1 = new BitSet();
bs1.set(1);
bs1.set(3);
BitSet bs2 = new BitSet();
bs2.flip(5, 8);
bs1.or(bs2);
System.out.println(bs1); // {1, 3, 5, 6, 7}
// but we can't write like this!
// System.out.println(
// new BitSet().set(1).set(3).or(
// new BitSet().flip(5, 8)
// )
// );
残念ながら、StringBuilder
/とは異なりStringBuffer
、すべてのBitSet
ミューテーターは を返しvoid
ます。