Jon Skeetは最近彼のブログで興味深いプログラミングトピックを取り上げました:「私の抽象化には、穴があります。
私はセットを持っています–
HashSet
実際、。いくつかのアイテムを削除したいのですが、アイテムの多くが存在しない可能性があります。実際、私たちのテストケースでは、「removals」コレクションの項目はいずれも元のセットには含まれません。これは、実際にコーディングが非常に簡単に聞こえます。結局のところ、私たちはSet<T>.removeAll
私たちを助ける必要がありますよね?「ソース」セットのサイズと「削除」コレクションのサイズをコマンドラインで指定し、両方をビルドします。ソースセットには負でない整数のみが含まれています。削除セットには負の整数のみが含まれています。を使用してすべての要素を削除するのにかかる時間を測定します
System.currentTimeMillis()
。これは、世界で最も正確なストップウォッチではありませんが、この例では十分すぎるほどです。これがコードです: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"); } }
簡単な仕事から始めましょう:100アイテムのソースセットと削除する100:
c:UsersJonTest>java Test 100 100 Time taken: 1ms
さて、それが遅くなるとは予想していませんでした…明らかに、少し物事を増やすことができます。100万個のアイテムと30万個のアイテムを削除するソースについてはどうですか?
c:UsersJonTest>java Test 1000000 300000 Time taken: 38ms
うーん。それはまだかなり速いようです。今、私は少し残酷で、そのすべてを削除するように頼んでいると感じています。少し簡単にしましょう– 300,000のソースアイテムと300,000の削除:
c:UsersJonTest>java Test 300000 300000 Time taken: 178131ms
すみません?約3 分?うわぁ!確かに、38ミリ秒で管理したものよりも小さなコレクションから項目を削除する方が簡単なはずです。
なぜこれが起こっているのか誰かが説明できますか?なぜHashSet<T>.removeAll
メソッドはとても遅いのですか?