7

I have this code:

return myList
    .stream()
    .filter(Objects::nonNull)
    .filter(listItem -> {
        try {
            return listItem.matchesCondition();
        } catch (Exception e) {
            // log error
            return false;
        }
    })
    .findFirst()
    .map(listItem -> {
        try {
            return listItem.getResult();
        } catch (Exception e) {

            // IF THIS HAPPENS, HOW CAN WE ADVANCE TO THE NEXT ITEM IN THE STREAM.
            // I'M ASSUMING WE CAN NOT SINCE THE STREAM WAS TERMINATED BY findFirst.
            // BUT HOW CAN I WRITE THIS IN A DIFFERENT WAY TO ACHIEVE THAT BEHAVIOR?

            // log error
            return null;
        }
    });

The issue is, if the first matching listItem throws an exception in the map function, an empty Optional is returned.

But instead, I want to continue testing the remaining items in the list, and try to map the next one that matches the filter.

How can I do that with streams and lambdas?

I can convert to this more imperative code but would like to find a functional solution.

for (MyListItem myList : listItem) {
    try {
        if (listItem.matchesCondition()) {
            return Optional.of(listItem.getResult());
        }
    } catch (Exception e) {

        // SWALLOW THE EXCEPTION SO THE NEXT ITEM IS TESTED

        // log error
    }
}

return Optional.empty();
0

1 Answer 1

10

You have to move the findFirst to the very end, because it reduces the stream to just (at most) a single element and you cannot "go back" and get more after that.

return myList
    .stream()
    .filter(Objects::nonNull)
    .filter( ... )
    .map( ... ) // returns null on Exception, so filter again
    .filter(Objects::nonNull)
    .findFirst()
Sign up to request clarification or add additional context in comments.

3 Comments

Alternatively, instead of .map(to null on exception ).filter(Objects::nonNull) you may use .flatMap(listItem -> { try { return Stream.of(listItem.getResult()); } catch(Exception e) { return null; } }). The flatMap operation will treat null like Stream.empty().
@Holger. I thought about that (or the similar flatMap over Option.of). But it is just as noisy as the filter(::nonNull). Would be nice to have something like Scala's .flatMap(Try(....).toOption) to just ignore exceptions in the stream.
Well, you could make a utility method doing exactly that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.