You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2022/12/10 22:37:51 UTC

[sis] 01/02: Reduce the use of `CollectionsExt` when Java 11 methods can do the work.

This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit eaf802470811a6639488361f789764e9fb10f4df
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat Dec 10 22:50:03 2022 +0100

    Reduce the use of `CollectionsExt` when Java 11 methods can do the work.
---
 .../apache/sis/coverage/grid/ImageRenderer.java    |   3 +-
 .../sis/internal/jaxb/NonMarshalledAuthority.java  |   2 +-
 .../src/main/java/org/apache/sis/xml/Pooled.java   |   3 +-
 .../main/java/org/apache/sis/xml/Transformer.java  |  17 +-
 .../java/org/apache/sis/test/MetadataAssert.java   |   3 +-
 .../coverage/MultiResolutionCoverageLoader.java    |   3 +-
 .../referencing/GeodeticObjectBuilder.java         |   3 +-
 .../referencing/factory/GeodeticObjectFactory.java |  12 +-
 .../DefaultCoordinateOperationFactory.java         |  12 +-
 .../apache/sis/internal/util/CollectionsExt.java   | 207 ++++-----------------
 .../java/org/apache/sis/measure/UnitDimension.java |  12 +-
 .../sis/internal/util/CollectionsExtTest.java      |  18 +-
 .../aggregate/ConcatenatedGridResource.java        |   3 +-
 .../apache/sis/storage/event/StoreListeners.java   |   3 +-
 14 files changed, 63 insertions(+), 238 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
index 4b2073b4cf..337facc853 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/ImageRenderer.java
@@ -46,7 +46,6 @@ import org.apache.sis.internal.coverage.j2d.RasterFactory;
 import org.apache.sis.internal.coverage.j2d.TiledImage;
 import org.apache.sis.internal.coverage.j2d.WritableTiledImage;
 import org.apache.sis.internal.feature.Resources;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.util.NullArgumentException;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
@@ -303,7 +302,7 @@ public class ImageRenderer {
      */
     public ImageRenderer(final GridCoverage coverage, GridExtent sliceExtent) {
         ArgumentChecks.ensureNonNull("coverage", coverage);
-        bands = CollectionsExt.toArray(coverage.getSampleDimensions(), SampleDimension.class);
+        bands = coverage.getSampleDimensions().toArray(SampleDimension[]::new);
         geometry = coverage.getGridGeometry();
         final GridExtent source = geometry.getExtent();
         final int dimension = source.getDimension();
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java
index 5633da9724..c7707e22e9 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java
@@ -269,7 +269,7 @@ public final class NonMarshalledAuthority<T> extends CitationConstant.Authority<
         switch (merged.size()) {
             case 0:  return Collections.emptyList();
             case 1:  return Collections.singletonList(merged.get(0));
-            default: return Containers.unmodifiableList(CollectionsExt.toArray(merged, Identifier.class));
+            default: return Containers.unmodifiableList(merged.toArray(Identifier[]::new));
         }
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java
index 53927dcf9b..cc112fc728 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/Pooled.java
@@ -36,7 +36,6 @@ import org.apache.sis.util.Version;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.Strings;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.xml.LegacyNamespaces;
@@ -312,7 +311,7 @@ abstract class Pooled {
                                 copy.put(key, (String) schema);
                             }
                         }
-                        copy = CollectionsExt.unmodifiableOrCopy(copy);
+                        copy = Map.copyOf(copy);
                     }
                     schemas = copy;
                     return;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
index 2c38fef814..dff0fcbeeb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/Transformer.java
@@ -23,7 +23,6 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Arrays;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.InvalidPropertiesFormatException;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -35,7 +34,6 @@ import javax.xml.stream.events.Attribute;
 import javax.xml.stream.events.Namespace;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.jaxb.TypeRegistration;
 
 
@@ -185,7 +183,7 @@ abstract class Transformer {
         namespaces             = new HashMap<>();
         outerElements          = new ArrayList<>();
         renamedAttributes      = new ArrayList<>();
-        outerElementProperties = Collections.emptyMap();
+        outerElementProperties = Map.of();
     }
 
     /**
@@ -365,9 +363,8 @@ abstract class Transformer {
         }
         /*
          * At this point we finished computing the map values. Many values are maps with only 1 entry.
-         * Save a little bit of space by replacing maps of 1 element by Collections.singletonMap(…).
          */
-        m.replaceAll((k, v) -> CollectionsExt.compact(v));
+        m.replaceAll((k, v) -> Map.copyOf(v));
         return m;
     }
 
@@ -386,8 +383,8 @@ abstract class Transformer {
     final List<Attribute> attributes() {
         final List<Attribute> attributes;
         switch (renamedAttributes.size()) {
-            case 0:  attributes = Collections.emptyList(); break;      // Avoid object creation for this common case.
-            case 1:  attributes = Collections.singletonList(renamedAttributes.remove(0)); break;
+            case 0:  attributes = List.of(); break;             // Avoid object creation for this common case.
+            case 1:  attributes = List.of(renamedAttributes.remove(0)); break;
             default: attributes = Arrays.asList(renamedAttributes.toArray(new Attribute[renamedAttributes.size()]));
                      renamedAttributes.clear();
                      break;
@@ -422,7 +419,7 @@ abstract class Transformer {
                         String localPart = value.substring(s+1).trim();
                         QName name = new QName(namespace, localPart, prefix);
                         final Map<String,String> currentMap = outerElementProperties;
-                        outerElementProperties = renamingMap(namespace).getOrDefault(localPart, Collections.emptyMap());
+                        outerElementProperties = renamingMap(namespace).getOrDefault(localPart, Map.of());
                         final boolean changed = (name != (name = convert(name)));
                         outerElementProperties = currentMap;
                         if (changed) {
@@ -493,7 +490,7 @@ abstract class Transformer {
         final String localPart = name.getLocalPart();
         if (isTypeElement(localPart)) {
             outerElements.add(name);
-            outerElementProperties = renamingMap(name.getNamespaceURI()).getOrDefault(localPart, Collections.emptyMap());
+            outerElementProperties = renamingMap(name.getNamespaceURI()).getOrDefault(localPart, Map.of());
         }
     }
 
@@ -519,7 +516,7 @@ abstract class Transformer {
                         namespace = XMLConstants.NULL_NS_URI;
                         localPart = null;
                     }
-                    outerElementProperties = renamingMap(namespace).getOrDefault(localPart, Collections.emptyMap());
+                    outerElementProperties = renamingMap(namespace).getOrDefault(localPart, Map.of());
                     break;
                 }
             }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java b/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
index 0081be869e..04269a6334 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/MetadataAssert.java
@@ -30,7 +30,6 @@ import org.opengis.metadata.content.FeatureCatalogueDescription;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.test.xml.DocumentComparator;
 import org.apache.sis.internal.xml.LegacyNamespaces;
-import org.apache.sis.internal.util.CollectionsExt;
 
 import static org.apache.sis.test.TestUtilities.getSingleton;
 
@@ -121,7 +120,7 @@ public strictfp class MetadataAssert extends Assert {
         final Scope scope = source.getScope();
         assertNotNull("metadata.lineage.source.scope", scope);
         assertEquals("metadata.lineage.source.scope.level", ScopeCode.FEATURE_TYPE, scope.getLevel());
-        final CharSequence[] actual = CollectionsExt.toArray(getSingleton(scope.getLevelDescription()).getFeatures(), CharSequence.class);
+        final var actual = getSingleton(scope.getLevelDescription()).getFeatures().toArray(CharSequence[]::new);
         for (int i=0; i<actual.length; i++) {
             actual[i] = actual[i].toString();
         }
diff --git a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/MultiResolutionCoverageLoader.java b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/MultiResolutionCoverageLoader.java
index 997ebdb70b..bb54bff5e7 100644
--- a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/MultiResolutionCoverageLoader.java
+++ b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/coverage/MultiResolutionCoverageLoader.java
@@ -34,7 +34,6 @@ import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridRoundingMode;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.math.DecimalFunctions;
 import org.apache.sis.io.TableAppender;
 
@@ -125,7 +124,7 @@ public class MultiResolutionCoverageLoader {
         this.resource  = resource;
         areaOfInterest = domain;
         readRanges     = range;
-        double[][] resolutions = CollectionsExt.toArray(resource.getResolutions(), double[].class);
+        double[][] resolutions = resource.getResolutions().toArray(double[][]::new);
         if (resolutions.length <= 1) {
             final GridGeometry gg = resource.getGridGeometry();
             if (resolutions.length != 0) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
index b1ca5ec52f..afec836244 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
@@ -49,7 +49,6 @@ import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.Conversion;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.referencing.provider.TransverseMercator;
 import org.apache.sis.internal.referencing.provider.PolarStereographicA;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
@@ -641,7 +640,7 @@ public class GeodeticObjectBuilder extends Builder<GeodeticObjectBuilder> {
         }
         ArgumentChecks.ensureValidIndex(srcDim - repDim, firstDimension);
         if (source instanceof CompoundCRS) {
-            final CoordinateReferenceSystem[] components = CollectionsExt.toArray(((CompoundCRS) source).getComponents(), CoordinateReferenceSystem.class);
+            final var components = ((CompoundCRS) source).getComponents().toArray(CoordinateReferenceSystem[]::new);
             int lower = 0;
             for (int i=0; i<components.length; i++) {
                 final CoordinateReferenceSystem c = components[i];
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
index cdd7cb9ddd..130abbc8ec 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
@@ -19,8 +19,6 @@ package org.apache.sis.referencing.factory;
 import java.util.Date;
 import java.util.Locale;
 import java.util.Map;
-import java.util.HashMap;
-import java.util.Collections;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
@@ -53,7 +51,6 @@ import org.apache.sis.internal.referencing.MergedProperties;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.internal.system.Semaphores;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.util.iso.AbstractFactory;
 import org.apache.sis.util.resources.Messages;
@@ -249,13 +246,8 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory
      *
      * @param  properties  the default properties, or {@code null} if none.
      */
-    public GeodeticObjectFactory(Map<String,?> properties) {
-        if (properties == null || properties.isEmpty()) {
-            properties = Collections.emptyMap();
-        } else {
-            properties = CollectionsExt.compact(new HashMap<>(properties));
-        }
-        defaultProperties = properties;
+    public GeodeticObjectFactory(final Map<String,?> properties) {
+        defaultProperties = (properties != null) ? Map.copyOf(properties) : Map.of();
         pool = new WeakHashSet<>(AbstractIdentifiedObject.class);
         parser = new AtomicReference<>();
     }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
index c0988e6453..3f8a768c9b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
@@ -18,7 +18,6 @@ package org.apache.sis.referencing.operation;
 
 import java.util.Map;
 import java.util.HashMap;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import org.opengis.util.FactoryException;
@@ -41,7 +40,6 @@ import org.apache.sis.internal.referencing.CoordinateOperations;
 import org.apache.sis.internal.referencing.ReferencingFactoryContainer;
 import org.apache.sis.internal.referencing.ReferencingUtilities;
 import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.URLs;
 import org.apache.sis.referencing.CRS;
@@ -97,10 +95,8 @@ public class DefaultCoordinateOperationFactory extends AbstractFactory implement
     static final boolean USE_EPSG_FACTORY = true;
 
     /**
-     * The default properties, or an empty map if none. This map shall not change after construction in
-     * order to allow usage without synchronization in multi-thread context. But we do not need to wrap
-     * in a unmodifiable map since {@code DefaultCoordinateOperationFactory} does not provide public
-     * access to it.
+     * The default properties, or an empty map if none. This map shall be immutable
+     * in order to allow usage without synchronization in multi-thread context.
      */
     private final Map<String,?> defaultProperties;
 
@@ -163,7 +159,7 @@ public class DefaultCoordinateOperationFactory extends AbstractFactory implement
     @SuppressWarnings("ResultOfMethodCallIgnored")
     public DefaultCoordinateOperationFactory(Map<String,?> properties, final MathTransformFactory factory) {
         if (properties == null || properties.isEmpty()) {
-            properties = Collections.emptyMap();
+            properties = Map.of();
         } else {
             String key   = null;
             Object value = null;
@@ -181,7 +177,7 @@ public class DefaultCoordinateOperationFactory extends AbstractFactory implement
                         .getString(Errors.Keys.IllegalPropertyValueClass_2, key, Classes.getClass(value)));
             }
             properties.remove(ReferencingFactoryContainer.DATUM_FACTORY);
-            properties = CollectionsExt.compact(properties);
+            properties = Map.copyOf(properties);
         }
         defaultProperties = properties;
         if (factory != null) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
index 566185a50d..0803fdeb29 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
@@ -18,7 +18,6 @@ package org.apache.sis.internal.util;
 
 import java.util.*;
 import java.lang.reflect.Array;
-import java.util.function.Predicate;
 import org.opengis.util.CodeList;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Numbers;
@@ -48,6 +47,11 @@ import static org.apache.sis.util.collection.Containers.hashMapCapacity;
  * purpose of a geospatial library and may change at any time. Some method contracts are a little
  * bit tedious to explain, which is another indication that they should not be in public API.
  *
+ * <h2>Null values</h2>
+ * All methods in this class accepts null values. The collections created by this class also accept null.
+ * This class prefers {@link Collections} methods instead of the new static {@code of(…)} method in interfaces
+ * because the former accept null values while the latter throws {@link NullPointerException}.
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @version 1.4
  * @since   0.3
@@ -335,7 +339,8 @@ public final class CollectionsExt extends Static {
      * sense of {@link Object#equals(Object)}, then only the last instance of the duplicated
      * values will be included in the returned set.
      *
-     * <p>This method differs from {@link Set#of(Object...)} in that it preserves element order.</p>
+     * <p>This method differs from {@link Set#of(Object...)} in that it preserves element order
+     * and optionally accepts null elements.</p>
      *
      * @param  <E>          the type of array elements.
      * @param  excludeNull  {@code true} for excluding the {@code null} element from the returned set.
@@ -383,30 +388,24 @@ public final class CollectionsExt extends Static {
      * <strong>not</strong> be modified after this method call. In case of doubt, use the
      * standard {@link Collections#unmodifiableSet(Set)} method instead.</p>
      *
+     * <p>This method differs from {@link Set#copyOf(Collection)} in that it may avoid copy,
+     * preserves element order and optionally null elements.</p>
+     *
      * @param  <E>  the type of elements in the set.
      * @param  set  the set to make unmodifiable, or {@code null}.
      * @return a unmodifiable version of the given set, or {@code null} if the given set was null.
      *
      * @see #compact(Set)
      */
-    public static <E> Set<E> unmodifiableOrCopy(Set<E> set) {
-        if (set != null) {
-            switch (set.size()) {
-                case 0: {
-                    set = Collections.emptySet();
-                    break;
-                }
-                case 1: {
-                    set = Collections.singleton(set.iterator().next());
-                    break;
-                }
-                default: {
-                    set = Collections.unmodifiableSet(set);
-                    break;
-                }
-            }
+    public static <E> Set<E> unmodifiableOrCopy(final Set<E> set) {
+        if (set == null) {
+            return null;
+        }
+        switch (set.size()) {
+            case 0:  return Collections.emptySet();
+            case 1:  return Collections.singleton(set.iterator().next());
+            default: return Collections.unmodifiableSet(set);
         }
-        return set;
     }
 
     /**
@@ -420,34 +419,28 @@ public final class CollectionsExt extends Static {
      * <strong>not</strong> be modified after this method call. In case of doubt, use the
      * standard {@link Collections#unmodifiableMap(Map)} method instead.</p>
      *
+     * <p>This method differs from {@link Map#copyOf(Map)} in that it may avoid copy,
+     * preserves element order and optionally null elements.</p>
+     *
      * @param  <K>  the type of keys in the map.
      * @param  <V>  the type of values in the map.
      * @param  map  the map to make unmodifiable, or {@code null}.
      * @return a unmodifiable version of the given map, or {@code null} if the given map was null.
      *
      * @see #compact(Map)
-     *
-     * @todo Replace by {@code Map.copyOf(Map)} on JDK10, except when order matter ({@link LinkedHashMap}).
      */
-    public static <K,V> Map<K,V> unmodifiableOrCopy(Map<K,V> map) {
-        if (map != null) {
-            switch (map.size()) {
-                case 0: {
-                    map = Collections.emptyMap();
-                    break;
-                }
-                case 1: {
-                    final Map.Entry<K,V> entry = map.entrySet().iterator().next();
-                    map = Collections.singletonMap(entry.getKey(), entry.getValue());
-                    break;
-                }
-                default: {
-                    map = Collections.unmodifiableMap(map);
-                    break;
-                }
+    public static <K,V> Map<K,V> unmodifiableOrCopy(final Map<K,V> map) {
+        if (map == null) {
+            return null;
+        }
+        switch (map.size()) {
+            case 0: return Collections.emptyMap();
+            case 1: {
+                final Map.Entry<K,V> entry = map.entrySet().iterator().next();
+                return Collections.singletonMap(entry.getKey(), entry.getValue());
             }
+            default: return Collections.unmodifiableMap(map);
         }
-        return map;
     }
 
     /**
@@ -626,55 +619,13 @@ public final class CollectionsExt extends Static {
         return map;
     }
 
-    /**
-     * Returns a more compact representation of the given set. This method is similar to
-     * {@link #unmodifiableOrCopy(Set)} except that it does not wrap the set in an unmodifiable
-     * view. The intent is to avoid one level of indirection for performance and memory reasons.
-     * This is okay only if the set is kept in a private field and never escape outside that class.
-     *
-     * @param  <E>  the type of elements in the set.
-     * @param  set  the set to compact, or {@code null}.
-     * @return a unmodifiable version of the given set, or {@code null} if the given set was null.
-     *
-     * @see #unmodifiableOrCopy(Set)
-     */
-    public static <E> Set<E> compact(final Set<E> set) {
-        if (set != null) {
-            switch (set.size()) {
-                case 0: return Collections.emptySet();
-                case 1: return Collections.singleton(set.iterator().next());
-            }
-        }
-        return set;
-    }
-
-    /**
-     * Returns a more compact representation of the given list. This method is similar to
-     * {@link #unmodifiableOrCopy(List)} except that it does not wrap the list in an unmodifiable view.
-     * The intent is to avoid one level of indirection for performance and memory reasons.
-     * This is okay only if the list is kept in a private field and never escape outside that class.
-     *
-     * @param  <E>   the type of elements in the list.
-     * @param  list  the list to compact, or {@code null}.
-     * @return a unmodifiable version of the given list, or {@code null} if the given list was null.
-     *
-     * @see #unmodifiableOrCopy(List)
-     */
-    public static <E> List<E> compact(final List<E> list) {
-        if (list != null) {
-            switch (list.size()) {
-                case 0: return Collections.emptyList();
-                case 1: return Collections.singletonList(list.get(0));
-            }
-        }
-        return list;
-    }
-
     /**
      * Returns a snapshot of the given list. The returned list will not be affected by changes
      * in the given list after this method call. This method makes no guaranteed about whether
      * the returned list is modifiable or not.
      *
+     * <p>This method differs from {@link List#copyOf(Collection)} in that it accepts null elements.</p>
+     *
      * @param  <E>   the type of elements in the list.
      * @param  list  the list for which to take a snapshot, or {@code null} if none.
      * @return a snapshot of the given list, or {@code list} itself if null or unmodifiable.
@@ -736,13 +687,6 @@ public final class CollectionsExt extends Static {
      * <p>Note that in the {@link Iterator} and {@link Enumeration} cases, the given value object
      * is not valid anymore after this method call since it has been used for the iteration.</p>
      *
-     * <p>If the returned object needs to be a list, then this method can be chained
-     * with {@link #toList(Collection)} as below:</p>
-     *
-     * {@preformat java
-     *     List<?> list = toList(toCollection(object));
-     * }
-     *
      * @param  value  the value to return as a collection, or {@code null}.
      * @return the value as a collection, or wrapped in a collection (never {@code null}).
      */
@@ -799,36 +743,8 @@ public final class CollectionsExt extends Static {
     }
 
     /**
-     * Casts or copies the given collection to a list. Special cases:
-     *
-     * <ul>
-     *   <li>If the given collection is {@code null}, then this method returns {@code null}.</li>
-     *   <li>If the given collection is already a list, then it is returned unchanged.</li>
-     *   <li>Otherwise the elements are copied in a new list, which is returned.</li>
-     * </ul>
-     *
-     * This method can be chained with {@link #toCollection(Object)}
-     * for handling a wider range of types:
-     *
-     * {@preformat java
-     *     List<?> list = toList(toCollection(object));
-     * }
-     *
-     * @param  <T>         the type of elements in the given collection.
-     * @param  collection  the collection to cast or copy to a list.
-     * @return the given collection as a list, or a copy of the given collection.
-     */
-    public static <T> List<T> toList(final Collection<T> collection) {
-        if (collection instanceof List<?>) {
-            return (List<T>) collection;
-        }
-        return new ArrayList<>(collection);
-    }
-
-    /**
-     * Returns the elements of the given collection as an array. This method can be used when the {@code valueClass}
-     * argument is not known at compile-time. If the {@code valueClass} is known at compile-time, then callers should
-     * use {@link Collection#toArray(Object[])} instead.
+     * Returns the elements of the given collection as an array.
+     * This method can be used when the {@code valueClass} argument is not known at compile-time.
      *
      * @param  <T>         the compile-time value of {@code valueClass}.
      * @param  collection  the collection from which to get the elements.
@@ -836,8 +752,6 @@ public final class CollectionsExt extends Static {
      * @return the collection elements as an array, or {@code null} if {@code collection} is null.
      *
      * @since 0.6
-     *
-     * @todo Remove after migration to JDK11.
      */
     @SuppressWarnings("unchecked")
     public static <T> T[] toArray(final Collection<? extends T> collection, final Class<T> valueClass) {
@@ -964,57 +878,6 @@ public final class CollectionsExt extends Static {
         return map;
     }
 
-    /**
-     * Returns an iterator over the elements of the given iterator where the predicate returns {@code true}.
-     * The iterator may return {@code null} elements.
-     *
-     * @param  <E>     type of elements in the iterator to return.
-     * @param  it      the iterator to filter.
-     * @param  filter  the predicate to use for filtering elements.
-     * @return an iterator over filtered elements.
-     */
-    public static <E> Iterator<E> filter(final Iterator<E> it, final Predicate<? super E> filter) {
-        return new Iterator<E>() {
-            /** Whether the {@code next} element has been verified as valid. */
-            private boolean valid;
-
-            /** The next element to return. */
-            private E next;
-
-            /** Tests whether there is more elements to return. */
-            @Override public boolean hasNext() {
-                if (!valid) {
-                    do {
-                        if (!it.hasNext()) {
-                            return false;
-                        }
-                        next = it.next();
-                    } while (!filter.test(next));
-                    valid = true;
-                }
-                return true;
-            }
-
-            /**
-             * Returns the next element. If there are no more elements,
-             * the exception will be thrown by the wrapped iterator.
-             */
-            @Override public E next() {
-                if (!valid) {
-                    do next = it.next();
-                    while (!filter.test(next));
-                }
-                valid = false;
-                return next;
-            }
-
-            /** Remove the last element returned by the iterator. */
-            @Override public void remove() {
-                it.remove();
-            }
-        };
-    }
-
     /**
      * Returns {@code true} if the next elements returned by the given iterators are the same.
      * This method compares using the identity operation ({@code ==}), not {@code equals(Object)}.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitDimension.java b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitDimension.java
index 7767533ae7..d8a425e80d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitDimension.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitDimension.java
@@ -130,7 +130,7 @@ final class UnitDimension implements Dimension, Serializable {
         }
         /*
          * Implementation note: following code duplicates the functionality of Map.computeIfAbsent(…),
-         * but we had to do it because we compute not only the value, but also the 'components' key.
+         * but we had to do it because we compute not only the value, but also the `components` key.
          */
         UnitDimension dim = (UnitDimension) UnitRegistry.get(components);
         if (dim == null) {
@@ -239,7 +239,7 @@ final class UnitDimension implements Dimension, Serializable {
         }
         /*
          * Fallback for non-SIS implementations. The cast from <? extends Dimension> to <Dimension>
-         * is safe if we use the 'components' map as a read-only map (no put operation allowed).
+         * is safe if we use the `components` map as a read-only map (no put operation allowed).
          */
         @SuppressWarnings("unchecked")
         Map<Dimension,Integer> components = (Map<Dimension,Integer>) dimension.getBaseDimensions();
@@ -352,8 +352,8 @@ final class UnitDimension implements Dimension, Serializable {
             final UnitDimension that = (UnitDimension) other;
             if (symbol == that.symbol) {
                 /*
-                 * Do not compare 'components' if 'symbols' is non-zero because in such case
-                 * the components map contains 'this', which would cause an infinite loop.
+                 * Do not compare `components` if `symbols` is non-zero because in such case
+                 * the components map contains `this`, which would cause an infinite loop.
                  */
                 return (symbol != 0) || components.equals(that.components);
             }
@@ -367,8 +367,8 @@ final class UnitDimension implements Dimension, Serializable {
     @Override
     public int hashCode() {
         /*
-         * Do not use 'components' in hash code calculation if 'symbols' is non-zero
-         * beause in such case the map contains 'this', which would cause an infinite loop.
+         * Do not use `components` in hash code calculation if `symbols` is non-zero
+         * beause in such case the map contains `this`, which would cause an infinite loop.
          */
         return (symbol != 0) ? symbol ^ (int) serialVersionUID : components.hashCode();
     }
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/CollectionsExtTest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/util/CollectionsExtTest.java
index d8dcb5aeb0..7b8fb254f1 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/CollectionsExtTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/CollectionsExtTest.java
@@ -30,7 +30,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Locale;
-import java.util.function.Predicate;
 import org.apache.sis.util.collection.CodeListSet;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -42,7 +41,7 @@ import static org.apache.sis.test.Assert.*;
  * Tests the {@link CollectionsExt} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.4
  * @since   0.3
  * @module
  */
@@ -151,21 +150,6 @@ public final strictfp class CollectionsExtTest extends TestCase {
         }
     }
 
-    /**
-     * Tests {@link CollectionsExt#filter(Iterator, Predicate)}.
-     */
-    @Test
-    public void testFilter() {
-        final Iterator<Integer> it = CollectionsExt.filter(Arrays.asList(2, 5, 7, 4, 8).iterator(), (Integer n) -> (n & 1) == 0);
-        assertTrue  (   it.hasNext());
-        assertEquals(2, it.next().intValue());
-        assertEquals(4, it.next().intValue());
-        assertTrue  (   it.hasNext());
-        assertTrue  (   it.hasNext());
-        assertEquals(8, it.next().intValue());
-        assertFalse (   it.hasNext());
-    }
-
     /**
      * Tests {@link CollectionsExt#identityEquals(Iterator, Iterator)}.
      */
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java
index 7e266da25a..dd83644e2d 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java
@@ -40,7 +40,6 @@ import org.apache.sis.internal.storage.MemoryGridResource;
 import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.internal.storage.RangeArgument;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.ArraysExt;
 
@@ -276,7 +275,7 @@ final class ConcatenatedGridResource extends AbstractGridCoverageResource implem
         if (common == null) {
             int count = 0;
             for (final GridCoverageResource slice : slices) {
-                final double[][] sr = CollectionsExt.toArray(slice.getResolutions(), double[].class);
+                final double[][] sr = slice.getResolutions().toArray(double[][]::new);
                 if (sr != null) {                       // Should never be null, but we are paranoiac.
                     if (common == null) {
                         common = sr;
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/event/StoreListeners.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/event/StoreListeners.java
index ab90b1c4b7..804badd303 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/event/StoreListeners.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/event/StoreListeners.java
@@ -40,7 +40,6 @@ import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.storage.Resources;
 import org.apache.sis.internal.storage.StoreResource;
 import org.apache.sis.internal.storage.StoreUtilities;
-import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.Strings;
 import org.apache.sis.storage.DataStoreProvider;
 import org.apache.sis.storage.DataStore;
@@ -899,7 +898,7 @@ public class StoreListeners implements Localized {
                 throw illegalEventType(type);
             }
         }
-        permittedEventTypes = READ_EVENT_TYPES.equals(types) ? READ_EVENT_TYPES : CollectionsExt.compact(types);
+        permittedEventTypes = READ_EVENT_TYPES.equals(types) ? READ_EVENT_TYPES : Set.copyOf(types);
         ForType.removeUnreachables(listeners, types);
     }