JDK-8261677 : (coll) Optimize Collections.unmodifiable* and synchronized*
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 17
  • Submitted: 2021-02-12
  • Updated: 2021-03-15
  • Resolved: 2021-03-03
Related Reports
CSR :  
Description
Summary
-------

Changing the `unmodifiable*` methods in `java.util.Collections` so they do not re-wrap unmodifiable collections in another unmodifiable collections. That is, make calls to the `umodifiable*` methods idempotent.

Problem
-------

The `unmodifiable*` methods in `Collections` will take an existing collection and return an unmodifiable view of it. These methods do not inspect their arguments to see if they are already an unmodifiable collection. In cases where a collection is already unmodifiable, they will wrap the collection in another unmodifiable view. This creates needless overhead. The problem of creating nested wrappers has been observed in the wild to consume excess CPU cycles and to cause stack overflow errors.

Solution
--------

Change the `unmodifiable*` wrapping methods to avoid wrapping if the argument is already of an appropriate class. This proposal specifies idempotency only for unmodifiable wrappers internal to `java.util.Collection`. We continue to wrap other unmodifiable classes in the standard libraries (e.g. collections introduced in JEP 269 that are produced by `List.of()` and similar) because of semantic inconsistencies between those collections and these wrappers. 
    
  
Specification
-------------

The following methods in `Collections` will be modified:

* `unmodifiableCollection`
* `unmodifiableList`
* `unmodifiableMap`
* `unmodifiableNavigableMap`
* `unmodifiableNavigableSet`
* `unmodifiableSet`
* `unmodifiableSortedMap`
* `unmodifiableSortedSet`

In each we will check the class of the argument. If the argument's class is the same as the the class returned by the method we return the argument instead.

An `@implNote` will be added for each affected method stating "this method may return its argument if the argument is already unmodifiable."



Comments
The reason for the CSR is mainly to document the behavior change in the implementation, so that's why we put scope as JDK, and the text about "may return its argument" in an @implNote. However, this textual change is a change to Java SE, and even though it has no changes to testable assertions, it's still a change to the SE spec. So from that standpoint I guess the scope could be SE. If that's a reasonable interpretation of "SE" scope, then I'm ok with it.
15-03-2021

Changes targeted to 17. I can update both.
15-03-2021

While @implNote is non-normative, the changes are to be expected at the JavaSE API 17 (?, JDK-6323374 hints 17 ) specification level, so curious if the scope here should be SE ? BTW this CSR doesn't have Fix Version defined.
15-03-2021

Moving the CSR to Approved. Left a code review comment concerning if the implementation should check for and accept subclasses in more cases, e.g. treat a navigableUnmodifiableFoo as serving as a sortedUnmodifiableFoo.
03-03-2021