From 83c573d42712fb3d7970fe7da2282753a82fd860 Mon Sep 17 00:00:00 2001 From: henryjen Date: Tue, 11 Jun 2013 13:41:38 -0700 Subject: [PATCH] 8009736: Comparator API cleanup Reviewed-by: psandoz, briangoetz, mduigou, plevart --- src/share/classes/java/util/Collections.java | 10 + src/share/classes/java/util/Comparator.java | 345 ++++++++++++++++-- src/share/classes/java/util/Comparators.java | 261 ++----------- src/share/classes/java/util/Map.java | 69 ++++ src/share/classes/java/util/TreeMap.java | 4 +- .../java/util/function/BinaryOperator.java | 30 ++ .../classes/java/util/stream/Collectors.java | 21 +- .../java/util/stream/ReferencePipeline.java | 5 +- .../classes/java/util/stream/SortedOps.java | 3 +- test/java/nio/file/Files/StreamTest.java | 16 +- test/java/util/Collection/ListDefaults.java | 19 +- .../BasicTest.java | 285 ++++++--------- test/java/util/Comparator/TypeTest.java | 96 +++++ test/java/util/Map/EntryComparators.java | 139 +++++++ .../function/BinaryOperator/BasicTest.java | 104 ++++++ .../java/util/stream/SequentialOpTest.java | 7 +- .../tests/java/util/stream/SliceOpTest.java | 2 +- .../tests/java/util/stream/SortedOpTest.java | 20 +- .../misc/JavaLangAccess/NewUnsafeString.java | 8 +- 19 files changed, 966 insertions(+), 478 deletions(-) rename test/java/util/{Comparators => Comparator}/BasicTest.java (55%) create mode 100644 test/java/util/Comparator/TypeTest.java create mode 100644 test/java/util/Map/EntryComparators.java create mode 100644 test/java/util/function/BinaryOperator/BasicTest.java diff --git a/src/share/classes/java/util/Collections.java b/src/share/classes/java/util/Collections.java index da258793b..ad4540db1 100644 --- a/src/share/classes/java/util/Collections.java +++ b/src/share/classes/java/util/Collections.java @@ -4304,6 +4304,11 @@ public class Collections { } private Object readResolve() { return Collections.reverseOrder(); } + + @Override + public Comparator> reversed() { + return Comparator.naturalOrder(); + } } /** @@ -4367,6 +4372,11 @@ public class Collections { public int hashCode() { return cmp.hashCode() ^ Integer.MIN_VALUE; } + + @Override + public Comparator reversed() { + return cmp; + } } /** diff --git a/src/share/classes/java/util/Comparator.java b/src/share/classes/java/util/Comparator.java index 017c2e78e..cd65ca4ea 100644 --- a/src/share/classes/java/util/Comparator.java +++ b/src/share/classes/java/util/Comparator.java @@ -25,10 +25,12 @@ package java.util; +import java.io.Serializable; import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; import java.util.function.ToDoubleFunction; +import java.util.Comparators; /** * A comparison function, which imposes a total ordering on some @@ -175,88 +177,357 @@ public interface Comparator { * Returns a comparator that imposes the reverse ordering of this * comparator. * - * @return A comparator that imposes the reverse ordering of this + * @return a comparator that imposes the reverse ordering of this * comparator. * @since 1.8 */ - default Comparator reverseOrder() { + default Comparator reversed() { return Collections.reverseOrder(this); } /** - * Constructs a lexicographic order comparator with another comparator. - * For example, a {@code Comparator byLastName} can be composed - * with another {@code Comparator byFirstName}, then {@code - * byLastName.thenComparing(byFirstName)} creates a {@code - * Comparator} which sorts by last name, and for equal last names - * sorts by first name. - * - * @param other the other comparator used when equals on this. + * Returns a lexicographic-order comparator with another comparator. + * If this {@code Comparator} considers two elements equal, i.e. + * {@code compare(a, b) == 0}, {@code other} is used to determine the order. + * + *

The returned comparator is serializable if the specified comparator + * is also serializable. + * + * @apiNote + * For example, to sort a collection of {@code String} based on the length + * and then case-insensitive natural ordering, the comparator can be + * composed using following code, + * + *

{@code
+     *     Comparator cmp = Comparator.comparing(String::length)
+     *             .thenComparing(String.CASE_INSENSITIVE_ORDER);
+     * }
+ * + * @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 thenComparing(Comparator other) { - return Comparators.compose(this, other); + Objects.requireNonNull(other); + return (Comparator & 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 {@code Comparable} key. This default implementation calls - * {@code thenComparing(this, Comparators.comparing(keyExtractor))}. + * Returns a lexicographic-order comparator with a function that + * extracts a key to be compared with the given {@code Comparator}. + * + * @implSpec This default implementation behaves as if {@code + * thenComparing(comparing(keyExtractor, cmp))}. * - * @param the {@link Comparable} type for comparison - * @param keyExtractor the function used to extract the {@link Comparable} sort key + * @param the type of the sort key + * @param keyExtractor the function used to extract the sort key + * @param keyComparator the {@code Comparator} used to compare the sort key + * @return a lexicographic-order comparator composed of this comparator + * and then comparing on the key extracted by the keyExtractor function * @throws NullPointerException if the argument is null. - * @see Comparators#comparing(Function) + * @see #comparing(Function, Comparator) * @see #thenComparing(Comparator) * @since 1.8 */ - default > Comparator thenComparing(Function keyExtractor) { - return thenComparing(Comparators.comparing(keyExtractor)); + default > Comparator thenComparing( + Function keyExtractor, + Comparator keyComparator) + { + return thenComparing(comparing(keyExtractor, keyComparator)); } /** - * Constructs a lexicographic order comparator with a function that - * extracts a {@code int} value. This default implementation calls {@code - * thenComparing(this, Comparators.comparing(keyExtractor))}. + * Returns a lexicographic-order comparator with a function that + * extracts a {@code Comparable} sort key. + * + * @implSpec This default implementation behaves as if {@code + * thenComparing(comparing(keyExtractor))}. * - * @param keyExtractor the function used to extract the integer value + * @param the type of the {@link Comparable} sort key + * @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} sort key. * @throws NullPointerException if the argument is null. - * @see Comparators#comparing(ToIntFunction) + * @see #comparing(Function) + * @see #thenComparing(Comparator) + * @since 1.8 + */ + default > Comparator thenComparing( + Function keyExtractor) + { + return thenComparing(comparing(keyExtractor)); + } + + /** + * Returns a lexicographic-order comparator with a function that + * extracts a {@code int} sort key. + * + * @implSpec This default implementation behaves as if {@code + * thenComparing(comparing(keyExtractor))}. + * + * @param keyExtractor the function used to extract the integer sort key + * @return a lexicographic-order comparator composed of this and then the + * {@code int} sort key + * @throws NullPointerException if the argument is null. + * @see #comparing(ToIntFunction) * @see #thenComparing(Comparator) * @since 1.8 */ default Comparator thenComparing(ToIntFunction keyExtractor) { - return thenComparing(Comparators.comparing(keyExtractor)); + return thenComparing(comparing(keyExtractor)); } /** - * Constructs a lexicographic order comparator with a function that - * extracts a {@code long} value. This default implementation calls - * {@code thenComparing(this, Comparators.comparing(keyExtractor))}. + * Returns a lexicographic-order comparator with a function that + * extracts a {@code long} sort key. + * + * @implSpec This default implementation behaves as if {@code + * thenComparing(comparing(keyExtractor))}. * - * @param keyExtractor the function used to extract the long value + * @param keyExtractor the function used to extract the long sort key + * @return a lexicographic-order comparator composed of this and then the + * {@code long} sort key * @throws NullPointerException if the argument is null. - * @see Comparators#comparing(ToLongFunction) + * @see #comparing(ToLongFunction) * @see #thenComparing(Comparator) * @since 1.8 */ default Comparator thenComparing(ToLongFunction keyExtractor) { - return thenComparing(Comparators.comparing(keyExtractor)); + return thenComparing(comparing(keyExtractor)); } /** - * Constructs a lexicographic order comparator with a function that - * extracts a {@code double} value. This default implementation calls - * {@code thenComparing(this, Comparators.comparing(keyExtractor))}. + * Returns a lexicographic-order comparator with a function that + * extracts a {@code double} sort key. * - * @param keyExtractor the function used to extract the double value + * @implSpec This default implementation behaves as if {@code + * thenComparing(comparing(keyExtractor))}. + * + * @param keyExtractor the function used to extract the double sort key + * @return a lexicographic-order comparator composed of this and then the + * {@code double} sort key * @throws NullPointerException if the argument is null. - * @see Comparators#comparing(ToDoubleFunction) + * @see #comparing(ToDoubleFunction) * @see #thenComparing(Comparator) * @since 1.8 */ default Comparator thenComparing(ToDoubleFunction keyExtractor) { - return thenComparing(Comparators.comparing(keyExtractor)); + return thenComparing(comparing(keyExtractor)); + } + + /** + * Returns a comparator that imposes the reverse of the natural + * ordering. + * + *

The returned comparator is serializable and throws {@link + * NullPointerException} when comparing {@code null}. + * + * @param the {@link Comparable} type of element to be compared + * @return a comparator that imposes the reverse of the natural + * ordering on {@code Comparable} objects. + * @see Comparable + * @since 1.8 + */ + public static > Comparator reverseOrder() { + return Collections.reverseOrder(); + } + + /** + * Returns a comparator that compares {@link Comparable} objects in natural + * order. + * + *

The returned comparator is serializable and throws {@link + * NullPointerException} when comparing {@code null}. + * + * @param the {@link Comparable} type of element to be compared + * @return a comparator that imposes the natural ordering on {@code + * Comparable} objects. + * @see Comparable + * @since 1.8 + */ + public static > Comparator naturalOrder() { + return (Comparator) Comparators.NaturalOrderComparator.INSTANCE; + } + + /** + * Returns a null-friendly comparator that considers {@code null} to be + * less than non-null. When both are {@code null}, they are considered + * equal. If both are non-null, the specified {@code Comparator} is used + * to determine the order. If the specified comparator is {@code null}, + * then the returned comparator considers all non-null values to be equal. + * + *

The returned comparator is serializable if the specified comparator + * is serializable. + * + * @param the type of the elements to be compared + * @param comparator a {@code Comparator} for comparing non-null values + * @return a comparator that considers {@code null} to be less than + * non-null, and compares non-null objects with the supplied + * {@code Comparator}. + * @since 1.8 + */ + public static Comparator nullsFirst(Comparator comparator) { + return new Comparators.NullComparator(true, comparator); + } + + /** + * Returns a null-friendly comparator that considers {@code null} to be + * greater than non-null. When both are {@code null}, they are considered + * equal. If both are non-null, the specified {@code Comparator} is used + * to determine the order. If the specified comparator is {@code null}, + * then the returned comparator considers all non-null values to be equal. + * + *

The returned comparator is serializable if the specified comparator + * is serializable. + * + * @param the type of the elements to be compared + * @param comparator a {@code Comparator} for comparing non-null values + * @return a comparator that considers {@code null} to be greater than + * non-null, and compares non-null objects with the supplied + * {@code Comparator}. + * @since 1.8 + */ + public static Comparator nullsLast(Comparator comparator) { + return new Comparators.NullComparator(false, comparator); + } + + /** + * Accepts a function that extracts a sort key from a type {@code T}, and + * returns a {@code Comparator} that compares by that sort key using + * the specified {@link Comparator}. + * + *

The returned comparator is serializable if the specified function + * and comparator are both serializable. + * + * @apiNote + * For example, to obtain a {@code Comparator} that compares {@code + * Person} objects by their last name ignoring case differences, + * + *

{@code
+     *     Comparator cmp = Comparator.comparing(
+     *             Person::getLastName,
+     *             String.CASE_INSENSITIVE_ORDER);
+     * }
+ * + * @param the type of element to be compared + * @param the type of the sort key + * @param keyExtractor the function used to extract the sort key + * @param keyComparator the {@code Comparator} used to compare the sort key + * @return a comparator that compares by an extracted key using the + * specified {@code Comparator} + * @throws NullPointerException if either argument is null + * @since 1.8 + */ + public static Comparator comparing( + Function keyExtractor, + Comparator keyComparator) + { + Objects.requireNonNull(keyExtractor); + Objects.requireNonNull(keyComparator); + return (Comparator & Serializable) + (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), + keyExtractor.apply(c2)); + } + + /** + * Accepts a function that extracts a {@link java.lang.Comparable + * Comparable} sort key from a type {@code T}, and returns a {@code + * Comparator} that compares by that sort key. + * + *

The returned comparator is serializable if the specified function + * is also serializable. + * + * @apiNote + * For example, to obtain a {@code Comparator} that compares {@code + * Person} objects by their last name, + * + *

{@code
+     *     Comparator byLastName = Comparator.comparing(Person::getLastName);
+     * }
+ * + * @param the type of element to be compared + * @param the type of the {@code Comparable} sort key + * @param keyExtractor the function used to extract the {@link + * Comparable} sort key + * @return a comparator that compares by an extracted key + * @throws NullPointerException if the argument is null + * @since 1.8 + */ + public static > Comparator comparing( + Function keyExtractor) + { + Objects.requireNonNull(keyExtractor); + return (Comparator & Serializable) + (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); + } + + /** + * Accepts a function that extracts an {@code int} sort key from a type + * {@code T}, and returns a {@code Comparator} that compares by that + * sort key. + * + *

The returned comparator is serializable if the specified function + * is also serializable. + * + * @param the type of element to be compared + * @param keyExtractor the function used to extract the integer sort key + * @return a comparator that compares by an extracted key + * @see #comparing(Function) + * @throws NullPointerException if the argument is null + * @since 1.8 + */ + public static Comparator comparing(ToIntFunction keyExtractor) { + Objects.requireNonNull(keyExtractor); + return (Comparator & Serializable) + (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); + } + + /** + * Accepts a function that extracts a {@code long} sort key from a type + * {@code T}, and returns a {@code Comparator} that compares by that + * sort key. + * + *

The returned comparator is serializable if the specified function is + * also serializable. + * + * @param the type of element to be compared + * @param keyExtractor the function used to extract the long sort key + * @return a comparator that compares by an extracted key + * @see #comparing(Function) + * @throws NullPointerException if the argument is null + * @since 1.8 + */ + public static Comparator comparing(ToLongFunction keyExtractor) { + Objects.requireNonNull(keyExtractor); + return (Comparator & Serializable) + (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); + } + + /** + * Accepts a function that extracts a {@code double} sort key from a type + * {@code T}, and returns a {@code Comparator} that compares by that + * sort key. + * + *

The returned comparator is serializable if the specified function + * is also serializable. + * + * @param the type of element to be compared + * @param keyExtractor the function used to extract the double sort key + * @return a comparator that compares by an extracted key + * @see #comparing(Function) + * @throws NullPointerException if the argument is null + * @since 1.8 + */ + public static Comparator comparing(ToDoubleFunction keyExtractor) { + Objects.requireNonNull(keyExtractor); + return (Comparator & Serializable) + (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); } } diff --git a/src/share/classes/java/util/Comparators.java b/src/share/classes/java/util/Comparators.java index 97b7412f5..a90383210 100644 --- a/src/share/classes/java/util/Comparators.java +++ b/src/share/classes/java/util/Comparators.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,16 +32,9 @@ import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; /** - * This class consists of {@code static} utility methods for comparators. Mostly - * factory method that returns a {@link Comparator}. - * - *

Unless otherwise noted, passing a {@code null} argument to a method in - * this class will cause a {@link NullPointerException} to be thrown. - * - * @see Comparator - * @since 1.8 + * Package private supporting class for {@link Comparator}. */ -public class Comparators { +class Comparators { private Comparators() { throw new AssertionError("no instances"); } @@ -51,231 +44,55 @@ public class Comparators { * * @see Comparable */ - private enum NaturalOrderComparator implements Comparator> { + enum NaturalOrderComparator implements Comparator> { INSTANCE; @Override public int compare(Comparable c1, Comparable c2) { return c1.compareTo(c2); } - } - - /** - * Returns a comparator that imposes the reverse of the natural - * ordering. - * - *

The returned comparator is serializable. - * - * @param {@link Comparable} type - * - * @return A comparator that imposes the reverse of the natural - * ordering on a collection of objects that implement - * the {@link Comparable} interface. - * @see Comparable - */ - public static > Comparator reverseOrder() { - return Collections.reverseOrder(); - } - - /** - * Returns a comparator that imposes the reverse ordering of the specified - * {@link Comparator}. - * - *

The returned comparator is serializable (assuming the specified - * comparator is also serializable). - * - * @param 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 Comparator reverseOrder(Comparator cmp) { - Objects.requireNonNull(cmp); - return Collections.reverseOrder(cmp); - } - - /** - * Gets a comparator compares {@link Comparable} type in natural order. - * - * @param {@link Comparable} type - */ - public static > Comparator naturalOrder() { - return (Comparator) NaturalOrderComparator.INSTANCE; - } - - /** - * Gets a comparator compares {@link Map.Entry} in natural order on key. - * - * @param {@link Comparable} key type - * @param value type - */ - public static , V> Comparator> naturalOrderKeys() { - return (Comparator> & Serializable) - (c1, c2) -> c1.getKey().compareTo(c2.getKey()); - } - - /** - * Gets a comparator compares {@link Map.Entry} in natural order on value. - * - * @param key type - * @param {@link Comparable} value type - */ - public static > Comparator> naturalOrderValues() { - return (Comparator> & Serializable) - (c1, c2) -> c1.getValue().compareTo(c2.getValue()); - } - - /** - * Gets a comparator compares {@link Map.Entry} by key using the given - * {@link Comparator}. - * - *

The returned comparator is serializable assuming the specified - * comparators are also serializable. - * - * @param key type - * @param value type - * @param cmp the key {@link Comparator} - */ - public static Comparator> byKey(Comparator cmp) { - Objects.requireNonNull(cmp); - return (Comparator> & Serializable) - (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey()); - } - - /** - * Gets a comparator compares {@link Map.Entry} by value using the given - * {@link Comparator}. - * - * @param key type - * @param value type - * @param cmp the value {@link Comparator} - */ - public static Comparator> byValue(Comparator cmp) { - Objects.requireNonNull(cmp); - return (Comparator> & Serializable) - (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue()); - } - /** - * Accepts a function that extracts a {@link java.lang.Comparable - * Comparable} sort key from a type {@code T}, and returns a {@code - * Comparator} that compares by that sort key. For example, if a class - * {@code Person} has a {@code String}-valued getter {@code getLastName}, - * then {@code comparing(Person::getLastName)} would return a {@code - * Comparator} that compares {@code Person} objects by their last - * name. - * - * @param the original element type - * @param the {@link Comparable} type for comparison - * @param keyExtractor the function used to extract the {@link Comparable} sort key - */ - public static > Comparator comparing(Function keyExtractor) { - Objects.requireNonNull(keyExtractor); - return (Comparator & Serializable) - (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); - } - - /** - * Accepts a function that extracts an {@code int} value from a type {@code - * T}, and returns a {@code Comparator} that compares by that value. - * - *

The returned comparator is serializable assuming the specified - * function is also serializable. - * - * @see #comparing(Function) - * @param the original element type - * @param keyExtractor the function used to extract the integer value - */ - public static Comparator comparing(ToIntFunction keyExtractor) { - Objects.requireNonNull(keyExtractor); - return (Comparator & Serializable) - (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); - } - - /** - * Accepts a function that extracts a {@code long} value from a type {@code - * T}, and returns a {@code Comparator} that compares by that value. - * - *

The returned comparator is serializable assuming the specified - * function is also serializable. - * - * @see #comparing(Function) - * @param the original element type - * @param keyExtractor the function used to extract the long value - */ - public static Comparator comparing(ToLongFunction keyExtractor) { - Objects.requireNonNull(keyExtractor); - return (Comparator & Serializable) - (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); + @Override + public Comparator> reversed() { + return Comparator.reverseOrder(); + } } /** - * Accepts a function that extracts a {@code double} value from a type - * {@code T}, and returns a {@code Comparator} that compares by that - * value. - * - *

The returned comparator is serializable assuming the specified - * function is also serializable. - * - * @see #comparing(Function) - * @param the original element type - * @param keyExtractor the function used to extract the double value + * Null-friendly comparators */ - public static Comparator comparing(ToDoubleFunction keyExtractor) { - Objects.requireNonNull(keyExtractor); - return (Comparator & Serializable) - (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); - } + final static class NullComparator implements Comparator, Serializable { + private static final long serialVersionUID = -7569533591570686392L; + private final boolean nullFirst; + // if null, non-null Ts are considered equal + private final Comparator real; + + @SuppressWarnings("unchecked") + NullComparator(boolean nullFirst, Comparator real) { + this.nullFirst = nullFirst; + this.real = (Comparator) real; + } - /** - * 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}, then {@code - * compose(byLastName, byFirstName)} creates a {@code Comparator} - * which sorts by last name, and for equal last names sorts by first name. - * - *

The returned comparator is serializable assuming the specified - * comparators are also serializable. - * - * @param the element type to be compared - * @param first the first comparator - * @param second the secondary comparator used when equals on the first - */ - public static Comparator compose(Comparator first, Comparator second) { - Objects.requireNonNull(first); - Objects.requireNonNull(second); - return (Comparator & Serializable) (c1, c2) -> { - int res = first.compare(c1, c2); - return (res != 0) ? res : second.compare(c1, c2); - }; - } + @Override + public int compare(T a, T b) { + if (a == null) { + return (b == null) ? 0 : (nullFirst ? -1 : 1); + } else if (b == null) { + return nullFirst ? 1: -1; + } else { + return (real == null) ? 0 : real.compare(a, b); + } + } - /** - * 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 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} - */ - public static BinaryOperator lesserOf(Comparator comparator) { - Objects.requireNonNull(comparator); - return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; - } + @Override + public Comparator thenComparing(Comparator other) { + Objects.requireNonNull(other); + return new NullComparator(nullFirst, real == null ? other : real.thenComparing(other)); + } - /** - * 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 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} - */ - public static BinaryOperator greaterOf(Comparator comparator) { - Objects.requireNonNull(comparator); - return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; + @Override + public Comparator reversed() { + return new NullComparator(!nullFirst, real == null ? null : real.reversed()); + } } } diff --git a/src/share/classes/java/util/Map.java b/src/share/classes/java/util/Map.java index bfb72d7f1..8ad16ee83 100644 --- a/src/share/classes/java/util/Map.java +++ b/src/share/classes/java/util/Map.java @@ -28,6 +28,7 @@ package java.util; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; +import java.io.Serializable; /** * An object that maps keys to values. A map cannot contain duplicate keys; @@ -446,6 +447,74 @@ public interface Map { * @see #equals(Object) */ int hashCode(); + + /** + * Returns a comparator that compares {@link Map.Entry} in natural order on key. + * + *

The returned comparator is serializable and throws {@link + * NullPointerException} when comparing an entry with a null key. + * + * @param the {@link Comparable} type of then map keys + * @param the type of the map values + * @return a comparator that compares {@link Map.Entry} in natural order on key. + * @see Comparable + */ + public static , V> Comparator> comparingByKey() { + return (Comparator> & Serializable) + (c1, c2) -> c1.getKey().compareTo(c2.getKey()); + } + + /** + * Returns a comparator that compares {@link Map.Entry} in natural order on value. + * + *

The returned comparator is serializable and throws {@link + * NullPointerException} when comparing an entry with null values. + * + * @param the type of the map keys + * @param the {@link Comparable} type of the map values + * @return a comparator that compares {@link Map.Entry} in natural order on value. + * @see Comparable + */ + public static > Comparator> comparingByValue() { + return (Comparator> & Serializable) + (c1, c2) -> c1.getValue().compareTo(c2.getValue()); + } + + /** + * Returns a comparator that compares {@link Map.Entry} by key using the given + * {@link Comparator}. + * + *

The returned comparator is serializable if the specified comparator + * is also serializable. + * + * @param the type of the map keys + * @param the type of the map values + * @param cmp the key {@link Comparator} + * @return a comparator that compares {@link Map.Entry} by the key. + */ + public static Comparator> comparingByKey(Comparator cmp) { + Objects.requireNonNull(cmp); + return (Comparator> & Serializable) + (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey()); + } + + /** + * Returns a comparator that compares {@link Map.Entry} by value using the given + * {@link Comparator}. + * + *

The returned comparator is serializable if the specified comparator + * is also serializable. + * + * @param the type of the map keys + * @param the type of the map values + * @param cmp the value {@link Comparator} + * @return a comparator that compares {@link Map.Entry} by the value. + */ + public static Comparator> comparingByValue(Comparator cmp) { + Objects.requireNonNull(cmp); + return (Comparator> & Serializable) + (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue()); + } } // Comparison and hashing diff --git a/src/share/classes/java/util/TreeMap.java b/src/share/classes/java/util/TreeMap.java index f34832c85..44d7449e0 100644 --- a/src/share/classes/java/util/TreeMap.java +++ b/src/share/classes/java/util/TreeMap.java @@ -2938,13 +2938,13 @@ public class TreeMap public int characteristics() { return (side == 0 ? Spliterator.SIZED : 0) | - Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED; + Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED; } @Override public Comparator> getComparator() { return tree.comparator != null ? - Comparators.byKey(tree.comparator) : null; + Map.Entry.comparingByKey(tree.comparator) : null; } } } diff --git a/src/share/classes/java/util/function/BinaryOperator.java b/src/share/classes/java/util/function/BinaryOperator.java index e81bce8c5..85b3db797 100644 --- a/src/share/classes/java/util/function/BinaryOperator.java +++ b/src/share/classes/java/util/function/BinaryOperator.java @@ -24,6 +24,9 @@ */ package java.util.function; +import java.util.Objects; +import java.util.Comparator; + /** * An operation upon two operands yielding a result. This is a specialization of * {@code BiFunction} where the operands and the result are all of the same type. @@ -35,4 +38,31 @@ package java.util.function; */ @FunctionalInterface public interface BinaryOperator extends BiFunction { + /** + * Returns 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 + * @return a {@code BinaryOperator} which returns the lesser of its operands, + * according to the supplied {@code Comparator} + * @throws NullPointerException if the argument is null + */ + public static BinaryOperator minBy(Comparator comparator) { + Objects.requireNonNull(comparator); + return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; + } + + /** + * Returns 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 + * @return a {@code BinaryOperator} which returns the greater of its operands, + * according to the supplied {@code Comparator} + * @throws NullPointerException if the argument is null + */ + public static BinaryOperator maxBy(Comparator comparator) { + Objects.requireNonNull(comparator); + return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; + } } diff --git a/src/share/classes/java/util/stream/Collectors.java b/src/share/classes/java/util/stream/Collectors.java index 0d14c888e..8f5e8ff42 100644 --- a/src/share/classes/java/util/stream/Collectors.java +++ b/src/share/classes/java/util/stream/Collectors.java @@ -30,7 +30,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Comparators; import java.util.DoubleSummaryStatistics; import java.util.EnumSet; import java.util.HashMap; @@ -78,7 +77,7 @@ import java.util.function.ToLongFunction; * * // Find highest-paid employee * Employee highestPaid = employees.stream() - * .collect(Collectors.maxBy(Comparators.comparing(Employee::getSalary))); + * .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary))); * * // Group employees by department * Map> byDept @@ -89,7 +88,7 @@ import java.util.function.ToLongFunction; * Map highestPaidByDept * = employees.stream() * .collect(Collectors.groupingBy(Employee::getDepartment, - * Collectors.maxBy(Comparators.comparing(Employee::getSalary)))); + * Collectors.maxBy(Comparator.comparing(Employee::getSalary)))); * * // Partition students into passing and failing * Map> passingFailing = @@ -404,7 +403,7 @@ public final class Collectors { * @implSpec * This produces a result equivalent to: *

{@code
-     *     reducing(Comparators.lesserOf(comparator))
+     *     reducing(BinaryOperator.minBy(comparator))
      * }
* * @param the type of the input elements @@ -413,7 +412,7 @@ public final class Collectors { */ public static Collector minBy(Comparator comparator) { - return reducing(Comparators.lesserOf(comparator)); + return reducing(BinaryOperator.minBy(comparator)); } /** @@ -423,7 +422,7 @@ public final class Collectors { * @implSpec * This produces a result equivalent to: *
{@code
-     *     reducing(Comparators.greaterOf(comparator))
+     *     reducing(BinaryOperator.maxBy(comparator))
      * }
* * @param the type of the input elements @@ -432,7 +431,7 @@ public final class Collectors { */ public static Collector maxBy(Comparator comparator) { - return reducing(Comparators.greaterOf(comparator)); + return reducing(BinaryOperator.maxBy(comparator)); } /** @@ -491,8 +490,8 @@ public final class Collectors { *

For example, given a stream of {@code Person}, to calculate tallest * person in each city: *

{@code
-     *     Comparator byHeight = Comparators.comparing(Person::getHeight);
-     *     BinaryOperator tallerOf = Comparators.greaterOf(byHeight);
+     *     Comparator byHeight = Comparator.comparing(Person::getHeight);
+     *     BinaryOperator tallerOf = BinaryOperator.greaterOf(byHeight);
      *     Map tallestByCity
      *         = people.stream().collect(groupingBy(Person::getCity, reducing(tallerOf)));
      * }
@@ -531,8 +530,8 @@ public final class Collectors { *

For example, given a stream of {@code Person}, to calculate the longest * last name of residents in each city: *

{@code
-     *     Comparator byLength = Comparators.comparing(String::length);
-     *     BinaryOperator longerOf = Comparators.greaterOf(byLength);
+     *     Comparator byLength = Comparator.comparing(String::length);
+     *     BinaryOperator longerOf = BinaryOperator.greaterOf(byLength);
      *     Map longestLastNameByCity
      *         = people.stream().collect(groupingBy(Person::getCity,
      *                                              reducing(Person::getLastName, longerOf)));
diff --git a/src/share/classes/java/util/stream/ReferencePipeline.java b/src/share/classes/java/util/stream/ReferencePipeline.java
index 6e3beca1f..8a86c2d6c 100644
--- a/src/share/classes/java/util/stream/ReferencePipeline.java
+++ b/src/share/classes/java/util/stream/ReferencePipeline.java
@@ -25,7 +25,6 @@
 package java.util.stream;
 
 import java.util.Comparator;
-import java.util.Comparators;
 import java.util.Iterator;
 import java.util.Objects;
 import java.util.Optional;
@@ -512,12 +511,12 @@ abstract class ReferencePipeline
 
     @Override
     public final Optional max(Comparator comparator) {
-        return reduce(Comparators.greaterOf(comparator));
+        return reduce(BinaryOperator.maxBy(comparator));
     }
 
     @Override
     public final Optional min(Comparator comparator) {
-        return reduce(Comparators.lesserOf(comparator));
+        return reduce(BinaryOperator.minBy(comparator));
 
     }
 
diff --git a/src/share/classes/java/util/stream/SortedOps.java b/src/share/classes/java/util/stream/SortedOps.java
index 7b2a6934b..de02ba8e3 100644
--- a/src/share/classes/java/util/stream/SortedOps.java
+++ b/src/share/classes/java/util/stream/SortedOps.java
@@ -27,7 +27,6 @@ package java.util.stream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
-import java.util.Comparators;
 import java.util.Objects;
 import java.util.Spliterator;
 import java.util.concurrent.ForkJoinTask;
@@ -114,7 +113,7 @@ final class SortedOps {
                   StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
             this.isNaturalSort = true;
             // Will throw CCE when we try to sort if T is not Comparable
-            this.comparator = (Comparator) Comparators.naturalOrder();
+            this.comparator = (Comparator) Comparator.naturalOrder();
         }
 
         /**
diff --git a/test/java/nio/file/Files/StreamTest.java b/test/java/nio/file/Files/StreamTest.java
index 0033dd31f..b5ff29772 100644
--- a/test/java/nio/file/Files/StreamTest.java
+++ b/test/java/nio/file/Files/StreamTest.java
@@ -43,7 +43,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Arrays;
-import java.util.Comparators;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -139,7 +139,7 @@ public class StreamTest {
 
     public void testBasic() {
         try (CloseableStream s = Files.list(testFolder)) {
-            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
             assertEquals(actual, level1);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
@@ -155,7 +155,7 @@ public class StreamTest {
 
     public void testWalk() {
         try (CloseableStream s = Files.walk(testFolder)) {
-            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
             assertEquals(actual, all);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
@@ -165,7 +165,7 @@ public class StreamTest {
     public void testWalkOneLevel() {
         try (CloseableStream s = Files.walk(testFolder, 1)) {
             Object[] actual = s.filter(path -> ! path.equals(testFolder))
-                               .sorted(Comparators.naturalOrder())
+                               .sorted(Comparator.naturalOrder())
                                .toArray();
             assertEquals(actual, level1);
         } catch (IOException ioe) {
@@ -177,7 +177,7 @@ public class StreamTest {
         // If link is not supported, the directory structure won't have link.
         // We still want to test the behavior with FOLLOW_LINKS option.
         try (CloseableStream s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
-            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
             assertEquals(actual, all_folowLinks);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
@@ -637,13 +637,13 @@ public class StreamTest {
     public void testClosedStream() throws IOException {
         try (CloseableStream s = Files.list(testFolder)) {
             s.close();
-            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
             assertTrue(actual.length <= level1.length);
         }
 
         try (CloseableStream s = Files.walk(testFolder)) {
             s.close();
-            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
             fail("Operate on closed stream should throw IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
@@ -652,7 +652,7 @@ public class StreamTest {
         try (CloseableStream s = Files.find(testFolder, Integer.MAX_VALUE,
                     (p, attr) -> true)) {
             s.close();
-            Object[] actual = s.sorted(Comparators.naturalOrder()).toArray();
+            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
             fail("Operate on closed stream should throw IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
diff --git a/test/java/util/Collection/ListDefaults.java b/test/java/util/Collection/ListDefaults.java
index 6011fbf78..e0f8e6f69 100644
--- a/test/java/util/Collection/ListDefaults.java
+++ b/test/java/util/Collection/ListDefaults.java
@@ -25,7 +25,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Comparators;
 import java.util.List;
 import java.util.LinkedList;
 import java.util.Stack;
@@ -337,23 +336,23 @@ public class ListDefaults {
 
             CollectionSupplier.shuffle(list);
             list.sort(null);
-            CollectionAsserts.assertSorted(list, Comparators.naturalOrder());
+            CollectionAsserts.assertSorted(list, Comparator.naturalOrder());
             if (test.name.startsWith("reverse")) {
                 Collections.reverse(list);
             }
             CollectionAsserts.assertContents(list, original);
 
             CollectionSupplier.shuffle(list);
-            list.sort(Comparators.naturalOrder());
-            CollectionAsserts.assertSorted(list, Comparators.naturalOrder());
+            list.sort(Comparator.naturalOrder());
+            CollectionAsserts.assertSorted(list, Comparator.naturalOrder());
             if (test.name.startsWith("reverse")) {
                 Collections.reverse(list);
             }
             CollectionAsserts.assertContents(list, original);
 
             CollectionSupplier.shuffle(list);
-            list.sort(Comparators.reverseOrder());
-            CollectionAsserts.assertSorted(list, Comparators.reverseOrder());
+            list.sort(Comparator.reverseOrder());
+            CollectionAsserts.assertSorted(list, Comparator.reverseOrder());
             if (!test.name.startsWith("reverse")) {
                 Collections.reverse(list);
             }
@@ -390,8 +389,8 @@ public class ListDefaults {
                 final List copy = new ArrayList<>(list);
                 final List subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
                 CollectionSupplier.shuffle(subList);
-                subList.sort(Comparators.naturalOrder());
-                CollectionAsserts.assertSorted(subList, Comparators.naturalOrder());
+                subList.sort(Comparator.naturalOrder());
+                CollectionAsserts.assertSorted(subList, Comparator.naturalOrder());
                 // verify that elements [0, from) remain unmodified
                 for (int i = 0; i < SUBLIST_FROM; i++) {
                     assertTrue(list.get(i) == copy.get(i),
@@ -412,8 +411,8 @@ public class ListDefaults {
                 public void call(final List list) {
                     final List copy = new ArrayList<>(list);
                     CollectionSupplier.shuffle(list);
-                    list.sort(Comparators.naturalOrder());
-                    CollectionAsserts.assertSorted(list, Comparators.naturalOrder());
+                    list.sort(Comparator.naturalOrder());
+                    CollectionAsserts.assertSorted(list, Comparator.naturalOrder());
                 }
             });
         }
diff --git a/test/java/util/Comparators/BasicTest.java b/test/java/util/Comparator/BasicTest.java
similarity index 55%
rename from test/java/util/Comparators/BasicTest.java
rename to test/java/util/Comparator/BasicTest.java
index 0913eb84b..5bbb700e0 100644
--- a/test/java/util/Comparators/BasicTest.java
+++ b/test/java/util/Comparator/BasicTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,19 +21,16 @@
  * questions.
  */
 
-/*
+/**
  * @test
- * @bug 8001667 8010279
+ * @summary Comparator default method tests
  * @run testng BasicTest
  */
 
+import java.util.TreeMap;
 import java.util.Comparator;
-import java.util.Comparators;
-import java.util.AbstractMap;
-import java.util.Map;
 import org.testng.annotations.Test;
 
-import java.util.function.BinaryOperator;
 import java.util.function.Function;
 import java.util.function.ToIntFunction;
 import java.util.function.ToLongFunction;
@@ -41,12 +38,8 @@ import java.util.function.ToDoubleFunction;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.assertSame;
 import static org.testng.Assert.fail;
 
-/**
- * Unit tests for helper methods in Comparators
- */
 @Test(groups = "unit")
 public class BasicTest {
     private static class Thing {
@@ -97,7 +90,7 @@ public class BasicTest {
         Thing[] things = new Thing[intValues.length];
         for (int i=0; i comp = Comparators.comparing(new ToIntFunction() {
+        Comparator comp = Comparator.comparing(new ToIntFunction() {
             @Override
             public int applyAsInt(Thing thing) {
                 return thing.getIntField();
@@ -111,7 +104,7 @@ public class BasicTest {
         Thing[] things = new Thing[longValues.length];
         for (int i=0; i comp = Comparators.comparing(new ToLongFunction() {
+        Comparator comp = Comparator.comparing(new ToLongFunction() {
             @Override
             public long applyAsLong(Thing thing) {
                 return thing.getLongField();
@@ -125,7 +118,7 @@ public class BasicTest {
         Thing[] things = new Thing[doubleValues.length];
         for (int i=0; i comp = Comparators.comparing(new ToDoubleFunction() {
+        Comparator comp = Comparator.comparing(new ToDoubleFunction() {
             @Override
             public double applyAsDouble(Thing thing) {
                 return thing.getDoubleField();
@@ -139,7 +132,7 @@ public class BasicTest {
         Thing[] things = new Thing[doubleValues.length];
         for (int i=0; i comp = Comparators.comparing(new Function() {
+        Comparator comp = Comparator.comparing(new Function() {
             @Override
             public String apply(Thing thing) {
                 return thing.getStringField();
@@ -150,16 +143,16 @@ public class BasicTest {
     }
 
     public void testNaturalOrderComparator() {
-        Comparator comp = Comparators.naturalOrder();
+        Comparator comp = Comparator.naturalOrder();
 
         assertComparisons(stringValues, comp, comparisons);
     }
 
     public void testReverseComparator() {
-        Comparator cmpr = Comparators.reverseOrder();
-        Comparator cmp = cmpr.reverseOrder();
+        Comparator cmpr = Comparator.reverseOrder();
+        Comparator cmp = cmpr.reversed();
 
-        assertEquals(cmp.reverseOrder(), cmpr);
+        assertEquals(cmp.reversed(), cmpr);
         assertEquals(0, cmp.compare("a", "a"));
         assertEquals(0, cmpr.compare("a", "a"));
         assertTrue(cmp.compare("a", "b") < 0);
@@ -170,9 +163,9 @@ public class BasicTest {
 
     public void testReverseComparator2() {
         Comparator cmp = (s1, s2) -> s1.length() - s2.length();
-        Comparator cmpr = cmp.reverseOrder();
+        Comparator cmpr = cmp.reversed();
 
-        assertEquals(cmpr.reverseOrder(), cmp);
+        assertEquals(cmpr.reversed(), cmp);
         assertEquals(0, cmp.compare("abc", "def"));
         assertEquals(0, cmpr.compare("abc", "def"));
         assertTrue(cmp.compare("abcd", "def") > 0);
@@ -181,71 +174,11 @@ public class BasicTest {
         assertTrue(cmpr.compare("abc", "defg") > 0);
     }
 
-    @Test(expectedExceptions=NullPointerException.class)
-    public void testReverseComparatorNPE() {
-        Comparator cmp = Comparators.reverseOrder(null);
-    }
-
-    public void testComposeComparator() {
-        // Longer string in front
-        Comparator first = (s1, s2) -> s2.length() - s1.length();
-        Comparator second = Comparators.naturalOrder();
-        Comparator composed = Comparators.compose(first, second);
-
-        assertTrue(composed.compare("abcdefg", "abcdef") < 0);
-        assertTrue(composed.compare("abcdef", "abcdefg") > 0);
-        assertTrue(composed.compare("abcdef", "abcdef") == 0);
-        assertTrue(composed.compare("abcdef", "ghijkl") < 0);
-        assertTrue(composed.compare("ghijkl", "abcdefg") > 0);
-    }
-
-    private  void assertPairComparison(K k1, V v1, K k2, V v2,
-                                        Comparator> ck,
-                                        Comparator> cv) {
-        final Map.Entry p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1);
-        final Map.Entry p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2);
-        final Map.Entry p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1);
-        final Map.Entry p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2);
-
-        assertTrue(ck.compare(p11, p11) == 0);
-        assertTrue(ck.compare(p12, p11) == 0);
-        assertTrue(ck.compare(p11, p12) == 0);
-        assertTrue(ck.compare(p12, p22) < 0);
-        assertTrue(ck.compare(p12, p21) < 0);
-        assertTrue(ck.compare(p21, p11) > 0);
-        assertTrue(ck.compare(p21, p12) > 0);
-
-        assertTrue(cv.compare(p11, p11) == 0);
-        assertTrue(cv.compare(p12, p11) > 0);
-        assertTrue(cv.compare(p11, p12) < 0);
-        assertTrue(cv.compare(p12, p22) == 0);
-        assertTrue(cv.compare(p12, p21) > 0);
-        assertTrue(cv.compare(p21, p11) == 0);
-        assertTrue(cv.compare(p21, p12) < 0);
-
-        Comparator> cmp = Comparators.compose(ck, cv);
-        assertTrue(cmp.compare(p11, p11) == 0);
-        assertTrue(cmp.compare(p12, p11) > 0);
-        assertTrue(cmp.compare(p11, p12) < 0);
-        assertTrue(cmp.compare(p12, p22) < 0);
-        assertTrue(cmp.compare(p12, p21) < 0);
-        assertTrue(cmp.compare(p21, p11) > 0);
-        assertTrue(cmp.compare(p21, p12) > 0);
-
-        cmp = Comparators.compose(cv, ck);
-        assertTrue(cmp.compare(p11, p11) == 0);
-        assertTrue(cmp.compare(p12, p11) > 0);
-        assertTrue(cmp.compare(p11, p12) < 0);
-        assertTrue(cmp.compare(p12, p22) < 0);
-        assertTrue(cmp.compare(p12, p21) > 0);
-        assertTrue(cmp.compare(p21, p11) > 0);
-        assertTrue(cmp.compare(p21, p12) < 0);
-    }
-
-    public void testKVComparatorable() {
-        assertPairComparison(1, "ABC", 2, "XYZ",
-                         Comparators.naturalOrderKeys(),
-                         Comparators.naturalOrderValues());
+    private  void assertComparison(Comparator cmp, T less, T greater) {
+        assertTrue(cmp.compare(less, greater) < 0, "less");
+        assertTrue(cmp.compare(less, less) == 0, "equal");
+        assertTrue(cmp.compare(greater, greater) == 0, "equal");
+        assertTrue(cmp.compare(greater, less) > 0, "greater");
     }
 
     private static class People {
@@ -273,33 +206,15 @@ public class BasicTest {
         new People("Jonah", "Doe", 10),
         new People("John", "Cook", 54),
         new People("Mary", "Cook", 50),
+        new People("Mary", null, 25),
+        new People("John", null, 27)
     };
 
-    public void testKVComparators() {
-        // Comparator cmp = Comparators.naturalOrder(); // Should fail to compiler as People is not comparable
-        // We can use simple comparator, but those have been tested above.
-        // Thus choose to do compose for some level of interation.
-        Comparator cmp1 = Comparators.comparing((Function) People::getFirstName);
-        Comparator cmp2 = Comparators.comparing((Function) People::getLastName);
-        Comparator cmp = Comparators.compose(cmp1, cmp2);
-
-        assertPairComparison(people[0], people[0], people[1], people[1],
-                         Comparators.byKey(cmp),
-                         Comparators.byValue(cmp));
-
-    }
-
-    private  void assertComparison(Comparator cmp, T less, T greater) {
-        assertTrue(cmp.compare(less, greater) < 0, "less");
-        assertTrue(cmp.compare(less, less) == 0, "equal");
-        assertTrue(cmp.compare(greater, less) > 0, "greater");
-    }
-
     public void testComparatorDefaultMethods() {
-        Comparator cmp = Comparators.comparing((Function) People::getFirstName);
-        Comparator cmp2 = Comparators.comparing((Function) People::getLastName);
+        Comparator cmp = Comparator.comparing((Function) People::getFirstName);
+        Comparator cmp2 = Comparator.comparing((Function) People::getLastName);
         // reverseOrder
-        assertComparison(cmp.reverseOrder(), people[1], people[0]);
+        assertComparison(cmp.reversed(), people[1], people[0]);
         // thenComparing(Comparator)
         assertComparison(cmp.thenComparing(cmp2), people[0], people[1]);
         assertComparison(cmp.thenComparing(cmp2), people[4], people[0]);
@@ -317,96 +232,138 @@ public class BasicTest {
         assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]);
     }
 
-    public void testGreaterOf() {
-        // lesser
-        assertSame(Comparators.greaterOf(Comparators.comparing(
-                                    (Function) People::getFirstName))
-                              .apply(people[0], people[1]),
-                   people[1]);
-        // euqal
-        assertSame(Comparators.greaterOf(Comparators.comparing(
-                                    (Function) People::getLastName))
-                              .apply(people[0], people[1]),
-                   people[0]);
-        // greater
-        assertSame(Comparators.greaterOf(Comparators.comparing(
-                                    (ToIntFunction) People::getAge))
-                              .apply(people[0], people[1]),
-                   people[0]);
+
+    public void testNullsFirst() {
+        Comparator strcmp = Comparator.nullsFirst(Comparator.naturalOrder());
+        Comparator cmp = Comparator.comparing(People::getLastName, strcmp)
+                                           .thenComparing(People::getFirstName, strcmp);
+        // Mary.null vs Mary.Cook - solve by last name
+        assertComparison(cmp, people[6], people[5]);
+        // John.null vs Mary.null - solve by first name
+        assertComparison(cmp, people[7], people[6]);
+
+        // More than one thenComparing
+        strcmp = Comparator.nullsFirst(Comparator.comparing((ToIntFunction) String::length)
+                                                 .thenComparing(String.CASE_INSENSITIVE_ORDER));
+        assertComparison(strcmp, null, "abc");
+        assertComparison(strcmp, "ab", "abc");
+        assertComparison(strcmp, "abc", "def");
+        assertEquals(0, strcmp.compare("abc", "ABC"));
+
+        // Ensure reverse still handle null properly
+        Comparator strcmp2 = strcmp.reversed().thenComparing(Comparator.naturalOrder());
+        assertComparison(strcmp2, "abc", null);
+        assertComparison(strcmp2, "abc", "ab");
+        assertComparison(strcmp2, "def", "abc");
+        assertComparison(strcmp2, "ABC", "abc");
+
+        // Considering non-null values to be equal
+        Comparator blind = Comparator.nullsFirst(null);
+        assertComparison(blind, null, "abc");
+        assertEquals(0, blind.compare("abc", "def"));
+        // reverse still consider non-null values to be equal
+        strcmp = blind.reversed();
+        assertComparison(strcmp, "abc", null);
+        assertEquals(0, strcmp.compare("abc", "def"));
+        // chain with another comparator to compare non-nulls
+        strcmp = blind.thenComparing(Comparator.naturalOrder());
+        assertComparison(strcmp, null, "abc");
+        assertComparison(strcmp, "abc", "def");
+    }
+
+    public void testNullsLast() {
+        Comparator strcmp = Comparator.nullsLast(Comparator.naturalOrder());
+        Comparator cmp = Comparator.comparing(People::getLastName, strcmp)
+                                           .thenComparing(People::getFirstName, strcmp);
+        // Mary.null vs Mary.Cook - solve by last name
+        assertComparison(cmp, people[5], people[6]);
+        // John.null vs Mary.null - solve by first name
+        assertComparison(cmp, people[7], people[6]);
+
+        // More than one thenComparing
+        strcmp = Comparator.nullsLast(Comparator.comparing((ToIntFunction) String::length)
+                                                .thenComparing(String.CASE_INSENSITIVE_ORDER));
+        assertComparison(strcmp, "abc", null);
+        assertComparison(strcmp, "ab", "abc");
+        assertComparison(strcmp, "abc", "def");
+
+        // Ensure reverse still handle null properly
+        Comparator strcmp2 = strcmp.reversed().thenComparing(Comparator.naturalOrder());
+        assertComparison(strcmp2, null, "abc");
+        assertComparison(strcmp2, "abc", "ab");
+        assertComparison(strcmp2, "def", "abc");
+        assertComparison(strcmp2, "ABC", "abc");
+
+        // Considering non-null values to be equal
+        Comparator blind = Comparator.nullsLast(null);
+        assertComparison(blind, "abc", null);
+        assertEquals(0, blind.compare("abc", "def"));
+        // reverse still consider non-null values to be equal
+        strcmp = blind.reversed();
+        assertComparison(strcmp, null, "abc");
+        assertEquals(0, strcmp.compare("abc", "def"));
+        // chain with another comparator to compare non-nulls
+        strcmp = blind.thenComparing(Comparator.naturalOrder());
+        assertComparison(strcmp, "abc", null);
+        assertComparison(strcmp, "abc", "def");
     }
 
-    public void testLesserOf() {
-        // lesser
-        assertSame(Comparators.lesserOf(Comparators.comparing(
-                                    (Function) People::getFirstName))
-                              .apply(people[0], people[1]),
-                   people[0]);
-        // euqal
-        assertSame(Comparators.lesserOf(Comparators.comparing(
-                                    (Function) People::getLastName))
-                              .apply(people[0], people[1]),
-                   people[0]);
-        // greater
-        assertSame(Comparators.lesserOf(Comparators.comparing(
-                                    (ToIntFunction) People::getAge))
-                              .apply(people[0], people[1]),
-                   people[1]);
+    public void testComposeComparator() {
+        // Longer string in front
+        Comparator first = (s1, s2) -> s2.length() - s1.length();
+        Comparator second = Comparator.naturalOrder();
+        Comparator composed = first.thenComparing(second);
+
+        assertTrue(composed.compare("abcdefg", "abcdef") < 0);
+        assertTrue(composed.compare("abcdef", "abcdefg") > 0);
+        assertTrue(composed.compare("abcdef", "abcdef") == 0);
+        assertTrue(composed.compare("abcdef", "ghijkl") < 0);
+        assertTrue(composed.compare("ghijkl", "abcdefg") > 0);
     }
 
     public void testNulls() {
         try {
-            Comparators.naturalOrder().compare("abc", (String) null);
+            Comparator.naturalOrder().compare("abc", (String) null);
             fail("expected NPE with naturalOrder");
         } catch (NullPointerException npe) {}
         try {
-            Comparators.naturalOrder().compare((String) null, "abc");
+            Comparator.naturalOrder().compare((String) null, "abc");
             fail("expected NPE with naturalOrder");
         } catch (NullPointerException npe) {}
 
         try {
-            Comparators.reverseOrder().compare("abc", (String) null);
+            Comparator.reverseOrder().compare("abc", (String) null);
             fail("expected NPE with naturalOrder");
         } catch (NullPointerException npe) {}
         try {
-            Comparators.reverseOrder().compare((String) null, "abc");
+            Comparator.reverseOrder().compare((String) null, "abc");
             fail("expected NPE with naturalOrder");
         } catch (NullPointerException npe) {}
 
         try {
-            Comparator> cmp = Comparators.byKey(null);
-            fail("byKey(null) should throw NPE");
+            Comparator cmp = Comparator.comparing((Function) null, Comparator.naturalOrder());
+            fail("comparing(null, cmp) should throw NPE");
         } catch (NullPointerException npe) {}
-
         try {
-            Comparator> cmp = Comparators.byValue(null);
-            fail("byValue(null) should throw NPE");
+            Comparator cmp = Comparator.comparing((Function) People::getFirstName, null);
+            fail("comparing(f, null) should throw NPE");
         } catch (NullPointerException npe) {}
 
         try {
-            Comparator cmp = Comparators.comparing((Function) null);
+            Comparator cmp = Comparator.comparing((Function) null);
             fail("comparing(null) should throw NPE");
         } catch (NullPointerException npe) {}
         try {
-            Comparator cmp = Comparators.comparing((ToIntFunction) null);
+            Comparator cmp = Comparator.comparing((ToIntFunction) null);
             fail("comparing(null) should throw NPE");
         } catch (NullPointerException npe) {}
         try {
-            Comparator cmp = Comparators.comparing((ToLongFunction) null);
+            Comparator cmp = Comparator.comparing((ToLongFunction) null);
             fail("comparing(null) should throw NPE");
         } catch (NullPointerException npe) {}
         try {
-            Comparator cmp = Comparators.comparing((ToDoubleFunction) null);
+            Comparator cmp = Comparator.comparing((ToDoubleFunction) null);
             fail("comparing(null) should throw NPE");
         } catch (NullPointerException npe) {}
-
-        try {
-            BinaryOperator op = Comparators.lesserOf(null);
-            fail("lesserOf(null) should throw NPE");
-        } catch (NullPointerException npe) {}
-
-        try {
-            BinaryOperator op = Comparators.greaterOf(null);
-            fail("lesserOf(null) should throw NPE");
-        } catch (NullPointerException npe) {}
     }
 }
diff --git a/test/java/util/Comparator/TypeTest.java b/test/java/util/Comparator/TypeTest.java
new file mode 100644
index 000000000..b1c8a41cf
--- /dev/null
+++ b/test/java/util/Comparator/TypeTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Comparator API narrowing type test
+ * @run testng TypeTest
+ */
+
+import java.util.function.Function;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Comparator;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit")
+public class TypeTest {
+    static class Person {
+        String name;
+        static Comparator C = (p1, p2) -> p1.name.compareTo(p2.name);
+
+        Person(String name) {
+            this.name = name;
+        }
+
+        String getName() { return name; }
+    }
+
+    static class Employee extends Person {
+        int id;
+        static Comparator C = (e1, e2) -> e1.id - e2.id;
+
+        Employee(int id, String name) {
+            super(name);
+            this.id = id;
+        }
+    }
+
+    static class Manager extends Employee {
+        long reports;
+        static Comparator C = (e1, e2) -> (int) (e1.reports - e2.reports);
+
+        Manager(String name, int id, long reports) {
+            super(id, name);
+            this.reports = reports;
+        }
+    }
+
+    static  void assertOrder(T o1, T o2, Comparator cmp) {
+        if (cmp.compare(o1, o2) > 0) {
+            System.out.println("Fail!!");
+        }
+        if (cmp.compare(o1, o2) == 0) {
+            System.out.println("Equal!!");
+        }
+    }
+
+    public static void main(String[] args) {
+        Manager m1 = new Manager("Manager", 2, 2000);
+        Manager m2 = new Manager("Manager", 4, 1300);
+
+        // Comparator tmp = Person.C;
+
+        // Comparator cmp = Employee.C.thenComparing(Person.C);
+        Comparator cmp = Employee.C.thenComparing(Person.C);
+        assertOrder(m1, m2, Employee.C.thenComparing(Person.C));
+        assertOrder(m1, m2, cmp);
+        assertOrder(m1, new Employee(1, "Z"), Person.C);
+        assertOrder(new Employee(1, "Z"), m2, Employee.C);
+
+        assertOrder(m1, m2, Comparator.comparing(Employee::getName, String.CASE_INSENSITIVE_ORDER));
+
+        Map map = new TreeMap<>();
+        map.entrySet().stream().sorted(Map.Entry.comparingByKey(String.CASE_INSENSITIVE_ORDER));
+    }
+}
diff --git a/test/java/util/Map/EntryComparators.java b/test/java/util/Map/EntryComparators.java
new file mode 100644
index 000000000..ce607a369
--- /dev/null
+++ b/test/java/util/Map/EntryComparators.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8009736 8010279
+ * @run testng EntryComparators
+ */
+import java.util.function.Function;
+import java.util.Comparator;
+import java.util.AbstractMap;
+import java.util.Map;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/**
+ * Unit tests for Map.Entry.comparing
+ */
+@Test(groups = "unit")
+public class EntryComparators {
+
+    private  void assertPairComparison(K k1, V v1, K k2, V v2,
+                                        Comparator> ck,
+                                        Comparator> cv) {
+        final Map.Entry p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1);
+        final Map.Entry p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2);
+        final Map.Entry p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1);
+        final Map.Entry p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2);
+
+        assertTrue(ck.compare(p11, p11) == 0);
+        assertTrue(ck.compare(p12, p11) == 0);
+        assertTrue(ck.compare(p11, p12) == 0);
+        assertTrue(ck.compare(p12, p22) < 0);
+        assertTrue(ck.compare(p12, p21) < 0);
+        assertTrue(ck.compare(p21, p11) > 0);
+        assertTrue(ck.compare(p21, p12) > 0);
+
+        assertTrue(cv.compare(p11, p11) == 0);
+        assertTrue(cv.compare(p12, p11) > 0);
+        assertTrue(cv.compare(p11, p12) < 0);
+        assertTrue(cv.compare(p12, p22) == 0);
+        assertTrue(cv.compare(p12, p21) > 0);
+        assertTrue(cv.compare(p21, p11) == 0);
+        assertTrue(cv.compare(p21, p12) < 0);
+
+        Comparator> cmp = ck.thenComparing(cv);
+        assertTrue(cmp.compare(p11, p11) == 0);
+        assertTrue(cmp.compare(p12, p11) > 0);
+        assertTrue(cmp.compare(p11, p12) < 0);
+        assertTrue(cmp.compare(p12, p22) < 0);
+        assertTrue(cmp.compare(p12, p21) < 0);
+        assertTrue(cmp.compare(p21, p11) > 0);
+        assertTrue(cmp.compare(p21, p12) > 0);
+
+        cmp = cv.thenComparing(ck);
+        assertTrue(cmp.compare(p11, p11) == 0);
+        assertTrue(cmp.compare(p12, p11) > 0);
+        assertTrue(cmp.compare(p11, p12) < 0);
+        assertTrue(cmp.compare(p12, p22) < 0);
+        assertTrue(cmp.compare(p12, p21) > 0);
+        assertTrue(cmp.compare(p21, p11) > 0);
+        assertTrue(cmp.compare(p21, p12) < 0);
+    }
+
+    public void testKVComparables() {
+        assertPairComparison(1, "ABC", 2, "XYZ",
+                         Map.Entry.comparingByKey(),
+                         Map.Entry.comparingByValue());
+    }
+
+    private static class People {
+        final String firstName;
+        final String lastName;
+        final int age;
+
+        People(String first, String last, int age) {
+            firstName = first;
+            lastName = last;
+            this.age = age;
+        }
+
+        String getFirstName() { return firstName; }
+        String getLastName() { return lastName; }
+        int getAge() { return age; }
+    }
+
+    private final People people[] = {
+        new People("John", "Doe", 34),
+        new People("Mary", "Doe", 30),
+    };
+
+    public void testKVComparators() {
+        // Comparator cmp = Comparator.naturalOrder(); // Should fail to compiler as People is not comparable
+        // We can use simple comparator, but those have been tested above.
+        // Thus choose to do compose for some level of interation.
+        Comparator cmp1 = Comparator.comparing((Function) People::getFirstName);
+        Comparator cmp2 = Comparator.comparing((Function) People::getLastName);
+        Comparator cmp = cmp1.thenComparing(cmp2);
+
+        assertPairComparison(people[0], people[0], people[1], people[1],
+                         Map.Entry.comparingByKey(cmp),
+                         Map.Entry.comparingByValue(cmp));
+
+    }
+
+    public void testNulls() {
+        try {
+            Comparator> cmp = Map.Entry.comparingByKey(null);
+            fail("comparingByKey(null) should throw NPE");
+        } catch (NullPointerException npe) {}
+
+        try {
+            Comparator> cmp = Map.Entry.comparingByValue(null);
+            fail("comparingByValue(null) should throw NPE");
+        } catch (NullPointerException npe) {}
+    }
+}
diff --git a/test/java/util/function/BinaryOperator/BasicTest.java b/test/java/util/function/BinaryOperator/BasicTest.java
new file mode 100644
index 000000000..1519fb881
--- /dev/null
+++ b/test/java/util/function/BinaryOperator/BasicTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8009736 8010279
+ * @run testng BasicTest
+ */
+
+import java.util.Comparator;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import org.testng.annotations.Test;
+
+
+import static java.util.function.BinaryOperator.minBy;
+import static java.util.function.BinaryOperator.maxBy;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.fail;
+
+/**
+ * Unit tests for helper methods in Comparators
+ */
+@Test(groups = "unit")
+public class BasicTest {
+
+    private static class People {
+        final String firstName;
+        final String lastName;
+        final int age;
+
+        People(String first, String last, int age) {
+            firstName = first;
+            lastName = last;
+            this.age = age;
+        }
+
+        String getFirstName() { return firstName; }
+        String getLastName() { return lastName; }
+        int getAge() { return age; }
+    }
+
+    private final People people[] = {
+        new People("John", "Doe", 34),
+        new People("Mary", "Doe", 30),
+    };
+
+    public void testMaxBy() {
+        Comparator cmp = Comparator.comparing((Function) People::getFirstName);
+        // lesser
+        assertSame(maxBy(cmp).apply(people[0], people[1]), people[1]);
+        // euqal
+        cmp = Comparator.comparing((Function) People::getLastName);
+        assertSame(maxBy(cmp).apply(people[0], people[1]), people[0]);
+        // greater
+        cmp = Comparator.comparing((ToIntFunction) People::getAge);
+        assertSame(maxBy(cmp).apply(people[0], people[1]), people[0]);
+    }
+
+    public void testLesserOf() {
+        Comparator cmp = Comparator.comparing((Function) People::getFirstName);
+        // lesser
+        assertSame(minBy(cmp).apply(people[0], people[1]), people[0]);
+        // euqal
+        cmp = Comparator.comparing((Function) People::getLastName);
+        assertSame(minBy(cmp).apply(people[0], people[1]), people[0]);
+        // greater
+        cmp = Comparator.comparing((ToIntFunction) People::getAge);
+        assertSame(minBy(cmp).apply(people[0], people[1]), people[1]);
+    }
+
+    public void testNulls() {
+        try {
+            BinaryOperator op = minBy(null);
+            fail("minBy(null) should throw NPE");
+        } catch (NullPointerException npe) {}
+
+        try {
+            BinaryOperator op = maxBy(null);
+            fail("maxBy(null) should throw NPE");
+        } catch (NullPointerException npe) {}
+    }
+}
diff --git a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SequentialOpTest.java b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SequentialOpTest.java
index 793b31dae..efa5c62e6 100644
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SequentialOpTest.java
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SequentialOpTest.java
@@ -22,7 +22,6 @@
  */
 package org.openjdk.tests.java.util.stream;
 
-import java.util.Comparators;
 import java.util.stream.LambdaTestHelpers;
 import java.util.stream.OpTestCase;
 import java.util.stream.StreamTestDataProvider;
@@ -109,9 +108,9 @@ public class SequentialOpTest extends OpTestCase {
                 = new UnaryOperator[] {
                 (UnaryOperator>) s -> s,
                 (UnaryOperator>) s -> s.map(id),
-                (UnaryOperator>) s -> s.sorted(Comparators.naturalOrder()),
-                (UnaryOperator>) s -> s.map(id).sorted(Comparators.naturalOrder()).map(id),
-                (UnaryOperator>) s -> s.filter(LambdaTestHelpers.pEven).sorted(Comparators.naturalOrder()).map(id),
+                (UnaryOperator>) s -> s.sorted(Comparator.naturalOrder()),
+                (UnaryOperator>) s -> s.map(id).sorted(Comparator.naturalOrder()).map(id),
+                (UnaryOperator>) s -> s.filter(LambdaTestHelpers.pEven).sorted(Comparator.naturalOrder()).map(id),
         };
 
         for (int c1Index = 0; c1Index < changers.length; c1Index++) {
diff --git a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java
index ff9400359..29086fa35 100644
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java
@@ -270,7 +270,7 @@ public class SliceOpTest extends OpTestCase {
     public void testLimitSort() {
         List l = countTo(100);
         Collections.reverse(l);
-        exerciseOps(l, s -> s.limit(10).sorted(Comparators.naturalOrder()));
+        exerciseOps(l, s -> s.limit(10).sorted(Comparator.naturalOrder()));
     }
 
     @Test(groups = { "serialization-hostile" })
diff --git a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java
index 93ac4eae3..956dea39e 100644
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java
@@ -40,10 +40,10 @@ public class SortedOpTest extends OpTestCase {
     public void testSorted() {
         assertCountSum(countTo(0).stream().sorted(), 0, 0);
         assertCountSum(countTo(10).stream().sorted(), 10, 55);
-        assertCountSum(countTo(10).stream().sorted(cInteger.reverseOrder()), 10, 55);
+        assertCountSum(countTo(10).stream().sorted(cInteger.reversed()), 10, 55);
 
         List to10 = countTo(10);
-        assertSorted(to10.stream().sorted(cInteger.reverseOrder()).iterator(), cInteger.reverseOrder());
+        assertSorted(to10.stream().sorted(cInteger.reversed()).iterator(), cInteger.reversed());
 
         Collections.reverse(to10);
         assertSorted(to10.stream().sorted().iterator());
@@ -51,7 +51,7 @@ public class SortedOpTest extends OpTestCase {
         Spliterator s = to10.stream().sorted().spliterator();
         assertTrue(s.hasCharacteristics(Spliterator.SORTED));
 
-        s = to10.stream().sorted(cInteger.reverseOrder()).spliterator();
+        s = to10.stream().sorted(cInteger.reversed()).spliterator();
         assertFalse(s.hasCharacteristics(Spliterator.SORTED));
     }
 
@@ -87,8 +87,8 @@ public class SortedOpTest extends OpTestCase {
         assertSorted(result.iterator());
         assertContentsUnordered(data, result);
 
-        result = exerciseOps(data, s -> s.sorted(cInteger.reverseOrder()));
-        assertSorted(result.iterator(), cInteger.reverseOrder());
+        result = exerciseOps(data, s -> s.sorted(cInteger.reversed()));
+        assertSorted(result.iterator(), cInteger.reversed());
         assertContentsUnordered(data, result);
     }
 
@@ -104,23 +104,23 @@ public class SortedOpTest extends OpTestCase {
         assertContentsUnordered(data, result);
 
         result = withData(data)
-                .stream(s -> s.sorted(cInteger.reverseOrder()).sorted(cInteger.reverseOrder()),
+                .stream(s -> s.sorted(cInteger.reversed()).sorted(cInteger.reversed()),
                         new CollectorOps.TestParallelSizedOp())
                 .exercise();
 
-        assertSorted(result, cInteger.reverseOrder());
+        assertSorted(result, cInteger.reversed());
         assertContentsUnordered(data, result);
 
         result = withData(data)
-                .stream(s -> s.sorted().sorted(cInteger.reverseOrder()),
+                .stream(s -> s.sorted().sorted(cInteger.reversed()),
                         new CollectorOps.TestParallelSizedOp())
                 .exercise();
 
-        assertSorted(result, cInteger.reverseOrder());
+        assertSorted(result, cInteger.reversed());
         assertContentsUnordered(data, result);
 
         result = withData(data)
-                .stream(s -> s.sorted(cInteger.reverseOrder()).sorted(),
+                .stream(s -> s.sorted(cInteger.reversed()).sorted(),
                         new CollectorOps.TestParallelSizedOp())
                 .exercise();
 
diff --git a/test/sun/misc/JavaLangAccess/NewUnsafeString.java b/test/sun/misc/JavaLangAccess/NewUnsafeString.java
index 930d57bee..ab608d7dc 100644
--- a/test/sun/misc/JavaLangAccess/NewUnsafeString.java
+++ b/test/sun/misc/JavaLangAccess/NewUnsafeString.java
@@ -22,7 +22,7 @@
  */
 
 import java.util.Objects;
-import java.util.Comparators;
+import java.util.Comparator;
 import sun.misc.JavaLangAccess;
 import sun.misc.SharedSecrets;
 
@@ -48,7 +48,7 @@ public class NewUnsafeString {
         if (!benchmark.equals(constructorCopy)) {
             throw new Error("Copy not equal");
         }
-        if (0 != Objects.compare(benchmark, constructorCopy, Comparators.naturalOrder())) {
+        if (0 != Objects.compare(benchmark, constructorCopy, Comparator.naturalOrder())) {
             throw new Error("Copy not equal");
         }
 
@@ -58,7 +58,7 @@ public class NewUnsafeString {
         if (!benchmark.equals(jlaCopy)) {
             throw new Error("Copy not equal");
         }
-        if (0 != Objects.compare(benchmark, jlaCopy, Comparators.naturalOrder())) {
+        if (0 != Objects.compare(benchmark, jlaCopy, Comparator.naturalOrder())) {
             throw new Error("Copy not equal");
         }
 
@@ -68,7 +68,7 @@ public class NewUnsafeString {
         if (!constructorCopy.equals(jlaCopy)) {
             throw new Error("Copy not equal");
         }
-        if (0 != Objects.compare(constructorCopy, jlaCopy, Comparators.naturalOrder())) {
+        if (0 != Objects.compare(constructorCopy, jlaCopy, Comparator.naturalOrder())) {
             throw new Error("Copy not equal");
         }
 
-- 
GitLab