"Дизайн API похож на секс: сделайте одну ошибку и поддержите ее на всю оставшуюся жизнь" (Джош Блох в твиттере)суб >
В библиотеке Java много ошибок дизайна. Stack extends Vector
(обсуждение), и мы не можем исправить это, не вызывая поломки. Мы можем попытаться осудить Integer.getInteger
(обсуждение), но он, вероятно, останется навсегда.
Тем не менее, некоторые виды переоснащения могут быть выполнены без поломки.
Эффективное Java 2nd Edition, пункт 18: Предпочитает интерфейсы для абстрактных классов: существующие классы могут быть легко модифицированы для реализации нового интерфейса ".
Примеры: String implements CharSequence
, Vector implements List
и т.д.
Эффективное Java 2nd Edition, пункт 42: разумно использовать varargs: вы можете модифицировать существующий метод, который принимает массив как его последний параметр, чтобы вместо этого принимать varags, не влияя на существующих клиентов.
Известный пример (in) Arrays.asList
, который вызвал путаницу (обсуждение), но не поломка.
Этот вопрос касается другого вида переоснащения:
Можете ли вы модифицировать метод void
, чтобы вернуть что-то, не нарушая существующий код?
Моя первая догадка указывает на да, потому что:
- Тип возврата не влияет на то, какой метод выбран во время компиляции
- Смотрите: JLS 15.12.2.11 - Тип возврата не рассматривается
- Таким образом, изменение типа возвращаемого значения не изменяет, какой метод выбран компилятором
- Дооснащение из
void
, чтобы вернуть что-то, является законным (но не наоборот).
- Даже когда вы используете отражение, такие вещи, как
Class.getMethod
, не различают по типу возврата
Однако я хотел бы услышать более тщательный анализ других, более опытных в разработке Java/API.
Приложение: Мотивация
Как указано в названии, одна мотивация заключается в облегчении программирования стиля свободного интерфейса.
Рассмотрим этот простой фрагмент, который печатает перетасованный список имен:
List<String> names = Arrays.asList("Eenie", "Meenie", "Miny", "Moe");
Collections.shuffle(names);
System.out.println(names);
// prints e.g. [Miny, Moe, Meenie, Eenie]
Had Collections.shuffle(List)
объявлен для возврата списка ввода, мы могли бы написать:
System.out.println(
Collections.shuffle(Arrays.asList("Eenie", "Meenie", "Miny", "Moe"))
);
В Collections
есть другие методы, которые были бы гораздо приятнее использовать, если бы они возвращали список ввода вместо void
, например. reverse(List)
, sort(List)
и т.д. На самом деле, если Collections.sort
и Arrays.sort
return 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
, предотвращающий свободное владение, не ограничивается этими методами полезности. java.util.BitSet
также могли быть записаны для возврата this
(ala 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
, ALL мутаторов BitSet
возвращает void
.