user1071840
user1071840

Reputation: 3592

Is there any performance benefit of using Arrays.stream() over iterating on an array?

I need to iterate on all the enum values, check if they were used to construct an int (called input) and if so, add them to a Set (called usefulEnums). I can either use streams API or iterate over all the enums to do this task. Is there any benefit of using Arrays.stream() over the traditional approach of iterating over the values() array?

   enum TestEnum { VALUE1, VALUE2, VALUE3 };

   Set<TestEnum> usefulEnums = new HashSet<>();

   Arrays.stream(TestEnum.values())
            .filter(t -> (input & t.getValue()) != 0)
            .forEach(usefulEnums::add);

    for (TestEnum t : TestEnum.values()) {
        if ((input & t.getValue()) != 0) {
            usefulEnums.add(t);
        }
    }

Upvotes: 4

Views: 704

Answers (2)

Eugene
Eugene

Reputation: 120858

For this short operation the for loop is going to be faster (nano-seconds faster), but to me the stream operation is more verbose, it tells exactly what is being done here. It's like reading diagonally.

Also you could collect directly to a HashSet:

Arrays.stream(TestEnum.values())
        .filter(t -> (input & t.getValue()) != 0)
        .collect(Collectors.toCollection(HashSet::new));

Valuable input from Holger as usual makes this even nicer:

EnumSet<TestEnum> filtered = EnumSet.allOf(TestEnum.class).stream()
            .filter(t -> (input & t.getValue()) != 0)
            .collect(Collectors.toCollection(() -> EnumSet.noneOf(TestEnum.class)));

Upvotes: 3

Holger
Holger

Reputation: 298153

If you care for efficiency, you should consider:

Set<TestEnum> usefulEnums = EnumSet.allOf(TestEnum.class);
usefulEnums.removeIf(t -> (input & t.getValue()) == 0);

Note that when you have to iterate over all enum constants of a type, using EnumSet.allOf(EnumType.class).stream() avoids the array creation of EnumType.values() entirely, however, most enum types don’t have enough constants for this to make a difference. Further, the JVM’s optimizer may remove the temporary array creation anyway.

But for this specific task, where the result is supposed to be a Set<TestEnum>, using an EnumSet instead of a HashSet may even improve subsequent operations working with the Set. Creating an EnumSet holding all constants and removing unintented constants like in the solution above, means just initializing a long with 0b111, followed by clearing the bits of nonmatching elements.

Upvotes: 5

Related Questions