Why doesn't Java allow generic subclasses of Throwable?
26638 просмотра
5 ответа
According to the Java Language Sepecification, 3rd edition:
It is a compile-time error if a generic class is a direct or indirect subclass of
Throwable
.
I wish to understand why this decision has been made. What's wrong with generic exceptions?
(As far as I know, generics are simply compile-time syntactic sugar, and they will be translated to Object
anyway in the .class
files, so effectively declaring a generic class is as if everything in it was an Object
. Please correct me if I'm wrong.)
Ответы (5)
149 плюса
As mark said, the types are not reifiable, which is a problem in the following case:
try {
doSomeStuff();
} catch (SomeException<Integer> e) {
// ignore that
} catch (SomeException<String> e) {
crashAndBurn()
}
Both SomeException<Integer>
and SomeException<String>
are erased to the same type, there is no way for the JVM to distinguish the exception instances, and therefore no way to tell which catch
block should be executed.
14 плюса
Here is a simple example of how to use the exception:
class IntegerExceptionTest {
public static void main(String[] args) {
try {
throw new IntegerException(42);
} catch (IntegerException e) {
assert e.getValue() == 42;
}
}
}
The body of the TRy statement throws the exception with a given value, which is caught by the catch clause.
In contrast, the following definition of a new exception is prohibited, because it creates a parameterized type:
class ParametricException<T> extends Exception { // compile-time error
private final T value;
public ParametricException(T value) { this.value = value; }
public T getValue() { return value; }
}
An attempt to compile the above reports an error:
% javac ParametricException.java
ParametricException.java:1: a generic class may not extend
java.lang.Throwable
class ParametricException<T> extends Exception { // compile-time error
^
1 error
This restriction is sensible because almost any attempt to catch such an exception must fail, because the type is not reifiable. One might expect a typical use of the exception to be something like the following:
class ParametricExceptionTest {
public static void main(String[] args) {
try {
throw new ParametricException<Integer>(42);
} catch (ParametricException<Integer> e) { // compile-time error
assert e.getValue()==42;
}
}
}
This is not permitted, because the type in the catch clause is not reifiable. At the time of this writing, the Sun compiler reports a cascade of syntax errors in such a case:
% javac ParametricExceptionTest.java
ParametricExceptionTest.java:5: <identifier> expected
} catch (ParametricException<Integer> e) {
^
ParametricExceptionTest.java:8: ')' expected
}
^
ParametricExceptionTest.java:9: '}' expected
}
^
3 errors
Because exceptions cannot be parametric, the syntax is restricted so that the type must be written as an identifier, with no following parameter.
Автор: IAdapter Размещён: 01.02.2009 06:1113 плюса
It's essentially because it was designed in a bad way.
This issue prevents clean abstract design e.g.,
public interface Repository<ID, E extends Entity<ID>> {
E getById(ID id) throws EntityNotFoundException<E, ID>;
}
The fact that a catch clause would fail for generics are not reified is no excuse for that. The compiler could simply disallow concrete generic types that extend Throwable or disallow generics inside catch clauses.
Автор: Michele Sollecito Размещён: 09.02.2015 11:214 плюса
Generics are checked at compile-time for type-correctness. The generic type information is then removed in a process called type erasure. For example, List<Integer>
will be converted to the non-generic type List
.
Because of type erasure, type parameters cannot be determined at run-time.
Let's assume you are allowed to extend Throwable
like this:
public class GenericException<T> extends Throwable
Now let's consider the following code:
try {
throw new GenericException<Integer>();
}
catch(GenericException<Integer> e) {
System.err.println("Integer");
}
catch(GenericException<String> e) {
System.err.println("String");
}
Due to type erasure, the runtime will not know which catch block to execute.
Therefore it is a compile-time error if a generic class is a direct or indirect subclass of Throwable.
Source: Problems with type erasure
Автор: outdev Размещён: 30.09.2017 11:352 плюса
I would expect that it's because there's no way to guarantee the parameterization. Consider the following code:
try
{
doSomethingThatCanThrow();
}
catch (MyException<Foo> e)
{
// handle it
}
As you note, parameterization is just syntactic sugar. However, the compiler tries to ensure that parameterization remains consistent across all references to an object in compilation scope. In the case of an exception, the compiler has no way to guarantee that MyException is only thrown from a scope that it is processing.
Автор: kdgregory Размещён: 01.02.2009 06:12Вопросы из категории :
- java В чем разница между int и Integer в Java и C #?
- java Как я могу определить IP моего маршрутизатора / шлюза в Java?
- java Каков наилучший способ проверки XML-файла по сравнению с XSD-файлом?
- java Как округлить результат целочисленного деления?
- java Преобразование списка <Integer> в список <String>
- generics Почему в C # нельзя хранить объект List <string> в переменной List <object>
- generics Преобразование общего типа из строки
- generics Лучший способ проверить, является ли универсальный тип строкой? (С #)
- generics Есть ли ограничение, которое ограничивает мой общий метод численными типами?
- generics Каковы различия между «универсальными» типами в C ++ и Java?
- exception Неужели так плохо поймать общее исключение?
- exception Когда выбирать отмеченные и непроверенные исключения
- exception Возвращаясь из блока finally в Java
- exception Как сбросить InnerException без потери трассировки стека в C #?
- exception Когда для конструктора правильно выбрасывать исключение?
- language-design Почему я не могу иметь абстрактные статические методы в C #?
- language-design Почему переменные не объявлены в «try» в области «catch» или «finally»?
- language-design Почему оператор switch был предназначен для перерыва?
- language-design Почему имена переменных не могут начинаться с цифр?
- language-design Почему Java не поддерживает целые числа без знака?