Why doesn't Java support generic Throwables?

后端 未结 5 1657
独厮守ぢ
独厮守ぢ 2020-12-14 17:02
class Bouncy extends Throwable {     
}
// Error: the generic class Bouncy may not subclass java.lang.Throwable

Why doesn\'t Java

5条回答
  •  遥遥无期
    2020-12-14 17:43

    You can still use generic methods, like this:

    public class SomeException {
        private final Object target;
    
        public SomeException(Object target) {
            this.target = target;
        }
    
        public  T getTarget() {
            return (T) target;
        }
    }
    
    ....
    
    catch (SomeException e) {
        Integer target = e.getTarget();
    }
    

    I do agree with Cristian's answer above. While the accepted answer is technically correct (insofar as it references the JVM specs), Cristian Vasile's answer is one that qualifies and even challenges the limitation.

    There are least two arguments that I noted in answers to this question that I do not agree with and that I will rebut. If the arguments in these answers were correct, we could use these arguments to attack generics in other contexts where they are used successfully today.


    The first argument states that we can't use this:

    catch (Exception e) {}
    

    because the JVM doesn't know how to work with Exception. This argument would seem to also attack this use of generics, on the basis that the JVM doesn't know how to use List:

    List list;
    

    The argument, of course, forgets that the compiler performs type erasure and so the JVM doesn't need to know how to handle Exception. It can simply handle Exception, just like it handles List.

    Of course, we could never handle catch(Exception e) and catch(Exception e) in the same try/catch because of type erasure, but then again, that's no worse than with method arguments or return values today: we don't handle myMethod(List) and myMethod(List) today either... (I reiterate this aspect in the second rebuttal below.)


    A second argument goes as follows. We don't allow this:

    catch (Exception e) {}
    

    because this wouldn't work:

    catch (Exception e) {}
    catch (Exception e) {}
    

    OK, then why not disallow this:

    interface MyInterface {
        Comparable getComparable();
    }
    

    because this does not work:

    interface MyInterface {
        Comparable getComparable();
        Comparable getComparable();
    }
    

    or this:

    interface MyInterface {
        void setComparable(Comparable comparable);
    }
    

    because this does not work:

    interface MyInterface {
        void setComparable(Comparable comparable);
        void setComparable(Comparable comparable);
    }
    

    In other words, why not disallow generics in most cases?

    This second argument forgets that, although we couldn't possibly allow different generic constructs that that erase to the same non-generic construct in these contexts, we can still do the next best thing and allow generics as long as the types don't erase to the same type. That's what we do with method parameters: we allow you to use generics, but complain as soon as we detect duplicate signatures after type erasure. Well, we could have done about the same thing with exceptions and catch blocks...


    In conclusion, I would expand on Cristian's answer. Instead of allowing generic exception classes and using the raw types in catch blocks:

    class MyException {}
    ...
    catch (MyException e) { // raw
    

    Java could have gone the whole way without problems:

    class MyException {}
    ...
    catch (MyException e) {
    

提交回复
热议问题