JDK-8329284 : Map.of() derived view collection mutators should throw UnsupportedOperationException
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Priority: P4
  • Status: Provisional
  • Resolution: Unresolved
  • Fix Versions: 26
  • Submitted: 2024-03-28
  • Updated: 2025-05-30
Related Reports
CSR :  
Description
Summary
-------

This change updates the mutator methods on the unmodifiable collection views `entrySet()` `keySet()` `values()` returned by `Map.of()` to throw `UnsupportedOperationException`.

Problem
-------

[`Map.of()`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#of()) is specified as returning an unmodifiable collection.

> Returns an unmodifiable map containing zero mappings.

The [specification for unmodifiable collections](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Collection.html#unmodifiable) requires the mutator methods of unmodifiable collections, and their derived view collections, to throw `UnsupportedOperationException`:

> An unmodifiable collection is a collection, all of whose mutator methods (as defined above) are specified to throw UnsupportedOperationException. Such a collection thus cannot be modified by calling any methods on it. For a collection to be properly unmodifiable, any view collections derived from it must also be unmodifiable. For example, if a List is unmodifiable, the List returned by List.subList is also unmodifiable.

In JDK 11 and newer, the mutator methods on the unmodifiable set returned by `Map.of().entrySet()` do not modify the underlying view, and also do not throw `UnsupportedOperationException`. In earlier versions the mutator methods of `entrySet()` threw `UnsupportedOperationException`. `keySet()` or `values()` always had the post-11 behaviors of `entrySet()`.

Solution
--------

The solution is to make the mutator methods `entrySet()` `keySet()` `values()` of `Map.of()` throw `UnsupportedOperationException`.

An alternate is to leave the existing behaviors in place, and prioritize compatibility with existing code that may rely on the buggy behaviour over compliance with the specification.

Specification
-------------

The [specification for unmodifiable maps](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html#unmodifiable) will be updated to explicitly say that mutator methods on derived view collections will also throw `UnsupportedOperationException`:

    diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java
    index ea2fd4e1807..6462a54df31 100644
    --- a/src/java.base/share/classes/java/util/Map.java
    +++ b/src/java.base/share/classes/java/util/Map.java
    @@ -122,8 +122,8 @@
      *
      * <ul>
      * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Keys and values
    - * cannot be added, removed, or updated. Calling any mutator method on the Map
    - * will always cause {@code UnsupportedOperationException} to be thrown.
    + * cannot be added, removed, or updated. Calling any mutator method on the Map or any derived view
    + * collection will always cause {@code UnsupportedOperationException} to be thrown.
      * However, if the contained keys or values are themselves mutable, this may cause the
      * Map to behave inconsistently or its contents to appear to change.
      * <li>They disallow {@code null} keys and values. Attempts to create them with
Comments
I posted a comment on the PR, copied here for convenience: > We haven't yet determined that corpus analysis has provided little useful information. Frankly, I think we've hardly tried. I've talked to @minborg about working with him on a compatibility analysis that will cover this PR as well as JDK-8316493 (remove caching fields in AbstractMap).
30-05-2025

I have reviewed this CSR as a change for 26. It is extremely hard to identify use sites through a corpus search because: 1. A site must be able to use Map.of() derived collections 2. The site must use remove on an empty collection If we ignore any of these in a search, we will come up with tons of false positives; this is in general, just hard to analyze. Thus, I believe the best approach is to apply this change in 26 and consider rolling back if there are reports that this causes issues.
30-05-2025

In another comment https://bugs.openjdk.org/browse/JDK-8328821?focusedId=14689541&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14689541 I suggested doing a survey of open source repositories. I think this would helpful to either surface unexpected surprises or to confirm our intuition. Either way I think it would be determinative. I've had half a mind to do this myself, but if somebody else were to pick it up I wouldn't mind.
22-04-2025

The corpus analysis of Google's codebase failed to find any code that was affected by the change, so by that metric the compatibility impact for this is lower than many of the breaking changes that have successfully been made in recent releases. It would be nice to have a corpus analysis of more open source code, but I also don't think it's necessary to conclude the risk of this change is low, and it hasn't been something I've been able to make time to do.
22-04-2025

I think maybe we can just commit this to release 26 and raise this in quality-discuss list, given the corpus search went nowhere.
22-04-2025

This CSR has been in Provisional state for some time. A reminder that JDK 25 rampdown 1 start is on June 5, 2025. CSRs intended to get in the release should be Finalized well ahead of the deadline. If there is no longer interest in this CSR, it can be withdrawn.
22-04-2025

What looks even more salient is that Map#of links directly to the "unmodifiable" heading of the Map class docs, which states "Calling any mutator method on the Map will always cause UnsupportedOperationException to be thrown." However, it "forgot" to explicitly say that that includes mutator methods on *view collections* too. But as Collection says "For a collection to be properly unmodifiable, any view collections derived from it must also be unmodifiable", and I think Map should probably state something like that as well. Almost positively just an oversight. And *that* repaired spec of course would make it clear that this was indeed a regression and should be fixed.
09-07-2024

A reminder that the JDK 23 ramp down date is coming up soon if there is still interest in addressing this issue in JDK 23.
24-05-2024

> please also clarify what the current behavior is that the CSR is proposing to change. Thanks, I added a paragraph to the problem section describing the current behavior. [~smarks] would you be willing to Review this CSR?
22-04-2024

Moving to Provisional, not Approved. [~smarks], please review this CSR. [~cushon], before this request is Finalized after Stuart's review, please also clarify what the current behavior is that the CSR is proposing to change.
02-04-2024