TreeSet and TreeMap.keySet() empty subSet spliterators should throw NullPointerException

XMLWordPrintable

    • behavioral
    • low
    • The new NPE only happens to an empty subSet, existing code would have ran into NPE for non-empty subSets before accidentally relying on this behavior.
    • Java API
    • Implementation

      Summary

      For the subSet from a java.util.TreeSet or a java.util.TreeMap::keySet, if such a set is empty, its spliterator now properly throws NullPointerException for tryAdvance and forEachRemaining.

      Problem

      The subSet for a TreeSet or a TreeMap.entrySet() got a customized spliterator implementation in JDK-8011426. That patch incorrectly omitted null checks when the subSet is empty, because the arguments are unused for empty subSets.

      This causes certain operations to misbehave. For example, in JShell:

      new TreeSet<Integer>().subSet(-1, 1).spliterator().tryAdvance(null);    // returns false
      new TreeSet<Integer>().subSet(-1, 1).spliterator().forEachRemaining(null);    // does nothing
      new TreeSet<Integer>().subSet(-1, 1).stream().forEach(null);    // does nothing
      

      However, the specifications for Spliterator's tryAdvance() and forEachRemaining() methods require throwing a NullPointerException if the argument is null. In addition, the Stream class has a general requirement that behavioral parameters (such as the parameter to forEach) must be non-null, implying that NullPointerException is thrown in such cases.

      Solution

      Add explicit null checks in the corresponding methods of these spliterator implementations.

      Specification

      No change. This is a behavioral change that aligns implementation to specification.

            Assignee:
            Chen Liang
            Reporter:
            Oli Gillespie
            Roger Riggs, Stuart Marks
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: