Jon Skeet kısa süre önce blogunda ilginç bir programlama konusu gündeme getirdi: "Soyutlamamda bir boşluk var sevgili Liza, sevgili Liza" (vurgu eklenmiştir):
HashSet
Aslında bir setim var . Bazı öğeleri ondan kaldırmak istiyorum… ve öğelerin çoğu pek mevcut olmayabilir. Aslında, bizim test örneğimizde, "kaldırma" koleksiyonundaki hiçbir öğe orijinal sette olmayacak. Bu sesler - aslında ve bir son derece kolay koduna -. SonuçtaSet<T>.removeAll
bize yardım etmeliyiz , değil mi?Komut satırında "kaynak" kümesinin boyutunu ve "kaldırma" koleksiyonunun boyutunu belirleyip ikisini de oluşturuyoruz. Kaynak kümesi yalnızca negatif olmayan tam sayıları içerir; kaldırma kümesi yalnızca negatif tamsayılar içerir. Kullanarak tüm öğeleri kaldırmanın ne kadar sürdüğünü ölçüyoruz
System.currentTimeMillis()
, ki bu dünyanın en doğru kronometresi değil ama göreceğiniz gibi bu durumda fazlasıyla yeterli. İşte kod:
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"); } }
Kolay bir iş vererek başlayalım: 100 öğelik bir kaynak kümesi ve kaldırılacak 100 öğe:
c:UsersJonTest>java Test 100 100 Time taken: 1ms
Tamam, yani yavaş olmasını beklemiyorduk… açıkça işleri biraz hızlandırabiliriz. Kaldırılacak bir milyon öğe ve 300.000 öğe kaynağı nasıl olur?
c:UsersJonTest>java Test 1000000 300000 Time taken: 38ms
Hmm. Yine de oldukça hızlı görünüyor. Şimdi biraz acımasız olduğumu hissediyorum, tüm bunları kaldırmasını istedim. Bunu biraz daha kolaylaştıralım - 300.000 kaynak öğe ve 300.000 kaldırma:
c:UsersJonTest>java Test 300000 300000 Time taken: 178131ms
Affedersiniz? Yaklaşık üç dakika mı? Eyvah! Elbette , 38 ms'de yönettiğimizden daha küçük bir koleksiyondaki öğeleri çıkarmak daha kolay olmalı ?
Birisi bunun neden olduğunu açıklayabilir mi? HashSet<T>.removeAll
Yöntem neden bu kadar yavaş?