Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

findFirst throws java.lang.NullPointerException

I have this code below. The findfirst call is throwing NullPointerException even though I have an orElseGet call chained

int numberOfRetry = 5;
String req = "abc";
String res =
    Stream.iterate(0, n -> n + 1).map(i -> {
        try {
            return req.substring(numberOfRetry - i);
        } catch (Exception e) {
            // log exception
        }
        return null;
    })
    .limit(1)
    .findFirst()
    .orElseGet(() -> "Exception");

However, it works fine if I put a filter call as shown below:

int numberOfRetry = 5;
String req = "abc";
String res =
    Stream.iterate(0, n -> n + 1).map(i -> {
        try {
            return req.substring(numberOfRetry - i);
        } catch (Exception e) {
            // log exception
        }
        return null;
    })
    .limit(1)
    .filter(Objects::nonNull)
    .findFirst()
    .orElseGet(() -> "Exception");

I guess we cannot explicitly return null in some situations, and it is not quite clear what those situations are at first glance. In the first case it returns a stream with the null element in it which throws NullPointerException, in the second case it returns an empty stream which works fine.

like image 223
fastcodejava Avatar asked Oct 15 '18 16:10

fastcodejava


People also ask

How to avoid null pointer exception in list Java 8?

Java 8 introduced an Optional class which is a nicer way to avoid NullPointerExceptions. You can use Optional to encapsulate the potential null values and pass or return it safely without worrying about the exception. Without Optional, when a method signature has return type of certain object.

What is the difference between findFirst and findAny Java 8?

The findAny() method returns any element from a Stream, while the findFirst() method returns the first element in a Stream.

How do I use stream findFirst?

Stream findFirst() in Java with examples Stream findFirst() returns an Optional (a container object which may or may not contain a non-null value) describing the first element of this stream, or an empty Optional if the stream is empty. If the stream has no encounter order, then any element may be returned.


1 Answers

Your code is explicitly returning null

return null

which thereafter throws NPE, according to the spec of Optional.findFirst which reads:

@throws NullPointerException if the element selected is null
Optional<T> findFirst();

Also, to clarify the code control couldn't even reach the orElseGet part which anyway assumingly works over an Optional (either empty or with some value).


Few suggestions :

  • Don't ignore exceptions, especially when you've caught the most generic out of them all.
  • Avoid returning null explicitly from within an iteration, it seems contradictory to why you'd iterate then.
  • Safer side in your code currently, you can filter-in only nonNull objects using filter as

    Stream.iterate(0, n -> n + 1).map(i -> {
           try {
               return req.substring(numberOfRetry - i);
           } catch (Exception e) {
               err.add(e);
           }
           return null;
    })
    .filter(Objects::nonNull)
    .limit(1)
    .findFirst()
    .orElse("Exception");
    
like image 106
Naman Avatar answered Sep 30 '22 06:09

Naman