JDK-8284272 : Make ConcurrentHashMap.CollectionView a sealed hierarchy
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.util.concurrent
  • Priority: P4
  • Status: Draft
  • Resolution: Unresolved
  • Submitted: 2022-04-04
  • Updated: 2022-04-04
Related Reports
CSR :  
Description
Summary
-------

Update `java.util.concurrent.CollectionView` to be a sealed class and `java.util.concurrent.CollectionView$KeySetView` to be final class.

Problem
-------

`java.util.concurrent.CollectionView` is a package private class with a package private constructor. It currently has 3 subclasses - `EntrySetView`, `KeySetView` and `ValuesView`. The `EntrySetView` and `ValuesView` are both final classes. The `KeySetView` is a public class, but it only has a package private constructor. Making the `CollectionView` a `sealed` class with only these 3 subclasses are permitted with more clearly convey its usage/design intent.

Solution
--------

`CollectionView` will be marked as `sealed` and `KeySetView` will be marked as `final`. Although the `KeySetView` is a `public` class, it only has a package private constructor and as such cannot be subclasses outside of this package. No subclasses of this class currently exist in this package. Additionally, the javadoc of this class already states "This class cannot be directly instantiated", so changing this to `final` shouldn't impact any other classes.

This entire class hierarchy of `CollectionView` and its subclasses implement the `java.io.Serializable` interface. Updating the `KeySetView` to be `final` changes the auto-generated serial version id of the class, but since the `KeySetView` already has a custom `serialVersionUID` defined for this class, changing this class to `final` will not impact the serial version id or backward compatibility (in context of serialization/de-serialization) of this class.

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


```
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java
@@ -4416,8 +4416,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
     /**
      * Base class for views.
      */
-    abstract static class CollectionView<K,V,E>
-        implements Collection<E>, java.io.Serializable {
+    abstract static sealed class CollectionView<K,V,E>
+        implements Collection<E>, java.io.Serializable permits EntrySetView, KeySetView, ValuesView {
         private static final long serialVersionUID = 7249069246763182397L;
         final ConcurrentHashMap<K,V> map;
         CollectionView(ConcurrentHashMap<K,V> map)  { this.map = map; }
@@ -4589,7 +4589,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
      *
      * @since 1.8
      */
-    public static class KeySetView<K,V> extends CollectionView<K,V,K>
+    public static final class KeySetView<K,V> extends CollectionView<K,V,K>
         implements Set<K>, java.io.Serializable {
         private static final long serialVersionUID = 7249069246763182397L;
         @SuppressWarnings("serial") // Conditionally serializable

```