Jon Skeet hat kürzlich in seinem Blog ein interessantes Programmierthema angesprochen: "Es gibt ein Loch in meiner Abstraktion, liebe Liza, liebe Liza" (Hervorhebung hinzugefügt):
Ich habe ein Set - a
HashSet
, in der Tat. Ich möchte einige Elemente daraus entfernen ... und viele der Elemente sind möglicherweise nicht vorhanden. In unserem Testfall befindet sich keines der Elemente in der Sammlung "Umzüge" im Originalsatz. Das klingt - und ist - extrem einfach zu codieren. Wir müssen uns dochSet<T>.removeAll
helfen, oder?Wir geben die Größe des "Quell" -Satzes und die Größe der "Entfernungs" -Sammlung in der Befehlszeile an und erstellen beide. Der Quellensatz enthält nur nicht negative Ganzzahlen. Der Entfernungssatz enthält nur negative Ganzzahlen. Wir messen, wie lange es dauert, alle Elemente mit zu entfernen.
System.currentTimeMillis()
Dies ist nicht die genaueste Stoppuhr der Welt, aber in diesem Fall mehr als ausreichend, wie Sie sehen werden. Hier ist der Code:import java.util.*; public class Test { public static void main(String[] args) { int sourceSize = Integer.parseInt(args[0]); int removalsSize = Integer.parseInt(args[1]); Set<Integer> source = new HashSet<Integer>(); Collection<Integer> removals = new ArrayList<Integer>(); for (int i = 0; i < sourceSize; i++) { source.add(i); } for (int i = 1; i <= removalsSize; i++) { removals.add(-i); } long start = System.currentTimeMillis(); source.removeAll(removals); long end = System.currentTimeMillis(); System.out.println("Time taken: " + (end - start) + "ms"); } }
Beginnen wir mit einer einfachen Aufgabe: einem Quellensatz von 100 Elementen und 100 zu entfernenden Elementen:
c:UsersJonTest>java Test 100 100 Time taken: 1ms
Okay, wir hatten also nicht erwartet, dass es langsam wird ... klar, wir können die Dinge ein wenig beschleunigen. Wie wäre es mit einer Quelle von einer Million Gegenständen und 300.000 zu entfernenden Gegenständen?
c:UsersJonTest>java Test 1000000 300000 Time taken: 38ms
Hmm. Das scheint immer noch ziemlich schnell zu sein. Jetzt fühle ich mich ein bisschen grausam und habe es gebeten, all das zu entfernen. Machen wir es uns etwas einfacher - 300.000 Quellelemente und 300.000 Entfernungen:
c:UsersJonTest>java Test 300000 300000 Time taken: 178131ms
Entschuldigen Sie? Fast drei Minuten ? Huch! Sicherlich sollte es einfacher sein, Gegenstände aus einer kleineren Sammlung zu entfernen als die, die wir in 38 ms verwaltet haben?
Kann jemand erklären, warum dies geschieht? Warum ist die HashSet<T>.removeAll
Methode so langsam?