Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8277530

stream.max/min chokes when max or min is null

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Confirmed in java 8, 16, and 17.0.1 across several environments, mostly linux.

      A DESCRIPTION OF THE PROBLEM :
      Using Comparator.nullsLast or nullsFirst, one can treat nulls as the min or max of a stream, potentially useful in some cases - e.g. finding the latest expiration date for a set of data, where a "null" anywhere in the set indicates that it should never expire.

      However, instead of returning an empty Optional, stream's .max and .min will produce NullPointerExceptions when trying to initialize the Optional.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      <some list of Integers, which contains nulls>.stream()
          .max(Comparator.nullsLast(Integer::compare));
      or
      <some list of Integers, which can contain nulls>.stream()
          .min(Comparator.nullsFirst(Integer::compare));

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      should return an empty Optional.
      ACTUAL -
      Exception in thread "main" java.lang.NullPointerException
      at java.base/java.util.Objects.requireNonNull(Objects.java:208)
      at java.base/java.util.Optional.of(Optional.java:113)
      at java.base/java.util.stream.ReduceOps$2ReducingSink.get(ReduceOps.java:129)
      at java.base/java.util.stream.ReduceOps$2ReducingSink.get(ReduceOps.java:107)
      at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
      at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
      at java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:662)
      at java.base/java.util.stream.ReferencePipeline.min(ReferencePipeline.java:703)

      ---------- BEGIN SOURCE ----------
      import java.util.Arrays;
      import java.util.List;
      import java.util.Comparator;

      class Main {
          public static void main(String[ ] args) {
              List<Integer> list = Arrays.asList(0, 1, 2, null);
              System.out.print(list.stream().max(Comparator.nullsLast(Integer::compare)));
              System.out.print(list.stream().min(Comparator.nullsFirst(Integer::compare)));
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The code can be restructured to include a "contains(null)" check before the stream logic, but in many cases this will be inefficient.

      FREQUENCY : always


            psandoz Paul Sandoz
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: