Ответ 1
Алмазный оператор не всегда может использоваться в Java 8. Первоначальный план улучшения вывода в Java 8 (JEP 101) имел два цели:
- Добавить поддержку вывода метода-типа в контексте метода
- Добавить поддержку вывода типа метода в цепочку вызовов
Выполнено только первое. Заимствуя пример из JEP, рассмотрим следующий класс:
class List<E> {
static <Z> List<Z> cons(Z head, List<Z> tail) { ... };
E head() { ... }
}
В Java 8 улучшенный вывод контекста метода позволяет компилировать следующее. С Java 7 он потерпит неудачу с ошибкой expected List<Integer>, found List<Object>
List<Integer> l = List.cons(42, new List<>());
Однако примеры, требующие вывода цепочных вызовов, по-прежнему не работают с Java 8:
Integer i = new List<>().head();
Раздел D JSR 335 включает в себя подсказку о том, почему принудительный вывод выражения был оставлен для Java 8:
Была некоторая заинтересованность в разрешении вывода "chain": in a(). b(), передавая информацию о типе от вызова b к вызову a. Это добавляет еще одно измерение сложности алгоритма вывода, поскольку частичная информация должна проходить в обоих направлениях; он работает только тогда, когда стирание возвращаемого типа a() фиксировано для всех экземпляров (например, List). Эта особенность не очень хорошо вписывается в модель выражения poly, так как тип цели не может быть легко получен; но, возможно, с дополнительными улучшениями, которые могут быть добавлены в будущем.
Есть еще несколько надуманных примеров, когда алмаз нельзя использовать.
Если подсчет ошибок, это не компилируется с javac до jdk8u25. (см. JDK-8029002)
class Test {
class C<T extends C<T>> {}
void m() {
C<?> i = new C<>();
}
}
error: incompatible types: cannot infer type arguments for Test.C<>
C<?> i = new C<>();
^
reason: inferred type does not conform to upper bound(s)
inferred: Test.C<CAP#1>
upper bound(s): Test.C<Test.C<CAP#1>>,Test.C<CAP#1>
where CAP#1 is a fresh type-variable:
CAP#1 extends Test.C<CAP#1> from capture of ?
Также существует проблема с производительностью (JDK-8051946) с новой реализацией вывода типа, которая может повлиять на код с использованием оператора алмаза. Следующий пример требует минут для компиляции, если используется оператор алмаза.
class Test {
<T> T and(T a, T b) { return null; }
class C<T> {}
void g(String s) {}
void g(Object s) {}
void m() {
g(
and(
and(
and(
and(
and(
and(
and(new C<>(),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()));
}
}