How should we manage jdk8 stream for null values

前端 未结 5 1306
北海茫月
北海茫月 2020-12-04 10:53

Hello fellow Java developers,

I know the subject may be a bit in advance as the JDK8 is not yet released (and not for now anyway..) but I was reading som

相关标签:
5条回答
  • 2020-12-04 11:26

    Stuart's answer provides a great explanation, but I'd like to provide another example.

    I ran into this issue when attempting to perform a reduce on a Stream containing null values (actually it was LongStream.average(), which is a type of reduction). Since average() returns OptionalDouble, I assumed the Stream could contain nulls but instead a NullPointerException was thrown. This is due to Stuart's explanation of null v. empty.

    So, as the OP suggests, I added a filter like so:

    list.stream()
        .filter(o -> o != null)
        .reduce(..);
    

    Or as tangens pointed out below, use the predicate provided by the Java API:

    list.stream()
        .filter(Objects::nonNull)
        .reduce(..);
    

    From the mailing list discussion Stuart linked: Brian Goetz on nulls in Streams

    0 讨论(0)
  • 2020-12-04 11:28

    Current thinking seems to be to "tolerate" nulls, that is, to allow them in general, although some operations are less tolerant and may end up throwing NPE. See the discussion of nulls on the Lambda Libraries expert group mailing list, specifically this message. Consensus around option #3 subsequently emerged (with a notable objection from Doug Lea). So yes, the OP's concern about pipelines blowing up with NPE is valid.

    It's not for nothing that Tony Hoare referred to nulls as the "Billion Dollar Mistake." Dealing with nulls is a real pain. Even with classic collections (without considering lambdas or streams) nulls are problematic. As fge mentioned in a comment, some collections allow nulls and others do not. With collections that allow nulls, this introduces ambiguities into the API. For example, with Map.get(), a null return indicates either that the key is present and its value is null, or that the key is absent. One has to do extra work to disambiguate these cases.

    The usual use for null is to denote the absence of a value. The approach for dealing with this proposed for Java SE 8 is to introduce a new java.util.Optional type, which encapsulates the presence/absence of a value, along with behaviors of supplying a default value, or throwing an exception, or calling a function, etc. if the value is absent. Optional is used only by new APIs, though, everything else in the system still has to put up with the possibility of nulls.

    My advice is to avoid actual null references to the greatest extent possible. It's hard to see from the example given how there could be a "null" Otter. But if one were necessary, the OP's suggestions of filtering out null values, or mapping them to a sentinel object (the Null Object Pattern) are fine approaches.

    0 讨论(0)
  • 2020-12-04 11:29

    Although the answers are 100% correct, a small suggestion to improve null case handling of the list itself with Optional:

     List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff)
                    .orElseGet(Collections::emptyList)
                    .stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
    

    The part Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList) will allow you to handle nicely the case when listOfStuff is null and return an emptyList instead of failing with NullPointerException.

    0 讨论(0)
  • 2020-12-04 11:41

    If you just want to filter null values out of a stream, you can simply use a method reference to java.util.Objects.nonNull(Object). From its documentation:

    This method exists to be used as a Predicate, filter(Objects::nonNull)

    For example:

    List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null);
    
    list.stream()
        .filter( Objects::nonNull )  // <-- Filter out null values
        .forEach( System.out::println );
    

    This will print:

    Foo
    Bar
    
    0 讨论(0)
  • 2020-12-04 11:43

    An example how to avoid null e.g. use filter before groupingBy

    Filter out the null instances before groupingBy.

    Here is an example

    MyObjectlist.stream()
                .filter(p -> p.getSomeInstance() != null)
                .collect(Collectors.groupingBy(MyObject::getSomeInstance));
    
    0 讨论(0)
提交回复
热议问题