Frage

class Bouncy<T> extends Throwable {     
}
// Error: the generic class Bouncy<T> may not subclass java.lang.Throwable

Warum funktioniert Java-Unterstützung generic Throwables?

merke ich, dass Typ Löschung bestimmte Dinge kompliziert, aber offensichtlich Java wird durch mit viel schon, also warum es nicht schiebt eine weitere Kerbe und erlaubt generische Throwables, mit ausführlichem Kompilierung-Check für potenzielle Probleme?


Ich fühle mich wie der Typ Löschung Argument eher schwach ist. Derzeit können wir nicht tun:

void process(List<String> list) {
}

void process(List<Integer> list) {
}

Natürlich bekommen wir ohne sie. Ich verlangen nicht, dass wir in der Lage sein sollten catch Bouncy<T1> und Bouncy<T2> im gleichen try Block zu tun, aber wenn wir sie in disjunkten Kontexten mit strengen Kompilierung-durchsetzbaren Regeln verwenden (was ziemlich die Art und Weise Generika funktioniert jetzt), wouldn ‚t es praktikabel sein?

War es hilfreich?

Lösung

Java Language Specification 8.1.2 Allgemeinklassen und Typparameter :

  

Diese Einschränkung erforderlich ist, da der Rastmechanismus der virtuellen Java-Maschine nur mit nicht-generischen Klassen funktioniert.

Ich persönlich denke, es ist, weil wir keine Vorteile von Generika innerhalb einer catch Klausel bekommen. Wir können nicht Schreib catch (Bouncy<String> ex) aufgrund Typ Löschung, aber wenn wir catch (Bouncy ex) schreiben, wäre es nutzlos sein, um es generische zu machen.

Andere Tipps

Typ Löschung. Runtime Ausnahmetyp hat keine Generika Informationen. So Sie nicht tun

} catch( Mistake<Account> ea) {
  ...
} catch( Mistake<User> eu) {
...
}

alle können Sie

catch( Mistake ea ) {
  ...
}

Und Typ Löschung ist, wie es beschlossen wurde, die Abwärtskompatibilität zu erhalten, wenn Java wurde von 1,4 bis 1,5 bewegt. Viele Menschen unglücklich war dann, und das zu Recht. Aber unter Berücksichtigung der Tatsache war es, die Menge des eingesetzten Code, es undenkbar, Code zu brechen, die glücklich arbeiteten in 1.4.

Kurze Antwort:., Weil sie Verknüpfungen nahm, so wie sie mit Lösch tat

Lange Antwort:. Wie andere schon angedeutet, wegen der Löschung, gibt es keine Möglichkeit, einen Unterschied zur Laufzeit zwischen einer „catch MyException “ und „Fang MyException “ zu machen

Aber das bedeutet nicht, dass es keine Notwendigkeit für die allgemeinen Ausnahmen . Ich möchte Generika Generika Felder verwenden können! Sie konnten einfach generische Ausnahmen erlaubt, aber nur damit sie im Rohzustand (beispielsweise „Fang MyException“) zu kontrollieren.

Zugegeben, dies würde Generika noch komplizierter. Dies ist nur zu zeigen, wie schlecht die Entscheidung Lösch Generika war. Wann werden wir eine Java-Version, dass unterstützt echter Generika (mit RTTI), nicht dem aktuellen syntaktischen Zucker?

Sie können immer noch generische Methoden verwenden, wie folgt aus:

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();
}

ich stimme mit Cristian Antwort oben. Während die akzeptierte Antwort technisch korrekt ist (soweit es die JVM-Spezifikationen verweist), ist Cristian Vasile Antwort ein, dass qualifiziert und fordert auch die Begrenzung.

Es gibt mindestens zwei Argumente, dass ich in Antworten auf diese Frage stellte fest, dass ich nicht einverstanden bin mit und dass ich entkräften. Wenn die Argumente in diesen Antworten richtig waren, können wir diese Argumente verwenden Generika in anderen Kontexten zu attackieren, wo sie heute erfolgreich eingesetzt werden.


Das erste Argument besagt, dass wir das nicht verwenden können:

catch (Exception<T1> e) {}

, weil die JVM nicht weiß, wie mit Exception<T1> zu arbeiten. Dieses Argument scheint auch diese Verwendung von Generika zu attackieren, auf der Grundlage, dass die JVM nicht weiß, wie List<T1> verwenden:

List<T1> list;

Das Argument, natürlich, vergisst, dass der Compiler führt Typ Löschung und so die JVM braucht nicht zu wissen, wie Exception<T1> zu behandeln. Es kann einfach Exception handhaben, wie es behandelt List.

Natürlich könnten wir nie wegen Typ Löschung catch(Exception<T1> e) und catch(Exception<T2> e) im gleichen try / catch behandeln, aber dann wieder, das ist nicht schlechter als mit der Methode Argumenten oder Rückgabewerten heute: Wir myMethod(List<T1>) und myMethod(List<T2>) nicht verarbeiten heute entweder ... (ich wiederhole diesen Aspekt in der zweiten Widerlegung unten).


Ein zweites Argument geht folgt wie. Wir tun dies nicht zulassen:

catch (Exception<T1> e) {}

, weil diese nicht funktionieren würde:

catch (Exception<T1> e) {}
catch (Exception<T2> e) {}

OK, dann, warum dies nicht nicht zulassen:

interface MyInterface {
    Comparable<Integer> getComparable();
}

, weil dieses nicht funktioniert :

interface MyInterface {
    Comparable<Integer> getComparable();
    Comparable<String> getComparable();
}

oder folgt aus:

interface MyInterface {
    void setComparable(Comparable<Integer> comparable);
}

, weil dieses nicht funktioniert :

interface MyInterface {
    void setComparable(Comparable<Integer> comparable);
    void setComparable(Comparable<String> comparable);
}

Mit anderen Worten, warum nicht disallow Generika in den meisten Fällen?

Das zweite Argument vergisst, dass, obwohl wir nicht möglicherweise verschiedene generische Konstrukte ermöglichen könnten, dass das Lösch auf das gleiche nicht-generische Konstrukt in diesen Kontexten, können wir immer noch die nächste beste Sache tun und erlaubt Generika solange die Typen Sie auf die gleiche Art nicht löschen . Das ist, was wir mit Methodenparameter zu tun: wir ermöglichen es Ihnen Generika zu verwenden, aber beschweren, sobald wir doppelte Signaturen nach Typ Löschung erkennen. Nun, wir über die gleiche Sache mit Ausnahmen und Catch-Blöcke getan haben könnte ...


Abschließend möchte ich auf Cristian Antwort erweitern. Statt allgemeine Ausnahmeklassen erlauben und mit den rohen Typen in catch Blöcke:

class MyException<T> {}
...
catch (MyException e) { // raw

Java den ganzen Weg haben könnte ohne Probleme weg:

class MyException<T> {}
...
catch (MyException<Foo> e) {

Hier sind ein paar Dinge, die Sie können tun:

  1. Throwables können generische Schnittstellen implementieren, solange die throwable selbst keine Typparameter hat, zum Beispiel

      

    interface Bouncy<E> {
          // ...
      }
      class BouncyString extends Exception implements Bouncy<String> {
          // ...
      }

  2.   
  3. A throws Klausel kann sich beziehen Parameter eingeben, zum Beispiel
      static <X extends Throwable> void
      throwIfInstanceOf(Throwable ex, Class<X> clazz) throws X {
          if (clazz.isInstance(ex)) throw clazz.cast(ex);
      }   
  4.   

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top