2016-05-30 15 views
0

Artikel 23 (Sie rohe Typen nicht in neuem Code verwenden) von Effective Java behaupten, dass rohe Typen in Java-Code verwendet immer gefährlich istSind rohe Typen immer schlecht?

Zum Beispiel behauptet, dass die folgende Methode gefährlich und unsicher ist

// Use of raw type for unknown element type - don't do this! 
static int numElementsInCommon(Set s1, Set s2) { 
    int result = 0; 
    for (Object o1 : s1) 
     if (s2.contains(o1)) 
      result++; 
    return result; 
} 

Obwohl ich sehen kann, dass jede Art von Schreibvorgang oder Klasse Cast Operation auf s1 und s2 zu allen Arten von Ausnahmen führen kann, verstehe ich nicht, warum die oben genannte Methode unsicher ist. Autor Joshua Bloch fährt fort, stattdessen die folgende Methode zu empfehlen.

// Unbounded wildcard type - typesafe and flexible 
static int numElementsInCommon(Set<?> s1, Set<?> s2){ 
    int result = 0; 
    for (Object o1 : s1) 
    if (s2.contains(o1)) 
     result++; 
    return result; 
} 

Mit anderen Worten, wenn ein Verfahren nur die Methoden der Object.Class verwendet und machen keine Änderungen an den Parametern, die vergangen sind, warum ist es schlecht?

+3

In der Vergangenheit, vor Generika, Menschen würden ** Typen in den Sammlungen des Tages (nämlich 'Hashtable' und' Vector', die zu dieser Zeit keine Sammlungen waren) ** mischen. Das führte zu Dingen wie '[0," abc ", Date]', was ein Hack ist (weil Java dir erlaubt, deine eigenen Datentypen zu erstellen). Mit 'Set ' haben Sie garantiert einen konsistenten Elementtyp. –

+0

Sicher. Meine Frage ist, sind raw-Typ unsicher im Fall von schreibgeschützten Methoden oder Operationen, die nur Methoden von ** Object.Class ** –

+0

ausgesetzt sind Nein, sie sind nicht. Zur Laufzeit sind alle Typen unformatiert, und sie tun genau dasselbe wie die empfohlene Methode mit den Platzhaltern. Aber diese Methode lässt den Compiler überprüfen, dass Sie nichts anderes tun als diese "sicheren Dinge". Ohne die Joker-Karte erhalten Sie keinen Fehler, wenn Sie beispielsweise versehentlich zu Ihrem Set hinzufügen. Verwenden Sie also entweder den generischen Typ, wenn Sie ihn kennen, oder den Platzhalter, wenn Sie es nicht wissen. Verwenden Sie keine Rohtypen. – Thilo

Antwort

2

Es ist in dem Sinne schlecht, dass es verhindert, dass der Compiler mehr von Ihrem Code typisiert.

Natürlich können Sie guten und sicheren Code ohne es schreiben. Die Leute machen es jeden Tag in Perl und Javascript. Und selbst in Java gibt es keinen Unterschied zwischen der Verwendung von Rohtypen und der Verwendung typisierter Auflistungen zur Laufzeit. Aber es gibt etwas, das gesagt werden kann, damit ein Compiler so viel wie möglich für Sie prüft.

Verwenden Sie also bei einer Methode wie in Ihrem Beispiel anstelle von unformatierten Typen Platzhalter (Set<?>). Wenn Sie "gefährlichen" Code wie s1.addAll(s2); schreiben, ruft der Compiler Sie an.

+0

Sinn macht. Ich bin überrascht, dass die Capture-Einschränkungen von der Schnittstelle in den untergeordneten Klassen nicht erzwungen werden. Siehe https://gist.github.com/dsKarthick/e6b1b62c70f3722b13d9047aa338b8c2 zum Beispiel. –

+0

Ich denke, dass Sie eine Compiler-Warnung über unformatierte Typen in der untergeordneten Klasse erhalten. Und wenn Sie Typen verwenden, müssen sie mit der übergeordneten Schnittstelle übereinstimmen. – Thilo

+0

Der Grund, warum Sie sogar rohe Typen für die untergeordnete Klasse (oder irgendwo in Java, wirklich) verwenden dürfen, ist Rückwärtskompatibilität mit altem Code vor Java5. Wenn Sie jedoch Typen verwenden, werden sie ordnungsgemäß erzwungen. – Thilo