changeset 7596:fb7b7275d220

8009736: Comparator to allow narrowing type on combinator APIs Reviewed-by: Summary: Allow to narrow return type, add javadoc return tag Allow key extract not limited to Comparable, but use a Comparator of key type.
author henryjen
date Fri, 08 Mar 2013 21:54:17 -0800
parents 79a9684a5542
children c436657091ee
files src/share/classes/java/util/Comparator.java src/share/classes/java/util/Comparators.java
diffstat 2 files changed, 123 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/Comparator.java	Fri Mar 08 16:02:27 2013 -0800
+++ b/src/share/classes/java/util/Comparator.java	Fri Mar 08 21:54:17 2013 -0800
@@ -25,6 +25,7 @@
 
 package java.util;
 
+import java.io.Serializable;
 import java.util.function.Function;
 import java.util.function.ToIntFunction;
 import java.util.function.ToLongFunction;
@@ -179,8 +180,8 @@
      *         comparator.
      * @since 1.8
      */
-    default Comparator<T> reverseOrder() {
-        return Collections.reverseOrder(this);
+    default <S extends T> Comparator<S> reverseOrder() {
+        return (Comparator<S>) Collections.reverseOrder(this);
     }
 
     /**
@@ -191,12 +192,39 @@
      * Comparator<Person>} which sorts by last name, and for equal last names
      * sorts by first name.
      *
-     * @param other the other comparator used when equals on this.
+     * @param  <S>  The type of elements compared by the returned comparator.
+     * @param  other the other comparator to be used when this comparator
+     *         compares two objects that are equal.
+     * @return A lexicographic order comparator composed of this and then the
+     *         other comparator
      * @throws NullPointerException if the argument is null.
      * @since 1.8
      */
-    default Comparator<T> thenComparing(Comparator<? super T> other) {
-        return Comparators.compose(this, other);
+    default <S extends T> Comparator<S> thenComparing(Comparator<? super T> other) {
+        return (Comparator<S> & Serializable) (c1, c2) -> {
+            int res = compare(c1, c2);
+            return (res != 0) ? res : other.compare(c1, c2);
+        };
+    }
+
+    /**
+     * Constructs a lexicographic order comparator with a function that
+     * extracts a key to be compared with the given {@code Comparator}.  This
+     * default implementation calls {@code thenComparing(this,
+     * Comparators.comparing(keyExtractor, cmp))}.
+     *
+     * @param  <S>  The type of elements compared by the returned comparator.
+     * @param  <U>  The type of the key for comparison
+     * @param  keyExtractor the function used to extract the sort key
+     * @return A lexicographic order comparator composed of this and then the
+     *         key comparator.
+     * @throws NullPointerException if the argument is null.
+     * @see Comparators#comparing(Function, Comparator)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default <S extends T, U> Comparator<S> thenComparing(Function<? super T, ? extends U> keyExtractor, Comparator<? super U> cmp) {
+        return thenComparing(Comparators.comparing(keyExtractor, cmp));
     }
 
     /**
@@ -204,14 +232,17 @@
      * extracts a {@code Comparable} key.  This default implementation calls
      * {@code thenComparing(this, Comparators.comparing(keyExtractor))}.
      *
-     * @param <U> the {@link Comparable} type for comparison
-     * @param keyExtractor the function used to extract the {@link Comparable} sort key
+     * @param  <S>  The type of elements compared by the returned comparator.
+     * @param  <U>  The {@link Comparable} type for comparison
+     * @param  keyExtractor the function used to extract the {@link Comparable} sort key
+     * @return A lexicographic order comparator composed of this and then the
+     *         {@link Comparable} key.
      * @throws NullPointerException if the argument is null.
      * @see Comparators#comparing(Function)
      * @see #thenComparing(Comparator)
      * @since 1.8
      */
-    default <U extends Comparable<? super U>> Comparator<T> thenComparing(Function<? super T, ? extends U> keyExtractor) {
+    default <S extends T, U extends Comparable<? super U>> Comparator<S> thenComparing(Function<? super T, ? extends U> keyExtractor) {
         return thenComparing(Comparators.comparing(keyExtractor));
     }
 
@@ -220,13 +251,16 @@
      * extracts a {@code int} value.  This default implementation calls {@code
      * thenComparing(this, Comparators.comparing(keyExtractor))}.
      *
-     * @param keyExtractor the function used to extract the integer value
+     * @param  <S>  The type of elements compared by the returned comparator.
+     * @param  keyExtractor the function used to extract the integer value
+     * @return A lexicographic order comparator composed of this and then the
+     *         {@code int} value
      * @throws NullPointerException if the argument is null.
      * @see Comparators#comparing(ToIntFunction)
      * @see #thenComparing(Comparator)
      * @since 1.8
      */
-    default Comparator<T> thenComparing(ToIntFunction<? super T> keyExtractor) {
+    default <S extends T> Comparator<S> thenComparing(ToIntFunction<? super T> keyExtractor) {
         return thenComparing(Comparators.comparing(keyExtractor));
     }
 
@@ -235,13 +269,16 @@
      * extracts a {@code long} value.  This default implementation calls
      * {@code thenComparing(this, Comparators.comparing(keyExtractor))}.
      *
-     * @param keyExtractor the function used to extract the long value
+     * @param  <S>  The type of elements compared by the returned comparator.
+     * @param  keyExtractor the function used to extract the long value
+     * @return A lexicographic order comparator composed of this and then the
+     *         {@code long} value
      * @throws NullPointerException if the argument is null.
      * @see Comparators#comparing(ToLongFunction)
      * @see #thenComparing(Comparator)
      * @since 1.8
      */
-    default Comparator<T> thenComparing(ToLongFunction<? super T> keyExtractor) {
+    default <S extends T> Comparator<S> thenComparing(ToLongFunction<? super T> keyExtractor) {
         return thenComparing(Comparators.comparing(keyExtractor));
     }
 
@@ -250,13 +287,16 @@
      * extracts a {@code double} value.  This default implementation calls
      * {@code thenComparing(this, Comparators.comparing(keyExtractor))}.
      *
-     * @param keyExtractor the function used to extract the double value
+     * @param  <S>  The type of elements compared by the returned comparator.
+     * @param  keyExtractor the function used to extract the double value
+     * @return A lexicographic order comparator composed of this and then the
+     *         {@code double} value
      * @throws NullPointerException if the argument is null.
      * @see Comparators#comparing(ToDoubleFunction)
      * @see #thenComparing(Comparator)
      * @since 1.8
      */
-    default Comparator<T> thenComparing(ToDoubleFunction<? super T> keyExtractor) {
+    default <S extends T> Comparator<S> thenComparing(ToDoubleFunction<? super T> keyExtractor) {
         return thenComparing(Comparators.comparing(keyExtractor));
     }
 }
--- a/src/share/classes/java/util/Comparators.java	Fri Mar 08 16:02:27 2013 -0800
+++ b/src/share/classes/java/util/Comparators.java	Fri Mar 08 21:54:17 2013 -0800
@@ -66,8 +66,7 @@
      *
      * <p>The returned comparator is serializable.
      *
-     * @param <T> {@link Comparable} type
-     *
+     * @param  <T> {@link Comparable} type
      * @return A comparator that imposes the reverse of the <i>natural
      *         ordering</i> on a collection of objects that implement
      *         the {@link Comparable} interface.
@@ -78,27 +77,12 @@
     }
 
     /**
-     * Returns a comparator that imposes the reverse ordering of the specified
-     * {@link Comparator}.
-     *
-     * <p>The returned comparator is serializable (assuming the specified
-     * comparator is also serializable).
-     *
-     * @param <T> the element type to be compared
-     * @param cmp a comparator whose ordering is to be reversed by the returned
-     *            comparator
-     * @return A comparator that imposes the reverse ordering of the
-     *         specified comparator.
-     */
-    public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
-        Objects.requireNonNull(cmp);
-        return Collections.reverseOrder(cmp);
-    }
-
-    /**
      * Gets a comparator compares {@link Comparable} type in natural order.
      *
-     * @param <T> {@link Comparable} type
+     * @param  <T> {@link Comparable} type
+     * @return A comparator that imposes the <i>natural ordering</i> on a
+     *         collection of objects that implement the {@link Comparable}
+     *         interface.
      */
     public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
         return (Comparator<T>) NaturalOrderComparator.INSTANCE;
@@ -107,8 +91,9 @@
     /**
      * Gets a comparator compares {@link Map.Entry} in natural order on key.
      *
-     * @param <K> {@link Comparable} key type
-     * @param <V> value type
+     * @param  <K> {@link Comparable} key type
+     * @param  <V> value type
+     * @return A comparator compares {@link Map.Entry} in natural order on key.
      */
     public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> naturalOrderKeys() {
         return (Comparator<Map.Entry<K, V>> & Serializable)
@@ -120,6 +105,7 @@
      *
      * @param <K> key type
      * @param <V> {@link Comparable} value type
+     * @return A comparator compares {@link Map.Entry} in natural order on value.
      */
     public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> naturalOrderValues() {
         return (Comparator<Map.Entry<K, V>> & Serializable)
@@ -133,28 +119,49 @@
      * <p>The returned comparator is serializable assuming the specified
      * comparators are also serializable.
      *
-     * @param <K> key type
-     * @param <V> value type
-     * @param cmp the key {@link Comparator}
+     * @param  <K> key type
+     * @param  <V> value type
+     * @param  cmp the key {@link Comparator}
+     * @return A comparator compares {@link Map.Entry} by the key.
      */
     public static <K, V> Comparator<Map.Entry<K, V>> byKey(Comparator<? super K> cmp) {
-        Objects.requireNonNull(cmp);
-        return (Comparator<Map.Entry<K, V>> & Serializable)
-            (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
+        return comparing(Map.Entry<K, V>::getKey, cmp);
     }
 
     /**
      * Gets a comparator compares {@link Map.Entry} by value using the given
      * {@link Comparator}.
      *
-     * @param <K> key type
-     * @param <V> value type
-     * @param cmp the value {@link Comparator}
+     * @param  <K> key type
+     * @param  <V> value type
+     * @param  cmp the value {@link Comparator}
+     * @return A comparator compares {@link Map.Entry} by the value.
      */
     public static <K, V> Comparator<Map.Entry<K, V>> byValue(Comparator<? super V> cmp) {
+        return comparing(Map.Entry<K, V>::getValue, cmp);
+    }
+
+    /**
+     * Accepts a function that extracts a sort key from a type {@code T}, and
+     * returns a {@code Comparator<T>} that compares by that sort key using
+     * specified {@link Comparator}.  For example, if a class {@code Person}
+     * has a {@code String}-valued getter {@code getLastName}, then {@code
+     * comparing(Person::getLastName, String.CASE_INSENSITIVE_ORDER} would
+     * return a {@code Comparator<Person>} that compares {@code Person}
+     * objects by their last name ignoring case differences.
+     *
+     * @param  <T> the original element type
+     * @param  <U> the type for comparison
+     * @param  keyExtractor the function used to extract the sort key
+     * @param  cmp the {@code Comparator} used to compare the sort key
+     * @return A comparator compares by extracted key using specified {@code
+     *         Comparator}
+     */
+    public static <T, U> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor, Comparator<? super U> cmp) {
+        Objects.requireNonNull(keyExtractor);
         Objects.requireNonNull(cmp);
-        return (Comparator<Map.Entry<K, V>> & Serializable)
-            (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> cmp.compare(keyExtractor.apply(c1), keyExtractor.apply(c2));
     }
 
     /**
@@ -166,9 +173,10 @@
      * Comparator<Person>} that compares {@code Person} objects by their last
      * name.
      *
-     * @param <T> the original element type
-     * @param <U> the {@link Comparable} type for comparison
-     * @param keyExtractor the function used to extract the {@link Comparable} sort key
+     * @param  <T> the original element type
+     * @param  <U> the {@link Comparable} type for comparison
+     * @param  keyExtractor the function used to extract the {@link Comparable} sort key
+     * @return A comparator compares by extracted key
      */
     public static <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor) {
         Objects.requireNonNull(keyExtractor);
@@ -177,15 +185,17 @@
     }
 
     /**
-     * Accepts a function that extracts an {@code int} value from a type {@code
-     * T}, and returns a {@code Comparator<T>} that compares by that value.
+     * Accepts a function that extracts an {@code int} value from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * value.
      *
-     * <p>The returned comparator is serializable assuming the specified
+     * <p> The returned comparator is serializable assuming the specified
      * function is also serializable.
      *
+     * @param  <T> the original element type
+     * @param  keyExtractor the function used to extract the integer value
+     * @return A comparator compares by extracted key
      * @see #comparing(Function)
-     * @param <T> the original element type
-     * @param keyExtractor the function used to extract the integer value
      */
     public static <T> Comparator<T> comparing(ToIntFunction<? super T> keyExtractor) {
         Objects.requireNonNull(keyExtractor);
@@ -194,15 +204,17 @@
     }
 
     /**
-     * Accepts a function that extracts a {@code long} value from a type {@code
-     * T}, and returns a {@code Comparator<T>} that compares by that value.
+     * Accepts a function that extracts a {@code long} value from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * value.
      *
-     * <p>The returned comparator is serializable assuming the specified
+     * <p> The returned comparator is serializable assuming the specified
      * function is also serializable.
      *
+     * @param  <T> the original element type
+     * @param  keyExtractor the function used to extract the long value
+     * @return A comparator compares by extracted key
      * @see #comparing(Function)
-     * @param <T> the original element type
-     * @param keyExtractor the function used to extract the long value
      */
     public static <T> Comparator<T> comparing(ToLongFunction<? super T> keyExtractor) {
         Objects.requireNonNull(keyExtractor);
@@ -215,12 +227,13 @@
      * {@code T}, and returns a {@code Comparator<T>} that compares by that
      * value.
      *
-     * <p>The returned comparator is serializable assuming the specified
+     * <p> The returned comparator is serializable assuming the specified
      * function is also serializable.
      *
+     * @param  <T> the original element type
+     * @param  keyExtractor the function used to extract the double value
+     * @return A comparator compares by extracted key
      * @see #comparing(Function)
-     * @param <T> the original element type
-     * @param keyExtractor the function used to extract the double value
      */
     public static<T> Comparator<T> comparing(ToDoubleFunction<? super T> keyExtractor) {
         Objects.requireNonNull(keyExtractor);
@@ -229,36 +242,13 @@
     }
 
     /**
-     * Constructs a lexicographic order from two {@link Comparator}s.  For
-     * example, if you have comparators {@code byLastName} and {@code
-     * byFirstName}, each of type {@code Comparator<Person>}, then {@code
-     * compose(byLastName, byFirstName)} creates a {@code Comparator<Person>}
-     * which sorts by last name, and for equal last names sorts by first name.
-     *
-     * <p>The returned comparator is serializable assuming the specified
-     * comparators are also serializable.
-     *
-     * @param <T> the element type to be compared
-     * @param first the first comparator
-     * @param second the secondary comparator used when equals on the first
-     */
-    public static<T> Comparator<T> compose(Comparator<? super T> first, Comparator<? super T> second) {
-        Objects.requireNonNull(first);
-        Objects.requireNonNull(second);
-        return (Comparator<T> & Serializable) (c1, c2) -> {
-            int res = first.compare(c1, c2);
-            return (res != 0) ? res : second.compare(c1, c2);
-        };
-    }
-
-    /**
      * Constructs a {@link BinaryOperator} which returns the lesser of two elements
      * according to the specified {@code Comparator}
      *
-     * @param comparator A {@code Comparator} for comparing the two values
-     * @param <T> the type of the elements to be compared
+     * @param  comparator A {@code Comparator} for comparing the two values
+     * @param  <T> the type of the elements to be compared
      * @return a {@code BinaryOperator} which returns the lesser of its operands,
-     * according to the supplied {@code Comparator}
+     *         according to the supplied {@code Comparator}
      */
     public static<T> BinaryOperator<T> lesserOf(Comparator<? super T> comparator) {
         return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
@@ -268,10 +258,10 @@
      * Constructs a {@link BinaryOperator} which returns the greater of two elements
      * according to the specified {@code Comparator}
      *
-     * @param comparator A {@code Comparator} for comparing the two values
-     * @param <T> the type of the elements to be compared
+     * @param  comparator A {@code Comparator} for comparing the two values
+     * @param  <T> the type of the elements to be compared
      * @return a {@code BinaryOperator} which returns the greater of its operands,
-     * according to the supplied {@code Comparator}
+     *         according to the supplied {@code Comparator}
      */
     public static<T> BinaryOperator<T> greaterOf(Comparator<? super T> comparator) {
         return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;