0

I have done some small benchmarks where I iterate over different collections and I found weird difference between HashSet and LinkedHashSet. When I execute exactly the same code but for different types(Integer vs String), I receive different results:

  1. For Integer iteration LinkedHashSet is faster(6,53[ms] vs 20[ms])
  2. For String iteration HashSet is faster(55,92[ms] vs 67[ms])
    public void iterateHashSet() {
        HashSet<String> strings = addStrings();
        List<Long> executionsTimes = new ArrayList<>();

        IntStream.range(0, ATTEMPT_COUNT).forEach(i -> {
            if (i >= ATTEMPT_COUNT * 0.7) {
                long start = System.nanoTime();
                strings.forEach(s -> {
                    ;
                });
                long resultTime = (System.nanoTime() - start);
                executionsTimes.add(resultTime);
            } else {
                strings.forEach(s -> {
                    ;
                });
            }
        });
        averageExecutionTime(executionsTimes);
    }

    public void iterateLinkedHashSet() {
        LinkedHashSet<String> strings = addStrings();
        List<Long> executionsTimes = new ArrayList<>();

        IntStream.range(0, ATTEMPT_COUNT).forEach(i -> {
            if (i>= ATTEMPT_COUNT * 0.7) {
                long start = System.nanoTime();
                strings.forEach(s -> {
                    ;
                });
                long resultTime = (System.nanoTime() - start);
                executionsTimes.add(resultTime);
            } else {
                strings.forEach(s -> {
                    ;
                });
            }
        });
        averageExecutionTime(executionsTimes);
    }

Size of each set is 1000000. For Integer test structure is the same besides the type of course :) I used ATTEMPT_COUNT to warmup JVM.

Do you have any idea where this difference comes from?

E: This is how I add strings:

    private LinkedHashSet<String> addStrings() {
    LinkedHashSet<String> strings = new LinkedHashSet<>();
    Random random = new Random();
    for (var i = 0; strings.size() < ELEMENT_COUNT; i++) {
        int number = random.ints(0, strings.size()+1)
                .findFirst()
                .getAsInt();
        StringBuilder stringBuilder = new StringBuilder();
        if (i % 2 == 0) {
            stringBuilder
                    .append("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
                            "Etiam quis tortor a ex bibendum pulvinar id vel erat. " +
                            "Pellentesque tempus sit amet ante in iaculis. Etiam sit amet mattis ligula. " +
                            "Curabitur aliquet elit dignissim, ullamcorper lorem laoreet, sagittis quam." +
                            " Maecenas fringilla egestas enim eu dignissim. Ut fermentum ligula eu tortor eleifend, " +
                            "et eleifend arcu tristique. Sed sit amet arcu diam. Pellentesque non suscipit massa. " +
                            "Suspendisse a mi ante. Curabitur laoreet non turpis sed fringilla. Aliquam dolor velit," +
                            " luctus nec bibendum in, dignissim eget est. Etiam convallis mattis lectus vitae euismod.")
                    .append(number);
        } else {
            stringBuilder
                    .append("Vivamus iaculis vulputate lectus sed cursus. Suspendisse efficitur " +
                            "molestie efficitur. Suspendisse et tortor a mi sagittis tempor porta vel eros. Curabitur nec " +
                            "pellentesque magna, in gravida risus. Etiam mollis, quam a sollicitudin fringilla, tellus massa " +
                            "lobortis neque, eget mattis nunc nisl eget erat. Cras finibus felis a nisl porta, at pellentesque" +
                            " nisi elementum. Sed ac dui lectus. Praesent id gravida metus, et tristique felis. Sed at massa" +
                            " ipsum. Duis at sapien quam. Aliquam erat volutpat. Cras gravida fermentum feugiat. Vivamus nec" +
                            " consequat diam. Proin ut purus laoreet massa tempus molestie. Maecenas luctus porta sapien id" +
                            " tincidunt. Maecenas posuere feugiat commodo.")
                    .append(number);
        }
        strings.add(stringBuilder.toString());
    }
    return strings;
}

Integers:

    private LinkedHashSet<Integer> addNumbers() {
    LinkedHashSet<Integer> numbers = new LinkedHashSet<>();
    Random random = new Random();
    for (var i = 0; numbers.size() < ELEMENT_COUNT; i++) {
        int number = random.ints(0, Integer.MAX_VALUE)
                .findFirst()
                .getAsInt();
        numbers.add(number);
    }
    return numbers;
}
ddoel
  • 1
  • 2
  • How do you generate data for your test? – Dmitry Ermolov Aug 19 '21 at 17:36
  • Added to my post. – ddoel Aug 19 '21 at 17:46
  • 1
    Why are you using `random.ints(0, Integer.MAX_VALUE) .findFirst() .getAsInt()` instead of just `random.nextInt()`? And what makes you confident that these random numbers are unique, i.e. that the resulting set truly has the specified size? – Holger Aug 20 '21 at 14:52
  • 1
    A `LinkedHashSet` does not become a non-linked `HashSet` when you assign it to a variable of type `HashSet`. It’s still the same object and calling `forEach` on it still ends up at the same implementation method. Any differences you’re measuring, are caused by the your method of measuring. – Holger Aug 20 '21 at 16:03

0 Answers0