Вы все еще можете использовать универсальные методы, например:
public class SomeException {
private final Object target;
public SomeException(Object target) {
this.target = target;
}
public <T> T getTarget() {
return (T) target;
}
}
....
catch (SomeException e) {
Integer target = e.getTarget();
}
Я согласен с ответом Кристиана выше. Хотя принятый ответ является технически правильным (поскольку он ссылается на спецификации JVM), ответ Кристиана Василе - тот, который квалифицирует и даже оспаривает ограничение.
Есть как минимум два аргумента, которые я отметил в ответах на этот вопрос, с которыми я не согласен и которые я опровергну. Если аргументы в этих ответах были правильными, мы могли бы использовать эти аргументы для атаки на дженерики в других контекстах, где они сегодня успешно используются.
Первый аргумент утверждает, что мы не можем использовать это:
catch (Exception<T1> e) {}
потому что JVM не знает, как работать с Exception<T1>
. Этот аргумент, по-видимому, также атакует использование дженериков на том основании, что JVM не знает, как использовать List<T1>
:
List<T1> list;
Аргумент, конечно, забывает, что компилятор выполняет стирание типов, и поэтому JVM не нужно знать, как обрабатывать Exception<T1>
. Он может просто обрабатывать Exception
, так же, как он обрабатывает List
.
Конечно, мы никогда не сможем обработать catch(Exception<T1> e)
и catch(Exception<T2> e)
в одном и том же try / catch из-за стирания типа, но опять же, это не хуже, чем с аргументами метода или возвращаемыми значениями сегодня: мы не обрабатываем 1024 * и myMethod(List<T2>)
сегодня либо ... (я повторяю этот аспект во втором опровержении ниже.)
Второй аргумент выглядит следующим образом. Мы этого не допустим:
catch (Exception<T1> e) {}
потому что это не сработает:
catch (Exception<T1> e) {}
catch (Exception<T2> e) {}
Хорошо, тогда почему бы не запретить это:
interface MyInterface {
Comparable<Integer> getComparable();
}
потому что это не работает :
interface MyInterface {
Comparable<Integer> getComparable();
Comparable<String> getComparable();
}
или это:
interface MyInterface {
void setComparable(Comparable<Integer> comparable);
}
потому что это не работает :
interface MyInterface {
void setComparable(Comparable<Integer> comparable);
void setComparable(Comparable<String> comparable);
}
Другими словами, почему бы не запретить генерики в большинстве случаев?
Этот второй аргумент забывает, что, хотя мы не можем допустить использования различных универсальных конструкций, которые стирают в одну и ту же неуниверсальную конструкцию в этих контекстах, мы все равно можем делать следующую лучшую вещь и разрешать генерики до тех пор, пока типы не стираются в один и тот же тип . Это то, что мы делаем с параметрами метода: мы разрешаем вам использовать дженерики, но жалуемся, как только мы обнаруживаем дубликаты подписей после стирания типа. Ну, мы могли бы сделать то же самое с исключениями и блоками перехвата ...
В заключение я бы остановился на ответе Кристиана. Вместо разрешения общих классов исключений и с использованием необработанных типов в блоках catch
:
class MyException<T> {}
...
catch (MyException e) { // raw
Java мог бы пройти весь путь без проблем:
class MyException<T> {}
...
catch (MyException<Foo> e) {