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

Optimize HashMap.keySet()/HashMap.values()/HashSet toArray() methods

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 14
    • core-libs
    • None
    • behavioral
    • low
    • Hide
      The following code sample illustrates the behavioral change:

      import java.util.*;

      class Example extends HashSet<String> {
        public Iterator<String> iterator() {
          add("(default)");
          return super.iterator();
        }

        public static void main(String[] args) {
          System.out.println(Arrays.toString(new Example().toArray()));
        }
      }

      Without applying the patch it outputs `[(default)]` as code author relies on implicit call of `iterator()` inside `toArray()`. After the patch is applied it outputs `[]`.
      Show
      The following code sample illustrates the behavioral change: import java.util.*; class Example extends HashSet<String> {   public Iterator<String> iterator() {     add("(default)");     return super.iterator();   }   public static void main(String[] args) {     System.out.println(Arrays.toString(new Example().toArray()));   } } Without applying the patch it outputs `[(default)]` as code author relies on implicit call of `iterator()` inside `toArray()`. After the patch is applied it outputs `[]`.
    • Java API
    • Implementation

      Summary

      The toArray() implementations in HashSet, HashMap.keySet(), HashMap.values(), LinkedHashSet, LinkedHashMap.keySet() and LinkedHashMap.values() will no longer delegate to iterator().

      Problem

      Currently the toArray() methods of HashSet, HashMap.keySet(), HashMap.values(), LinkedHashSet, LinkedHashMap.keySet() and LinkedHashMap.values() are inherited from AbstractCollection::toArray which creates an iterator(). This is unnecessarily expensive, as it maintains extra state in its fields and checks modCount after every element.

      Solution

      An optimization is proposed to manually implement toArray() methods of HashSet, HashMap.keySet(), HashMap.values(), LinkedHashSet, LinkedHashMap.keySet() and LinkedHashMap.values(), rather than inherit a less efficient implementation from AbstractCollection. As a result toArray() method won't create an iterator() anymore which may slightly affect the behavior. This is especially important for HashSet and LinkedHashSet which could be extended by users. For example, the user might subclass HashSet, override an iterator() method adding some custom logic and expect that this custom logic will be executed by toArray().

      Specification

      No specification change; behavioral change only.

            tvaleev Tagir Valeev
            tvaleev Tagir Valeev
            Stuart Marks
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: