Which is the fastest way for a containsAny check?

Viewed 794

in Something like 'contains any' for Java set? there a several solutions

  • Collections.disjoint(A, B)
  • setA.stream().anyMatch(setB::contains)
  • Sets.intersection(set1, set2).isEmpty()
  • CollectionUtils.containsAny()

im my case set1 is new ConcurrentHashMap<>().keySet() and set2 is an ArrayList

set1 can cointain up to 100 entries, set2 less then 10

Or will they all do the same and perform similar?

2 Answers
public static void main(String[] args) {
    Map<String, String> map = new ConcurrentHashMap<>();
    List<String> list = new ArrayList<>();

    for (int i = 0; i < 100; i++) {
        map.put(RandomStringUtils.randomNumeric(5), RandomStringUtils.randomNumeric(5));
    }

    for (int i = 0; i < 10; i++) {
        list.add(RandomStringUtils.randomNumeric(5));
    }

    Set<String> set = new HashSet<>(list);

    List<Runnable> methods = new ArrayList<>();
    methods.add(() -> { Collections.disjoint(map.keySet(), list); });
    methods.add(() -> { Collections.disjoint(list, map.keySet()); });

    methods.add(() -> { map.keySet().stream().anyMatch(list::contains); });
    methods.add(() -> { list.stream().anyMatch(map.keySet()::contains); });

    methods.add(() -> { Sets.intersection(map.keySet(), set).isEmpty(); });
    methods.add(() -> { Sets.intersection(set, map.keySet()).isEmpty(); });

    methods.add(() -> { CollectionUtils.containsAny(map.keySet(), list); });
    methods.add(() -> { CollectionUtils.containsAny(list, map.keySet()); });

    for (Runnable method : methods) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            method.run();
        }
        long end = System.currentTimeMillis();
        System.out.println("took " + (end - start));
    }

}

And the winner iiis Collections.disjoint

took 15
took 32
took 484
took 62
took 157
took 47
took 24
took 32

setA.stream().anyMatch(setB::contains) will be best because all the other options will be non-lazy evaluation and will be performed on all the elements.

For the stream, it will be lazy evaluation and will be returned once any match is found.

Also, from Documentation of CollectionUtils.containsAny()

In other words, this method returns true iff the intersection(java.lang.Iterable, java.lang.Iterable) of coll1 and coll2 is not empty.

Related