Emulate new methods for Comparator in Java 8.

Started from https://gwt-review.googlesource.com/#/c/13730/

Change-Id: I0d4c6da1a260fb3d89cf528d604b1c632d5adba4
diff --git a/user/super/com/google/gwt/emul/java/util/Comparator.java b/user/super/com/google/gwt/emul/java/util/Comparator.java
index 563608b..e0a9813 100644
--- a/user/super/com/google/gwt/emul/java/util/Comparator.java
+++ b/user/super/com/google/gwt/emul/java/util/Comparator.java
@@ -15,6 +15,14 @@
  */
 package java.util;
 
+import static javaemul.internal.InternalPreconditions.checkCriticalNotNull;
+
+import java.io.Serializable;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
 /**
  * An interface used a basis for implementing custom ordering. <a
  * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html">[Sun
@@ -22,6 +30,7 @@
  *
  * @param <T> the type to be compared.
  */
+@FunctionalInterface
 public interface Comparator<T> {
 
   int compare(T a, T b);
@@ -29,4 +38,84 @@
   @Override
   boolean equals(Object other);
 
+  default Comparator<T> reversed() {
+    return (a, b) -> compare(b, a);
+  }
+
+  default Comparator<T> thenComparing(Comparator<? super T> other) {
+    checkCriticalNotNull(other);
+    return (Comparator<T> & Serializable) (a, b) -> {
+      int c = compare(a, b);
+      return (c != 0) ? c : other.compare(a, b);
+    };
+  }
+
+  default <U> Comparator<T> thenComparing(Function<? super T, ? extends U> keyExtractor,
+      Comparator<? super U> keyComparator) {
+    return thenComparing(comparing(keyExtractor, keyComparator));
+  }
+
+  default <U extends Comparable<? super U>> Comparator<T> thenComparing(
+      Function<? super T, ? extends U> keyExtractor) {
+    return thenComparing(comparing(keyExtractor));
+  }
+
+  default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
+    return thenComparing(comparingInt(keyExtractor));
+  }
+
+  default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
+    return thenComparing(comparingLong(keyExtractor));
+  }
+
+  default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+    return thenComparing(comparingDouble(keyExtractor));
+  }
+
+  static <T, U> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor,
+      Comparator<? super U> keyComparator) {
+    checkCriticalNotNull(keyExtractor);
+    checkCriticalNotNull(keyComparator);
+    return (Comparator<T> & Serializable) (a, b) ->
+        keyComparator.compare(keyExtractor.apply(a), keyExtractor.apply(b));
+  }
+
+  static <T, U extends Comparable<? super U>> Comparator<T> comparing(
+      Function<? super T, ? extends U> keyExtractor) {
+    return comparing(keyExtractor, naturalOrder());
+  }
+
+  static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+    checkCriticalNotNull(keyExtractor);
+    return (Comparator<T> & Serializable) (a, b) ->
+        Double.compare(keyExtractor.applyAsDouble(a), keyExtractor.applyAsDouble(b));
+  }
+
+  static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
+    checkCriticalNotNull(keyExtractor);
+    return (Comparator<T> & Serializable) (a, b) ->
+        Integer.compare(keyExtractor.applyAsInt(a), keyExtractor.applyAsInt(b));
+  }
+
+  static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
+    checkCriticalNotNull(keyExtractor);
+    return (Comparator<T> & Serializable) (a, b) ->
+        Long.compare(keyExtractor.applyAsLong(a), keyExtractor.applyAsLong(b));
+  }
+
+  static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
+    return Comparators.natural();
+  }
+
+  static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
+    return new Comparators.NullComparator<>(true, comparator);
+  }
+
+  static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
+    return new Comparators.NullComparator<>(false, comparator);
+  }
+
+  static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
+    return Comparators.reverseOrder();
+  }
 }
diff --git a/user/super/com/google/gwt/emul/java/util/Comparators.java b/user/super/com/google/gwt/emul/java/util/Comparators.java
index e575a80..b01804c 100644
--- a/user/super/com/google/gwt/emul/java/util/Comparators.java
+++ b/user/super/com/google/gwt/emul/java/util/Comparators.java
@@ -17,31 +17,57 @@
 
 import static javaemul.internal.InternalPreconditions.checkNotNull;
 
+import java.io.Serializable;
+
 class Comparators {
   /*
-   * This is a utility class that provides a default Comparator. This class
+   * This is a utility class that provides default Comparators. This class
    * exists so Arrays and Collections can share the natural comparator without
    * having to know internals of each other.
    *
    * This class is package protected since it is not in the JRE.
    */
 
-  /**
-   * Compares two Objects according to their <i>natural ordering</i>.
-   *
-   * @see java.lang.Comparable
-   */
-  private static final Comparator<Object> NATURAL = new Comparator<Object>() {
-    @Override
-    public int compare(Object o1, Object o2) {
-      checkNotNull(o1);
-      checkNotNull(o2);
-      return ((Comparable<Object>) o1).compareTo(o2);
+  private static final Comparator<Comparable<Object>> NATURAL = (a, b) -> checkNotNull(a).compareTo(checkNotNull(b));
+
+  private static final Comparator<Comparable<Object>> REVERSE_ORDER = (a, b) -> checkNotNull(b).compareTo(checkNotNull(a));
+
+  static final class NullComparator<T> implements Comparator<T>, Serializable {
+    private final boolean nullFirst;
+    private final Comparator<T> delegate;
+
+    @SuppressWarnings("unchecked")
+    NullComparator(boolean nullFirst, Comparator<? super T> delegate) {
+      this.nullFirst = nullFirst;
+      this.delegate = (Comparator<T>) delegate;
     }
-  };
+
+    @Override
+    public int compare(T a, T b) {
+      if (a == null) {
+        return b == null ? 0 : (nullFirst ? -1 : 1);
+      }
+      if (b == null) {
+        return nullFirst ? 1 : -1;
+      }
+      return delegate == null ? 0 : delegate.compare(a, b);
+    }
+
+    @Override
+    public Comparator<T> reversed() {
+      return new NullComparator<>(!nullFirst, delegate == null ? null : delegate.reversed());
+    }
+
+    @Override
+    public Comparator<T> thenComparing(Comparator<? super T> other) {
+      return new NullComparator<>(nullFirst, delegate == null ?
+          other : delegate.thenComparing(other));
+    }
+  }
 
   /**
-   * Returns the natural Comparator.
+   * Returns the natural Comparator which compares two Objects
+   * according to their <i>natural ordering</i>.
    * <p>
    * Example:
    *
@@ -49,7 +75,13 @@
    *
    * @return the natural Comparator
    */
+  @SuppressWarnings("unchecked")
   public static <T> Comparator<T> natural() {
     return (Comparator<T>) NATURAL;
   }
+
+  @SuppressWarnings("unchecked")
+  public static <T> Comparator<T> reverseOrder() {
+    return (Comparator<T>) REVERSE_ORDER;
+  }
 }
diff --git a/user/test/com/google/gwt/emultest/EmulJava8Suite.java b/user/test/com/google/gwt/emultest/EmulJava8Suite.java
index 09394ae..7b311b3 100644
--- a/user/test/com/google/gwt/emultest/EmulJava8Suite.java
+++ b/user/test/com/google/gwt/emultest/EmulJava8Suite.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.emultest;
 
+import com.google.gwt.emultest.java8.util.ComparatorTest;
 import com.google.gwt.emultest.java8.util.DoubleSummaryStatisticsTest;
 import com.google.gwt.emultest.java8.util.IntSummaryStatisticsTest;
 import com.google.gwt.emultest.java8.util.LongSummaryStatisticsTest;
@@ -37,6 +38,7 @@
     GWTTestSuite suite = new GWTTestSuite("Tests for com.google.gwt.emul.java8");
 
     //-- java.util
+    suite.addTestSuite(ComparatorTest.class);
     suite.addTestSuite(OptionalTest.class);
     suite.addTestSuite(OptionalIntTest.class);
     suite.addTestSuite(OptionalLongTest.class);
diff --git a/user/test/com/google/gwt/emultest/java8/util/ComparatorTest.java b/user/test/com/google/gwt/emultest/java8/util/ComparatorTest.java
new file mode 100644
index 0000000..9460571
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java8/util/ComparatorTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.emultest.java8.util;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * Java 8 methods to test in java.util.Comparator.
+ */
+public class ComparatorTest extends EmulTestBase {
+
+  public void testThenComparing() {
+    Supplier<String[]> strings = () -> new String[] {"1,b", "1,a", "2,a"};
+    // expected sort results for 1st and 2nd char, each (f)orward or (r)everse
+    String[] f1f2 = {"1,a", "1,b", "2,a"};
+    String[] f1r2 = {"1,b", "1,a", "2,a"};
+    String[] f2f1 = {"1,a", "2,a" ,"1,b"};
+
+    // keyextractor
+    assertSortedEquals(f1f2, strings,
+        Comparator.<String, String>comparing(s -> s.split(",")[0])
+            .thenComparing(s -> s.split(",")[1])
+    );
+    // keyextractor, keycomparator
+    assertSortedEquals(f1r2, strings,
+        Comparator.<String, String>comparing(s -> s.split(",")[0])
+            .thenComparing(
+                s -> s.split(",")[1],
+                Comparator.<String>reverseOrder()
+            )
+    );
+
+    // int key extractor
+    assertSortedEquals(f2f1, strings,
+        Comparator.<String, String>comparing(s -> s.split(",")[1])
+            .thenComparingInt(
+                s -> Integer.parseInt(s.split(",")[0])
+            )
+    );
+    // long key extractor
+    assertSortedEquals(f2f1, strings,
+        Comparator.<String, String>comparing(s -> s.split(",")[1])
+            .thenComparingLong(
+                s -> Long.parseLong(s.split(",")[0])
+            )
+    );
+    // double key extractor
+    assertSortedEquals(f2f1, strings,
+        Comparator.<String, String>comparing(s -> s.split(",")[1])
+            .thenComparingDouble(
+                s -> Double.parseDouble(s.split(",")[0])
+            )
+    );
+  }
+
+  public void testComparing() {
+    Supplier<String[]> strings = () -> new String[] {"1b3", "2a1", "3c2"};
+    // pre-sorted lists to test against, named for which char (1-indexed) they are sorted on
+    String[] first = {"1b3", "2a1", "3c2"};
+    String[] second = {"2a1", "1b3", "3c2"};
+    String[] secondReversed = {"3c2", "1b3", "2a1"};
+    String[] third = {"2a1", "3c2", "1b3"};
+
+    // keyextractor
+    assertSortedEquals(first, strings, Comparator.comparing(Function.identity()));
+    assertSortedEquals(second, strings, Comparator.comparing(a -> a.substring(1)));
+    assertSortedEquals(third, strings, Comparator.comparing(a -> a.substring(2)));
+
+    // keyextractor, keycomparator
+    assertSortedEquals(secondReversed, strings, Comparator.comparing(a -> a.substring(1), Comparator.<String>reverseOrder()));
+
+    // double key extractor
+    assertSortedEquals(third, strings, Comparator.comparingDouble(a -> Double.parseDouble(a.substring(2))));
+    // int key extractor
+    assertSortedEquals(third, strings, Comparator.comparingInt(a -> Integer.parseInt(a.substring(2))));
+    // long key extractor
+    assertSortedEquals(third, strings, Comparator.comparingLong(a -> Long.parseLong(a.substring(2))));
+  }
+
+  public void testNullsFirst() {
+    Supplier<String[]> strings = () -> new String[]{"a", null, "c", null, "b"};
+    assertSortedEquals(
+        new String[] {null, null, "a", "b", "c"},
+        strings,
+        Comparator.nullsFirst(Comparator.naturalOrder())
+    );
+    assertSortedEquals(
+        new String[] {null, null, "c", "b", "a"},
+        strings,
+        Comparator.nullsFirst(Comparator.reverseOrder())
+    );
+  }
+
+  public void testNullsLast() {
+    Supplier<String[]> strings = () -> new String[]{"a", null, "c", null, "b"};
+    assertSortedEquals(
+        new String[] {"a", "b", "c", null, null},
+        strings,
+        Comparator.nullsLast(Comparator.naturalOrder())
+    );
+    assertSortedEquals(
+        new String[] {"c", "b", "a", null, null},
+        strings,
+        Comparator.nullsLast(Comparator.reverseOrder())
+    );
+  }
+
+  private static void assertSortedEquals(String[] expected, Supplier<String[]> presort, Comparator<String> comparator) {
+    String[] presortedArray = presort.get();
+    Arrays.sort(presortedArray, comparator);
+    assertEquals(expected, presortedArray);
+  }
+}