maybesomename
maybesomename

Reputation: 150

Is there a way to step out of a java stream if an item matches a condition?

I have a list of integers and I need to find the sum of its items. If the list contains any null items, the result should be null. My current implementation:

intList.stream().anyMatch(Objects::isNull) ? null : intList.stream().mapToInt(Integer::intValue).sum();

Can this be done with a single continuous stream? Is there an operation that terminates the stream if an item meets a condition?

Upvotes: 3

Views: 1336

Answers (4)

dajavax
dajavax

Reputation: 3400

As for your question "Is there an operation that terminates the stream if an item meets a condition?", Java 9 introduces Stream::takeWhile which does this.

However, using this for your use case would result in a sum of everything before the null (not what you are expecting of actually returning a null). For your case, and being limited to the JDK, using the answer proposed by M A is the best (though it does not stop when it reaches a null).

The actual best way would be if there is a takeWhileInclusive combined with the reduce operation. Unfortunately, takeWhileInclusive does not exist in the JDK. However, Tagir Valeev, who is a committer in the JDK, has written a stream extension library (StreamEx) which has StreamEx::takeWhileInclusive. It might be useful.

The following example, using that library, would step out with a null if null is encountered, or with the sum if it is not:

StreamEx.of(intList).takeWhileInclusive(Objects::nonNull)
    .reduce(0, (a, b) -> a == null || b == null ? null : a + b);

Upvotes: 3

WJS
WJS

Reputation: 40047

Streams are not always the right solution. And even when they are they may not be as efficient as a simple loop solution. In your case, I would do the following:

public static Integer sum(List<Integer> vals) {
    int sum = 0;
    for (Integer v : vals) {
        if (v == null) {
            return null;
        }
        sum += v;
    }
    return sum;
}

This both sums the elements or short circuits and returns a null.

Upvotes: 1

Eritrean
Eritrean

Reputation: 16498

May be using reduce like:

List<Integer> intList = Arrays.asList(1,2,3,null,4);
Integer sum = intList.stream().reduce(0, (a, b) -> a == null || b == null ? null: a + b);
System.out.println(sum);

Upvotes: 2

M A
M A

Reputation: 72884

You can control how the sum reduction occurs:

Integer sum = intList.stream().reduce(0, (i1, i2) -> {
        if(i1 == null) return null;
        if(i2 == null) return null;
        return i1 + i2;
    });

Upvotes: 2

Related Questions