2011-01-11 11 views
7

Ich bin kürzlich über den Javadoc für die Collection.checkedMap Familie von Funktionen zum Erstellen dynamisch typsicherer Ansichten der Standard-Collections-Typen gestolpert. Wenn man bedenkt, dass sie zusätzlich zu den Sammlungen eine weitere Sicherheitsschicht hinzufügen, die einen relativ häufigen Programmierfehler diagnostiziert, hätte ich gedacht, dass sie beliebter sein würden. Aus irgendeinem Grund habe ich sie in all den großen Java-Projekten, an denen ich gearbeitet habe, nicht einmal verwendet.Warum werden Collections.checkedMap und Freunde nicht häufiger verwendet?

Meine Frage ist dies: Gibt es einen bestimmten Grund, dass Java-Programmierer diese geprüften Wrapper nicht häufiger verwenden? Oder ist es nur Mangel an Nutzen/Mangel an Wissen über ihre Existenz?

BEARBEITEN: Um meine Frage zu klären, enthalten die generischen Versionen der Sammlungen noch typsichere Funktionen. Map 's containsKey, containsValue, remove und get alle arbeiten zum Beispiel auf Object. Meine Hauptfrage ist, dass bei diesem Typ - Unsicherheit - mehr Personen die geprüften Implementierungen nicht verwenden, um Runtime-Typ-Verletzungen zu diagnostizieren.

Antwort

13

Diese Klassen sind nur dann wirklich notwendig, wenn man Generika missbraucht (oder nicht benutzt). Sie dupliziert zur Laufzeit Duplikate, die ausreichen sollten, um zur Kompilierungszeit über die Typsicherheitsgarantien der Generics-Engine ausgeführt zu werden. Die Verwendung dieser Methoden ist daher nur im Kontext von API-Designern interessant, die den Benutzern der Bibliothek nicht vertrauen und entweder selbst oder die Benutzer vor den Benutzern schützen möchten, die die Karte nicht ordnungsgemäß verwenden .

Hier ist die Rede kurzer Sinn: Wenn Ihr Code rohen Art Warnungen oder jede unkontrollierte Umwandlung/Typ Warnungen kompiliert ohne, Sie sind garantiert, dass die checked* Methoden, die Sie nicht geben keinen Nutzen; Sie sind nur ein Runtime-Hit.

bearbeiten

Sie scheinen, dass get seit remove, werden den Abschluss, usw. arbeiten auf einem Object, sie sind irgendwie typ unsicher. Sie sind nicht. Keine dieser Methoden speichert ihren Operanden in der Karte, so dass Sie die Typsicherheit der Karte nicht gefährden. Diese Methoden nehmen ein Objekt aus einem Hauptgrund: aus Gründen der Abwärtskompatibilität. Es gab nie eine strenge Anforderung, dass Nachschlagewerke derselben Klasse angehören müssen. Wenn zum Beispiel eine Instanz der Klasse A und eine Instanz der Klasse B einander gleichwertig sein könnten, sollte a in die Map eingefügt werden und dann remove(b)aufgerufen werden, sollte die Zuordnung a entfernen.

Dieses Verhalten musste unterstützt werden, sobald Generika hinzugefügt wurden, um die Abwärtskompatibilität beizubehalten. Daher konnten sie die Schnittstelle nicht auf etwas wie remove(K) aktualisieren, da existierender Code darauf angewiesen sein könnte, eine Zuordnung zu entfernen, die eine Instanz einer vollständig anderen Klasse gegeben hat. Es ist jedoch nicht unsicher, und die Verwendung der geprüften Version der Karte ändert dieses Verhalten nicht im Geringsten.

+0

Der Hauptgrund, dass es scheint, dass es eine gute Idee sein könnte, diese Container zu haben, ist für Dinge wie Map's .put(), die ein Objekt statt ein K (zum Beispiel eine Map) nimmt ). Es scheint nicht wirklich wie ein Missbrauch von Generika zu sein, versehentlich ein Objekt des falschen Typs zu einer Karte hinzuzufügen; das ist mehr ein Programmierfehler. – templatetypedef

+2

@templatetypedef: Ich bin mir nicht sicher, was du meinst. Map's 'put' wird als' put (K, V) 'angegeben. Sie können kein altes Objekt in eine Map einfügen, wenn Sie Generika verwenden. –

+0

@Mark Peters- Mein Fehler; Ich meinte "Put", was ein "Objekt" anstatt eines "K" bedeutet. 'remove' ist genauso wie' containsKey' und 'containsValue'. – templatetypedef

0

RETRACT: Die folgende Meinung ist falsch. Abgesehen von der Rückwärtskompatibilität gibt es einige gute Gründe, warum es besser ist, einen Nachschlage-Index zu verwenden.

Es gibt keinen göttlichen Grund, warum diese Methoden Object statt E annehmen müssen. In realen Programmen, wenn ein Nicht-E-Objekt übergeben wird, ist es mit ziemlicher Sicherheit ein Anwendungsfehler.Die E-Version-API wäre in den meisten Situationen besser als die Objekt-Version. Und ich sage, Sun hat hier einen Fehler gemacht. Es gibt kein Problem mit der Rückwärtskompatibilität, da die generische API eine brandneue API ist.

Glücklicherweise würde meine IDE (IntelliJ) mich warnen, wenn ich einen Nicht-E-Typ an diese Methoden übergebe. Die statische Überprüfung wurde weit über die Sprachspezifikation und den Compiler hinaus geschoben.

+0

Ich habe nicht d/v, aber es gibt ein Abwärtskompatibilitätsproblem, und die generics collections APIs waren nicht "brandneu", sie haben die vorhandene Sammlung API nachgerüstet. –

+0

@ mark-peters die Put (K, V) auch bricht Ihre "Abwärtskompatibilität", weil die alte Methode nicht die Einschränkung hat. aber nein, es gibt keine Kompatibilitätsprobleme wie diese, weil jeder Code, der die generische Schnittstelle verwendet, neuer Code ist, und sie akzeptieren die neuen Bedingungen, und wenn sie put (K, V) akzeptieren können, können sie remove (K) akzeptieren. Eigentlich wollen alle entfernen (K) statt entfernen (Object). Jetzt gib meinen Standpunkt zurück. – irreputable

+0

Es geht nicht um eine Quellcode- oder Bytecode-Kompatibilität. Es geht um den Vertrag für 'remove (Object)' und ähnliche Methoden. Wenn sie die Sammlungen mit Generika nachgerüstet hätten, hätten sie zur Änderung von 'remove (Object)' auf 'remove (K)' die Spezifikation der Methode ändern müssen (wie in, was es * funktional * macht). –

Verwandte Themen