8037106: Optimize Arrays.asList(...).forEach
authorpsandoz
Tue, 18 Mar 2014 11:24:38 +0100
changeset 23354 221bf0e3642d
parent 23353 013edb90a29d
child 23355 87227bf950ef
8037106: Optimize Arrays.asList(...).forEach Reviewed-by: alanb, martin, mduigou, ulfzibis
jdk/src/share/classes/java/util/Arrays.java
jdk/test/java/util/Collection/CollectionDefaults.java
jdk/test/java/util/Collection/testlibrary/CollectionSupplier.java
jdk/test/java/util/List/ListDefaults.java
--- a/jdk/src/share/classes/java/util/Arrays.java	Tue Mar 18 11:10:53 2014 +0100
+++ b/jdk/src/share/classes/java/util/Arrays.java	Tue Mar 18 11:24:38 2014 +0100
@@ -28,6 +28,7 @@
 import java.lang.reflect.Array;
 import java.util.concurrent.ForkJoinPool;
 import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
 import java.util.function.DoubleBinaryOperator;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntFunction;
@@ -35,6 +36,7 @@
 import java.util.function.IntToLongFunction;
 import java.util.function.IntUnaryOperator;
 import java.util.function.LongBinaryOperator;
+import java.util.function.UnaryOperator;
 import java.util.stream.DoubleStream;
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
@@ -3848,12 +3850,13 @@
 
         @Override
         public int indexOf(Object o) {
-            if (o==null) {
-                for (int i=0; i<a.length; i++)
-                    if (a[i]==null)
+            E[] a = this.a;
+            if (o == null) {
+                for (int i = 0; i < a.length; i++)
+                    if (a[i] == null)
                         return i;
             } else {
-                for (int i=0; i<a.length; i++)
+                for (int i = 0; i < a.length; i++)
                     if (o.equals(a[i]))
                         return i;
             }
@@ -3869,6 +3872,28 @@
         public Spliterator<E> spliterator() {
             return Spliterators.spliterator(a, Spliterator.ORDERED);
         }
+
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            for (E e : a) {
+                action.accept(e);
+            }
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+            E[] a = this.a;
+            for (int i = 0; i < a.length; i++) {
+                a[i] = operator.apply(a[i]);
+            }
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            Arrays.sort(a, c);
+        }
     }
 
     /**
--- a/jdk/test/java/util/Collection/CollectionDefaults.java	Tue Mar 18 11:10:53 2014 +0100
+++ b/jdk/test/java/util/Collection/CollectionDefaults.java	Tue Mar 18 11:24:38 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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,6 +21,7 @@
  * questions.
  */
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -44,8 +45,8 @@
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.function.Supplier;
 
 /**
  * @test
@@ -59,26 +60,25 @@
     public static final Predicate<Integer> pEven = x -> 0 == x % 2;
     public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
 
-    @SuppressWarnings("unchecked")
-    private static final Supplier<?>[] TEST_CLASSES = {
-        // Collection
-        ExtendsAbstractCollection<Integer>::new,
+    private static final List<Function<Collection<Integer>, Collection<Integer>>> TEST_SUPPLIERS = Arrays.asList(
+            // Collection
+            ExtendsAbstractCollection<Integer>::new,
 
-        // Lists
-        java.util.ArrayList<Integer>::new,
-        java.util.LinkedList<Integer>::new,
-        java.util.Vector<Integer>::new,
-        java.util.concurrent.CopyOnWriteArrayList<Integer>::new,
-        ExtendsAbstractList<Integer>::new,
+            // Lists
+            java.util.ArrayList<Integer>::new,
+            java.util.LinkedList<Integer>::new,
+            java.util.Vector<Integer>::new,
+            java.util.concurrent.CopyOnWriteArrayList<Integer>::new,
+            ExtendsAbstractList<Integer>::new,
 
-        // Sets
-        java.util.HashSet<Integer>::new,
-        java.util.LinkedHashSet<Integer>::new,
-        java.util.TreeSet<Integer>::new,
-        java.util.concurrent.ConcurrentSkipListSet<Integer>::new,
-        java.util.concurrent.CopyOnWriteArraySet<Integer>::new,
-        ExtendsAbstractSet<Integer>::new
-    };
+            // Sets
+            java.util.HashSet<Integer>::new,
+            java.util.LinkedHashSet<Integer>::new,
+            java.util.TreeSet<Integer>::new,
+            java.util.concurrent.ConcurrentSkipListSet<Integer>::new,
+            java.util.concurrent.CopyOnWriteArraySet<Integer>::new,
+            ExtendsAbstractSet<Integer>::new
+       );
 
     private static final int SIZE = 100;
 
@@ -94,7 +94,7 @@
         cases.add(new Object[] { new ExtendsAbstractSet<>() });
 
         cases.add(new Object[] { Collections.newSetFromMap(new HashMap<>()) });
-        cases.add(new Object[] { Collections.newSetFromMap(new LinkedHashMap()) });
+        cases.add(new Object[] { Collections.newSetFromMap(new LinkedHashMap<>()) });
         cases.add(new Object[] { Collections.newSetFromMap(new TreeMap<>()) });
         cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentHashMap<>()) });
         cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentSkipListMap<>()) });
@@ -107,24 +107,23 @@
     }
 
     @Test(dataProvider = "setProvider")
-    public void testProvidedWithNull(final Set<Integer> set) throws Exception {
+    public void testProvidedWithNull(final Set<Integer> set) {
         try {
             set.forEach(null);
             fail("expected NPE not thrown");
-        } catch (NullPointerException expected) {
-                ; // expected
-            }
+        } catch (NullPointerException expected) { // expected
+        }
         try {
             set.removeIf(null);
             fail("expected NPE not thrown");
-        } catch (NullPointerException expected) {
-               ; // expected
+        } catch (NullPointerException expected) { // expected
         }
     }
 
     @Test
-    public void testForEach() throws Exception {
-        final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE);
+    public void testForEach() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier(TEST_SUPPLIERS, SIZE);
 
         for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
             final Collection<Integer> original = test.expected;
@@ -133,8 +132,7 @@
             try {
                 set.forEach(null);
                 fail("expected NPE not thrown");
-            } catch (NullPointerException expected) {
-                ; // expected
+            } catch (NullPointerException expected) { // expected
             }
             if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
                 CollectionAsserts.assertContentsUnordered(set, original, test.toString());
@@ -155,8 +153,9 @@
     }
 
     @Test
-    public void testRemoveIf() throws Exception {
-        final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE);
+    public void testRemoveIf() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier(TEST_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
             final Collection<Integer> original = test.expected;
             final Collection<Integer> set = test.collection;
@@ -164,8 +163,7 @@
             try {
                 set.removeIf(null);
                 fail("expected NPE not thrown");
-            } catch (NullPointerException expected) {
-                ; // expected
+            } catch (NullPointerException expected) { // expected
             }
             if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
                 CollectionAsserts.assertContentsUnordered(set, original, test.toString());
--- a/jdk/test/java/util/Collection/testlibrary/CollectionSupplier.java	Tue Mar 18 11:10:53 2014 +0100
+++ b/jdk/test/java/util/Collection/testlibrary/CollectionSupplier.java	Tue Mar 18 11:24:38 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,7 @@
 import java.lang.Integer;
 import java.lang.Iterable;
 import java.lang.Override;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -36,6 +37,7 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.function.Function;
 import java.util.function.Supplier;
 
 /**
@@ -44,20 +46,24 @@
  */
 public final class CollectionSupplier<C extends Collection<Integer>> implements Supplier<Iterable<CollectionSupplier.TestCase<C>>> {
 
-    private final Supplier<C>[] classes;
+    private final List<Function<Collection<Integer>, C>> suppliers;
     private final int size;
 
     /**
      * A Collection test case.
      */
     public static final class TestCase<C extends Collection<Integer>> {
-
         /**
          * The name of the test case.
          */
         public final String name;
 
         /**
+         * The supplier of a collection
+         */
+        public Function<Collection<Integer>, C> supplier;
+
+        /**
          * Unmodifiable reference collection, useful for comparisons.
          */
         public final List<Integer> expected;
@@ -71,11 +77,11 @@
          * Create a Collection test case.
          *
          * @param name name of the test case
-         * @param expected reference collection
          * @param collection the modifiable test collection
          */
-        public TestCase(String name, C collection) {
+        public TestCase(String name, Function<Collection<Integer>, C> supplier, C collection) {
             this.name = name;
+            this.supplier = supplier;
             this.expected = Collections.unmodifiableList(
                 Arrays.asList(collection.toArray(new Integer[0])));
             this.collection = collection;
@@ -107,54 +113,52 @@
     }
 
     /**
-     * Create a {@code Supplier} that creates instances of specified collection
-     * classes of specified length.
+     * Create a {@code CollectionSupplier} that creates instances of specified
+     * collection suppliers of the specified size.
      *
-     * @param classNames class names that implement {@code Collection}
+     * @param suppliers the suppliers names that supply {@code Collection}
+     *        instances
      * @param size the desired size of each collection
      */
-    public CollectionSupplier(Supplier<C>[] classes, int size) {
-        this.classes = Arrays.copyOf(classes, classes.length);
+    public CollectionSupplier(List<Function<Collection<Integer>, C>> suppliers, int size) {
+        this.suppliers = suppliers;
         this.size = size;
     }
 
     @Override
     public Iterable<TestCase<C>> get() {
         final Collection<TestCase<C>> cases = new LinkedList<>();
-        for (final Supplier<C> type : classes) {
+        for (final Function<Collection<Integer>, C> supplier : suppliers)
             try {
-                final Collection<Integer> empty = type.get();
-                cases.add(new TestCase("empty", empty));
+                cases.add(new TestCase<>("empty", supplier, supplier.apply(Collections.emptyList())));
 
-                final Collection<Integer> single = type.get();
-                single.add(42);
-                cases.add(new TestCase("single", single));
+                cases.add(new TestCase<>("single", supplier, supplier.apply(Arrays.asList(42))));
 
-                final Collection<Integer> regular = type.get();
+                final Collection<Integer> regular = new ArrayList<>();
                 for (int i = 0; i < size; i++) {
                     regular.add(i);
                 }
-                cases.add(new TestCase("regular", regular));
+                cases.add(new TestCase<>("regular", supplier, supplier.apply(regular)));
 
-                final Collection<Integer> reverse = type.get();
+                final Collection<Integer> reverse = new ArrayList<>();
                 for (int i = size; i >= 0; i--) {
                     reverse.add(i);
                 }
-                cases.add(new TestCase("reverse", reverse));
+                cases.add(new TestCase<>("reverse", supplier, supplier.apply(reverse)));
 
-                final Collection<Integer> odds = type.get();
+                final Collection<Integer> odds = new ArrayList<>();
                 for (int i = 0; i < size; i++) {
                     odds.add((i * 2) + 1);
                 }
-                cases.add(new TestCase("odds", odds));
+                cases.add(new TestCase<>("odds", supplier, supplier.apply(odds)));
 
-                final Collection<Integer> evens = type.get();
+                final Collection<Integer> evens = new ArrayList<>();
                 for (int i = 0; i < size; i++) {
                     evens.add(i * 2);
                 }
-                cases.add(new TestCase("evens", evens));
+                cases.add(new TestCase<>("evens", supplier, supplier.apply(evens)));
 
-                final Collection<Integer> fibonacci = type.get();
+                final Collection<Integer> fibonacci = new ArrayList<>();
                 int prev2 = 0;
                 int prev1 = 1;
                 for (int i = 0; i < size; i++) {
@@ -166,58 +170,62 @@
                     prev2 = prev1;
                     prev1 = n;
                 }
-                cases.add(new TestCase("fibonacci", fibonacci));
+                cases.add(new TestCase<>("fibonacci", supplier, supplier.apply(fibonacci)));
+
 
-            // variants where the size of the backing storage != reported size
+                boolean isStructurallyModifiable = false;
+                try {
+                    C t = supplier.apply(Collections.emptyList());
+                    t.add(1);
+                    isStructurallyModifiable = true;
+                } catch (UnsupportedOperationException e) { }
+
+                if (!isStructurallyModifiable)
+                    continue;
+
+
+                // variants where the size of the backing storage != reported size
                 // created by removing half of the elements
-                final Collection<Integer> emptyWithSlack = type.get();
+                final C emptyWithSlack = supplier.apply(Collections.emptyList());
                 emptyWithSlack.add(42);
                 assertTrue(emptyWithSlack.remove(42));
-                cases.add(new TestCase("emptyWithSlack", emptyWithSlack));
+                cases.add(new TestCase<>("emptyWithSlack", supplier, emptyWithSlack));
 
-                final Collection<Integer> singleWithSlack = type.get();
+                final C singleWithSlack = supplier.apply(Collections.emptyList());
                 singleWithSlack.add(42);
                 singleWithSlack.add(43);
                 assertTrue(singleWithSlack.remove(43));
-                cases.add(new TestCase("singleWithSlack", singleWithSlack));
+                cases.add(new TestCase<>("singleWithSlack", supplier, singleWithSlack));
 
-                final Collection<Integer> regularWithSlack = type.get();
+                final C regularWithSlack = supplier.apply(Collections.emptyList());
                 for (int i = 0; i < (2 * size); i++) {
                     regularWithSlack.add(i);
                 }
-                assertTrue(regularWithSlack.removeIf((x) -> {
-                    return x >= size;
-                }));
-                cases.add(new TestCase("regularWithSlack", regularWithSlack));
+                assertTrue(regularWithSlack.removeIf(x -> x < size));
+                cases.add(new TestCase<>("regularWithSlack", supplier, regularWithSlack));
 
-                final Collection<Integer> reverseWithSlack = type.get();
+                final C reverseWithSlack = supplier.apply(Collections.emptyList());
                 for (int i = 2 * size; i >= 0; i--) {
                     reverseWithSlack.add(i);
                 }
-                assertTrue(reverseWithSlack.removeIf((x) -> {
-                    return x < size;
-                }));
-                cases.add(new TestCase("reverseWithSlack", reverseWithSlack));
+                assertTrue(reverseWithSlack.removeIf(x -> x < size));
+                cases.add(new TestCase<>("reverseWithSlack", supplier, reverseWithSlack));
 
-                final Collection<Integer> oddsWithSlack = type.get();
+                final C oddsWithSlack = supplier.apply(Collections.emptyList());
                 for (int i = 0; i < 2 * size; i++) {
                     oddsWithSlack.add((i * 2) + 1);
                 }
-                assertTrue(oddsWithSlack.removeIf((x) -> {
-                    return x >= size;
-                }));
-                cases.add(new TestCase("oddsWithSlack", oddsWithSlack));
+                assertTrue(oddsWithSlack.removeIf(x -> x >= size));
+                cases.add(new TestCase<>("oddsWithSlack", supplier, oddsWithSlack));
 
-                final Collection<Integer> evensWithSlack = type.get();
+                final C evensWithSlack = supplier.apply(Collections.emptyList());
                 for (int i = 0; i < 2 * size; i++) {
                     evensWithSlack.add(i * 2);
                 }
-                assertTrue(evensWithSlack.removeIf((x) -> {
-                    return x >= size;
-                }));
-                cases.add(new TestCase("evensWithSlack", evensWithSlack));
+                assertTrue(evensWithSlack.removeIf(x -> x >= size));
+                cases.add(new TestCase<>("evensWithSlack", supplier, evensWithSlack));
 
-                final Collection<Integer> fibonacciWithSlack = type.get();
+                final C fibonacciWithSlack = supplier.apply(Collections.emptyList());
                 prev2 = 0;
                 prev1 = 1;
                 for (int i = 0; i < size; i++) {
@@ -229,15 +237,12 @@
                     prev2 = prev1;
                     prev1 = n;
                 }
-                assertTrue(fibonacciWithSlack.removeIf((x) -> {
-                    return x < 20;
-                }));
-                cases.add(new TestCase("fibonacciWithSlack",
-                    fibonacciWithSlack));
-            } catch (Exception failed) {
+                assertTrue(fibonacciWithSlack.removeIf(x -> x < 20));
+                cases.add(new TestCase<>("fibonacciWithSlack", supplier, fibonacciWithSlack));
+            }
+            catch (Exception failed) {
                 throw new TestException(failed);
             }
-        }
 
         return cases;
     }
--- a/jdk/test/java/util/List/ListDefaults.java	Tue Mar 18 11:10:53 2014 +0100
+++ b/jdk/test/java/util/List/ListDefaults.java	Tue Mar 18 11:24:38 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,6 +23,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -43,31 +44,45 @@
 
 import java.lang.reflect.Constructor;
 import java.util.ConcurrentModificationException;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 
 /**
  * @test
  * @summary Unit tests for extension methods on List
- * @bug 8023367
+ * @bug 8023367 8037106
  * @library ../Collection/testlibrary
  * @build CollectionAsserts CollectionSupplier ExtendsAbstractList
  * @run testng ListDefaults
  */
 public class ListDefaults {
 
-    private static final Supplier<?>[] LIST_CLASSES = {
-        java.util.ArrayList::new,
-        java.util.LinkedList::new,
-        java.util.Vector::new,
-        java.util.concurrent.CopyOnWriteArrayList::new,
-        ExtendsAbstractList::new
-     };
+    // Suppliers of lists that can support structural modifications
+    private static final List<Function<Collection, List>> LIST_STRUCT_MOD_SUPPLIERS = Arrays.asList(
+            java.util.ArrayList::new,
+            java.util.LinkedList::new,
+            java.util.Vector::new,
+            java.util.concurrent.CopyOnWriteArrayList::new,
+            ExtendsAbstractList::new
+    );
 
-    private static final Supplier<?>[] LIST_CME_CLASSES = {
-        java.util.ArrayList::new,
-        java.util.Vector::new
-     };
+    // Suppliers of lists that can support in place modifications
+    private static final List<Function<Collection, List>> LIST_SUPPLIERS = Arrays.asList(
+            java.util.ArrayList::new,
+            java.util.LinkedList::new,
+            java.util.Vector::new,
+            java.util.concurrent.CopyOnWriteArrayList::new,
+            ExtendsAbstractList::new,
+            c -> Arrays.asList(c.toArray())
+    );
+
+    // Suppliers of lists supporting CMEs
+    private static final List<Function<Collection, List>> LIST_CME_SUPPLIERS = Arrays.asList(
+            java.util.ArrayList::new,
+            java.util.Vector::new
+    );
 
     private static final Predicate<Integer> pEven = x -> 0 == x % 2;
     private static final Predicate<Integer> pOdd = x -> 1 == x % 2;
@@ -83,17 +98,13 @@
     private static final int SUBLIST_TO = SIZE - 5;
     private static final int SUBLIST_SIZE = SUBLIST_TO - SUBLIST_FROM;
 
-    private static interface Callback {
-        void call(List<Integer> list);
-    }
-
     // call the callback for each recursive subList
-    private void trimmedSubList(final List<Integer> list, final Callback callback) {
+    private void trimmedSubList(final List<Integer> list, final Consumer<List<Integer>> callback) {
         int size = list.size();
         if (size > 1) {
             // trim 1 element from both ends
             final List<Integer> subList = list.subList(1, size - 1);
-            callback.call(subList);
+            callback.accept(subList);
             trimmedSubList(subList, callback);
         }
     }
@@ -107,17 +118,21 @@
         cases.add(new Object[] { new Vector<>() });
         cases.add(new Object[] { new Stack<>() });
         cases.add(new Object[] { new CopyOnWriteArrayList<>() });
+        cases.add(new Object[] { Arrays.asList() });
 
-        cases.add(new Object[] { new ArrayList(){{add(42);}} });
-        cases.add(new Object[] { new LinkedList(){{add(42);}} });
-        cases.add(new Object[] { new Vector(){{add(42);}} });
-        cases.add(new Object[] { new Stack(){{add(42);}} });
-        cases.add(new Object[] { new CopyOnWriteArrayList(){{add(42);}} });
+        List<Integer> l = Arrays.asList(42);
+        cases.add(new Object[] { new ArrayList<>(l) });
+        cases.add(new Object[] { new LinkedList<>(l) });
+        cases.add(new Object[] { new Vector<>(l) });
+        Stack<Integer> s = new Stack<>(); s.addAll(l);
+        cases.add(new Object[]{s});
+        cases.add(new Object[] { new CopyOnWriteArrayList<>(l) });
+        cases.add(new Object[] { l });
         return cases.toArray(new Object[0][cases.size()]);
     }
 
     @Test(dataProvider = "listProvider")
-    public void testProvidedWithNull(final List<Integer> list) throws Exception {
+    public void testProvidedWithNull(final List<Integer> list) {
         try {
             list.forEach(null);
             fail("expected NPE not thrown");
@@ -138,11 +153,12 @@
     }
 
     @Test
-    public void testForEach() throws Exception {
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+    public void testForEach() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.expected);
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> original = test.expected;
+            final List<Integer> list = test.collection;
 
             try {
                 list.forEach(null);
@@ -165,23 +181,21 @@
                 }
             }
 
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> actual = new LinkedList<>();
-                    list.forEach(actual::add);
-                    CollectionAsserts.assertContents(actual, list);
-                }
-            });
+            trimmedSubList(list, l -> {
+                    final List<Integer> a = new LinkedList<>();
+                    l.forEach(a::add);
+                    CollectionAsserts.assertContents(a, l);
+                });
         }
     }
 
     @Test
-    public void testRemoveIf() throws Exception {
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+    public void testRemoveIf() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_STRUCT_MOD_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.expected);
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> original = test.expected;
+            final List<Integer> list = test.collection;
 
             try {
                 list.removeIf(null);
@@ -195,9 +209,9 @@
             }
         }
 
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.expected);
-            final List<Integer> list = ((List<Integer>) test.collection);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> original = test.expected;
+            final List<Integer> list = test.collection;
             list.removeIf(pOdd);
             for (int i : list) {
                 assertTrue((i % 2) == 0);
@@ -211,9 +225,9 @@
             assertTrue(list.isEmpty());
         }
 
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.expected);
-            final List<Integer> list = ((List<Integer>) test.collection);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> original = test.expected;
+            final List<Integer> list = test.collection;
             final List<Integer> listCopy = new ArrayList<>(list);
             if (original.size() > SUBLIST_SIZE) {
                 final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
@@ -237,22 +251,19 @@
             }
         }
 
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> copy = new ArrayList<>(list);
-                    list.removeIf(pOdd);
-                    for (int i : list) {
-                        assertTrue((i % 2) == 0);
-                    }
-                    for (int i : copy) {
-                        if (i % 2 == 0) {
-                            assertTrue(list.contains(i));
-                        } else {
-                            assertFalse(list.contains(i));
-                        }
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> list = test.collection;
+            trimmedSubList(list, l -> {
+                final List<Integer> copy = new ArrayList<>(l);
+                l.removeIf(pOdd);
+                for (int i : l) {
+                    assertTrue((i % 2) == 0);
+                }
+                for (int i : copy) {
+                    if (i % 2 == 0) {
+                        assertTrue(l.contains(i));
+                    } else {
+                        assertFalse(l.contains(i));
                     }
                 }
             });
@@ -267,12 +278,13 @@
     }
 
     @Test
-    public void testReplaceAll() throws Exception {
+    public void testReplaceAll() {
         final int scale = 3;
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.expected);
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> original = test.expected;
+            final List<Integer> list = test.collection;
 
             try {
                 list.replaceAll(null);
@@ -281,7 +293,7 @@
             CollectionAsserts.assertContents(list, original);
 
             list.replaceAll(x -> scale * x);
-            for (int i=0; i < original.size(); i++) {
+            for (int i = 0; i < original.size(); i++) {
                 assertTrue(list.get(i) == (scale * original.get(i)), "mismatch at index " + i);
             }
 
@@ -306,28 +318,26 @@
             }
         }
 
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> copy = new ArrayList<>(list);
-                    final int offset = 5;
-                    list.replaceAll(x -> offset + x);
-                    for (int i=0; i < copy.size(); i++) {
-                        assertTrue(list.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
-                    }
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> list = test.collection;
+            trimmedSubList(list, l -> {
+                final List<Integer> copy = new ArrayList<>(l);
+                final int offset = 5;
+                l.replaceAll(x -> offset + x);
+                for (int i = 0; i < copy.size(); i++) {
+                    assertTrue(l.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
                 }
             });
         }
     }
 
     @Test
-    public void testSort() throws Exception {
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+    public void testSort() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.expected);
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> original = test.expected;
+            final List<Integer> list = test.collection;
             CollectionSupplier.shuffle(list);
             list.sort(Integer::compare);
             CollectionAsserts.assertSorted(list, Integer::compare);
@@ -338,23 +348,23 @@
 
             CollectionSupplier.shuffle(list);
             list.sort(null);
-            CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
+            CollectionAsserts.assertSorted(list, Comparator.naturalOrder());
             if (test.name.startsWith("reverse")) {
                 Collections.reverse(list);
             }
             CollectionAsserts.assertContents(list, original);
 
             CollectionSupplier.shuffle(list);
-            list.sort(Comparator.<Integer>naturalOrder());
-            CollectionAsserts.assertSorted(list, Comparator.<Integer>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(Comparator.<Integer>reverseOrder());
-            CollectionAsserts.assertSorted(list, Comparator.<Integer>reverseOrder());
+            list.sort(Comparator.reverseOrder());
+            CollectionAsserts.assertSorted(list, Comparator.reverseOrder());
             if (!test.name.startsWith("reverse")) {
                 Collections.reverse(list);
             }
@@ -365,32 +375,35 @@
             CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR);
             // check sort by verifying that bitCount increases and never drops
             int minBitCount = 0;
-            int bitCount = 0;
             for (final Integer i : list) {
-                bitCount = Integer.bitCount(i);
+                int bitCount = Integer.bitCount(i);
                 assertTrue(bitCount >= minBitCount);
                 minBitCount = bitCount;
             }
 
+            // Resuse the supplier to store AtomicInteger instead of Integer
+            // Hence the use of raw type and cast
+            List<AtomicInteger> incomparablesData = new ArrayList<>();
+            for (int i = 0; i < test.expected.size(); i++) {
+                incomparablesData.add(new AtomicInteger(i));
+            }
+            Function f = test.supplier;
             @SuppressWarnings("unchecked")
-            final Constructor<? extends List<?>> defaultConstructor = ((Class<? extends List<?>>)test.collection.getClass()).getConstructor();
-            final List<AtomicInteger> incomparables = (List<AtomicInteger>) defaultConstructor.newInstance();
+            List<AtomicInteger> incomparables = (List<AtomicInteger>) f.apply(incomparablesData);
 
-            for (int i=0; i < test.expected.size(); i++) {
-                incomparables.add(new AtomicInteger(i));
-            }
             CollectionSupplier.shuffle(incomparables);
             incomparables.sort(ATOMIC_INTEGER_COMPARATOR);
-            for (int i=0; i < test.expected.size(); i++) {
+            for (int i = 0; i < test.expected.size(); i++) {
                 assertEquals(i, incomparables.get(i).intValue());
             }
 
+
             if (original.size() > SUBLIST_SIZE) {
                 final List<Integer> copy = new ArrayList<>(list);
                 final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
                 CollectionSupplier.shuffle(subList);
-                subList.sort(Comparator.<Integer>naturalOrder());
-                CollectionAsserts.assertSorted(subList, Comparator.<Integer>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),
@@ -404,25 +417,22 @@
             }
         }
 
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> copy = new ArrayList<>(list);
-                    CollectionSupplier.shuffle(list);
-                    list.sort(Comparator.<Integer>naturalOrder());
-                    CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
-                }
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> list = test.collection;
+            trimmedSubList(list, l -> {
+                CollectionSupplier.shuffle(l);
+                l.sort(Comparator.naturalOrder());
+                CollectionAsserts.assertSorted(l, Comparator.naturalOrder());
             });
         }
     }
 
     @Test
-    public void testForEachThrowsCME() throws Exception {
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+    public void testForEachThrowsCME() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> list = test.collection;
 
             if (list.size() <= 1) {
                 continue;
@@ -430,7 +440,7 @@
             boolean gotException = false;
             try {
                 // bad predicate that modifies its list, should throw CME
-                list.forEach((x) -> {list.add(x);});
+                list.forEach(list::add);
             } catch (ConcurrentModificationException cme) {
                 gotException = true;
             }
@@ -441,11 +451,11 @@
     }
 
     @Test
-    public void testRemoveIfThrowsCME() throws Exception {
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+    public void testRemoveIfThrowsCME() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.expected);
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> list = test.collection;
 
             if (list.size() <= 1) {
                 continue;
@@ -453,7 +463,7 @@
             boolean gotException = false;
             try {
                 // bad predicate that modifies its list, should throw CME
-                list.removeIf((x) -> {return list.add(x);});
+                list.removeIf(list::add);
             } catch (ConcurrentModificationException cme) {
                 gotException = true;
             }
@@ -464,10 +474,11 @@
     }
 
     @Test
-    public void testReplaceAllThrowsCME() throws Exception {
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+    public void testReplaceAllThrowsCME() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> list = test.collection;
 
             if (list.size() <= 1) {
                 continue;
@@ -486,10 +497,11 @@
     }
 
     @Test
-    public void testSortThrowsCME() throws Exception {
-        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+    public void testSortThrowsCME() {
+        @SuppressWarnings("unchecked")
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
         for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> list = test.collection;
 
             if (list.size() <= 1) {
                 continue;
@@ -523,7 +535,7 @@
     }
 
     @Test(dataProvider = "shortIntListProvider")
-    public void testRemoveIfFromSlice(final List<Integer> list) throws Exception {
+    public void testRemoveIfFromSlice(final List<Integer> list) {
         final List<Integer> sublist = list.subList(3, 6);
         assertTrue(sublist.removeIf(x -> x == 4));
         CollectionAsserts.assertContents(list, SLICED_EXPECTED);