2012-10-06 8 views
8

Ich postete einen Code here, die ein Problem, das das Plakat hatte, richtig gelöst hat. OP wollte Duplikate entfernen und bestimmte Sonderelemente an die Spitze einer Liste bringen. Ich benutzte eine TreeSet mit einer speziellen Comparable Klasse, die die Locale wickelte, mit denen sie arbeiteten, um zu erreichen, was sie wollten.Gleich und vergleichbar mit Sets

Ich habe dann zu denken ... wie Sie tun ... dass ich Duplikate wurde eliminiert durch 0 aus der compareTo Methode Rückkehr nicht durch true von einer equals Implementierung Rückkehr als eine richtig ein Duplikat angeben tun müßten in einer Set (aus der definition einer Set).

Ich habe keine Einwände gegen die Verwendung dieser Technik, aber verwende ich, was könnte eine undokumentierte Funktion? Kann ich davon ausgehen, dass es auch weiterhin funktionieren wird, wenn man so etwas tut?

+0

Wie Herr Nurkiewicz weist darauf hin, dieses Verhalten festgelegt ist, so dass es sicher ist. Ich stimme zu, dass es aber überraschend ist! –

Antwort

17

Es scheint, wie dies ziemlich gut in JavaDoc of TreeSet (fett Mine) dokumentiert:

Beachten Sie, dass die Bestellung durch einen Satz beibehalten (mit oder ohne eine explizite Komparator vorgesehen ist) müssen konsistent sein mit gleich wenn es die Set Schnittstelle korrekt implementieren soll. (Siehe Comparable oder Comparator für eine genaue Definition im Einklang mit Gleichgestellten.) Dies ist so, weil die Set Schnittstelle in Bezug auf die equals Operation definiert ist, sondern eine TreeSet Instanz führt all Element Vergleiche mit seiner compareTo (oder vergleichen) Methode, also sind zwei Elemente, die durch diese Methode als gleich angesehen werden, vom Standpunkt der Menge her gleich. Das Verhalten einer Menge ist wohldefiniert, auch wenn ihre Reihenfolge nicht mit Gleichem übereinstimmt; es entspricht nur nicht dem allgemeinen Vertrag der Set Schnittstelle. Hier

ist ein Beispiel für die only (?) JDK class die Comparable implementiert, ist aber nicht im Einklang mit equals():

Set<BigDecimal> decimals = new HashSet<BigDecimal>(); 
decimals.add(new BigDecimal("42")); 
decimals.add(new BigDecimal("42.0")); 
decimals.add(new BigDecimal("42.00")); 
System.out.println(decimals); 

decimals am Ende haben drei Werte, weil 42, 42.0 und 42.00 nicht gleich so weit wie equals() ist besorgt. Aber wenn Sie HashSet durch TreeSet ersetzen, enthält die resultierende Menge nur 1 Element (42 - das zufällig die erste hinzugefügt wurde), da alle von ihnen als gleich betrachtet werden, wenn sie mit BigDecimal.compareTo() verglichen werden.

Dies zeigt, dass TreeSet in einer Art und Weise „ gebrochen“ ist, wenn Arten nicht im Einklang mit equals() verwenden. Es funktioniert immer noch ordnungsgemäß und alle Operationen sind gut definiert - es entspricht nicht dem Vertrag der Klasse Set - wenn zwei Klassen nicht equal() sind, werden sie nicht als Duplikate betrachtet.

Siehe

auch
+0

Interessanterweise gibt es keinen solchen Kommentar in den 'ConcurrentSkipListSet'-Dokumenten. – OldCurmudgeon

+1

@OldCurmudgeon Es ist tatsächlich auch im [javadoc von SortedSet] (http://docs.oracle.com/javase/7/docs/api/java/util/SortedSet.html) angegeben (und sowohl TreeSet als auch ConcurrentSkipListSet implementieren das) Schnittstelle). – assylias

+0

So tut es !! Guter Fang. – OldCurmudgeon