Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need to continue filtering Java stream when map throws exception after filter and findFirst

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();
like image 471
Chad K Avatar asked Jun 22 '17 23:06

Chad K


1 Answers

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()
like image 78
Thilo Avatar answered Nov 03 '22 01:11

Thilo