提交 85eb44e6 编写于 作者: P psandoz

8037106: Optimize Arrays.asList(...).forEach

Reviewed-by: alanb, martin, mduigou, ulfzibis
上级 830d7a16
...@@ -28,6 +28,7 @@ package java.util; ...@@ -28,6 +28,7 @@ package java.util;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.function.BinaryOperator; import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.DoubleBinaryOperator; import java.util.function.DoubleBinaryOperator;
import java.util.function.IntBinaryOperator; import java.util.function.IntBinaryOperator;
import java.util.function.IntFunction; import java.util.function.IntFunction;
...@@ -35,6 +36,7 @@ import java.util.function.IntToDoubleFunction; ...@@ -35,6 +36,7 @@ import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction; import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator; import java.util.function.IntUnaryOperator;
import java.util.function.LongBinaryOperator; import java.util.function.LongBinaryOperator;
import java.util.function.UnaryOperator;
import java.util.stream.DoubleStream; import java.util.stream.DoubleStream;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.LongStream; import java.util.stream.LongStream;
...@@ -3848,12 +3850,13 @@ public class Arrays { ...@@ -3848,12 +3850,13 @@ public class Arrays {
@Override @Override
public int indexOf(Object o) { public int indexOf(Object o) {
if (o==null) { E[] a = this.a;
for (int i=0; i<a.length; i++) if (o == null) {
if (a[i]==null) for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i; return i;
} else { } else {
for (int i=0; i<a.length; i++) for (int i = 0; i < a.length; i++)
if (o.equals(a[i])) if (o.equals(a[i]))
return i; return i;
} }
...@@ -3869,6 +3872,28 @@ public class Arrays { ...@@ -3869,6 +3872,28 @@ public class Arrays {
public Spliterator<E> spliterator() { public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED); 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);
}
} }
/** /**
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
* questions. * questions.
*/ */
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
...@@ -44,8 +45,8 @@ import java.util.TreeMap; ...@@ -44,8 +45,8 @@ import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier;
/** /**
* @test * @test
...@@ -59,26 +60,25 @@ public class CollectionDefaults { ...@@ -59,26 +60,25 @@ public class CollectionDefaults {
public static final Predicate<Integer> pEven = x -> 0 == x % 2; public static final Predicate<Integer> pEven = x -> 0 == x % 2;
public static final Predicate<Integer> pOdd = x -> 1 == x % 2; public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
@SuppressWarnings("unchecked") private static final List<Function<Collection<Integer>, Collection<Integer>>> TEST_SUPPLIERS = Arrays.asList(
private static final Supplier<?>[] TEST_CLASSES = { // Collection
// Collection ExtendsAbstractCollection<Integer>::new,
ExtendsAbstractCollection<Integer>::new,
// Lists
// Lists java.util.ArrayList<Integer>::new,
java.util.ArrayList<Integer>::new, java.util.LinkedList<Integer>::new,
java.util.LinkedList<Integer>::new, java.util.Vector<Integer>::new,
java.util.Vector<Integer>::new, java.util.concurrent.CopyOnWriteArrayList<Integer>::new,
java.util.concurrent.CopyOnWriteArrayList<Integer>::new, ExtendsAbstractList<Integer>::new,
ExtendsAbstractList<Integer>::new,
// Sets
// Sets java.util.HashSet<Integer>::new,
java.util.HashSet<Integer>::new, java.util.LinkedHashSet<Integer>::new,
java.util.LinkedHashSet<Integer>::new, java.util.TreeSet<Integer>::new,
java.util.TreeSet<Integer>::new, java.util.concurrent.ConcurrentSkipListSet<Integer>::new,
java.util.concurrent.ConcurrentSkipListSet<Integer>::new, java.util.concurrent.CopyOnWriteArraySet<Integer>::new,
java.util.concurrent.CopyOnWriteArraySet<Integer>::new, ExtendsAbstractSet<Integer>::new
ExtendsAbstractSet<Integer>::new );
};
private static final int SIZE = 100; private static final int SIZE = 100;
...@@ -94,7 +94,7 @@ public class CollectionDefaults { ...@@ -94,7 +94,7 @@ public class CollectionDefaults {
cases.add(new Object[] { new ExtendsAbstractSet<>() }); cases.add(new Object[] { new ExtendsAbstractSet<>() });
cases.add(new Object[] { Collections.newSetFromMap(new HashMap<>()) }); 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 TreeMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentHashMap<>()) }); cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentHashMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentSkipListMap<>()) }); cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentSkipListMap<>()) });
...@@ -107,24 +107,23 @@ public class CollectionDefaults { ...@@ -107,24 +107,23 @@ public class CollectionDefaults {
} }
@Test(dataProvider = "setProvider") @Test(dataProvider = "setProvider")
public void testProvidedWithNull(final Set<Integer> set) throws Exception { public void testProvidedWithNull(final Set<Integer> set) {
try { try {
set.forEach(null); set.forEach(null);
fail("expected NPE not thrown"); fail("expected NPE not thrown");
} catch (NullPointerException expected) { } catch (NullPointerException expected) { // expected
; // expected }
}
try { try {
set.removeIf(null); set.removeIf(null);
fail("expected NPE not thrown"); fail("expected NPE not thrown");
} catch (NullPointerException expected) { } catch (NullPointerException expected) { // expected
; // expected
} }
} }
@Test @Test
public void testForEach() throws Exception { public void testForEach() {
final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE); @SuppressWarnings("unchecked")
final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier(TEST_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) { for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
final Collection<Integer> original = test.expected; final Collection<Integer> original = test.expected;
...@@ -133,8 +132,7 @@ public class CollectionDefaults { ...@@ -133,8 +132,7 @@ public class CollectionDefaults {
try { try {
set.forEach(null); set.forEach(null);
fail("expected NPE not thrown"); fail("expected NPE not thrown");
} catch (NullPointerException expected) { } catch (NullPointerException expected) { // expected
; // expected
} }
if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) { if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
CollectionAsserts.assertContentsUnordered(set, original, test.toString()); CollectionAsserts.assertContentsUnordered(set, original, test.toString());
...@@ -155,8 +153,9 @@ public class CollectionDefaults { ...@@ -155,8 +153,9 @@ public class CollectionDefaults {
} }
@Test @Test
public void testRemoveIf() throws Exception { public void testRemoveIf() {
final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE); @SuppressWarnings("unchecked")
final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier(TEST_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) { for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
final Collection<Integer> original = test.expected; final Collection<Integer> original = test.expected;
final Collection<Integer> set = test.collection; final Collection<Integer> set = test.collection;
...@@ -164,8 +163,7 @@ public class CollectionDefaults { ...@@ -164,8 +163,7 @@ public class CollectionDefaults {
try { try {
set.removeIf(null); set.removeIf(null);
fail("expected NPE not thrown"); fail("expected NPE not thrown");
} catch (NullPointerException expected) { } catch (NullPointerException expected) { // expected
; // expected
} }
if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) { if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
CollectionAsserts.assertContentsUnordered(set, original, test.toString()); CollectionAsserts.assertContentsUnordered(set, original, test.toString());
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,6 +25,7 @@ import java.lang.Exception; ...@@ -25,6 +25,7 @@ import java.lang.Exception;
import java.lang.Integer; import java.lang.Integer;
import java.lang.Iterable; import java.lang.Iterable;
import java.lang.Override; import java.lang.Override;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
...@@ -36,6 +37,7 @@ import static org.testng.Assert.assertTrue; ...@@ -36,6 +37,7 @@ import static org.testng.Assert.assertTrue;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
...@@ -44,19 +46,23 @@ import java.util.function.Supplier; ...@@ -44,19 +46,23 @@ import java.util.function.Supplier;
*/ */
public final class CollectionSupplier<C extends Collection<Integer>> implements Supplier<Iterable<CollectionSupplier.TestCase<C>>> { 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; private final int size;
/** /**
* A Collection test case. * A Collection test case.
*/ */
public static final class TestCase<C extends Collection<Integer>> { public static final class TestCase<C extends Collection<Integer>> {
/** /**
* The name of the test case. * The name of the test case.
*/ */
public final String name; public final String name;
/**
* The supplier of a collection
*/
public Function<Collection<Integer>, C> supplier;
/** /**
* Unmodifiable reference collection, useful for comparisons. * Unmodifiable reference collection, useful for comparisons.
*/ */
...@@ -71,11 +77,11 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements ...@@ -71,11 +77,11 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements
* Create a Collection test case. * Create a Collection test case.
* *
* @param name name of the test case * @param name name of the test case
* @param expected reference collection
* @param collection the modifiable test 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.name = name;
this.supplier = supplier;
this.expected = Collections.unmodifiableList( this.expected = Collections.unmodifiableList(
Arrays.asList(collection.toArray(new Integer[0]))); Arrays.asList(collection.toArray(new Integer[0])));
this.collection = collection; this.collection = collection;
...@@ -107,54 +113,52 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements ...@@ -107,54 +113,52 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements
} }
/** /**
* Create a {@code Supplier} that creates instances of specified collection * Create a {@code CollectionSupplier} that creates instances of specified
* classes of specified length. * 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 * @param size the desired size of each collection
*/ */
public CollectionSupplier(Supplier<C>[] classes, int size) { public CollectionSupplier(List<Function<Collection<Integer>, C>> suppliers, int size) {
this.classes = Arrays.copyOf(classes, classes.length); this.suppliers = suppliers;
this.size = size; this.size = size;
} }
@Override @Override
public Iterable<TestCase<C>> get() { public Iterable<TestCase<C>> get() {
final Collection<TestCase<C>> cases = new LinkedList<>(); final Collection<TestCase<C>> cases = new LinkedList<>();
for (final Supplier<C> type : classes) { for (final Function<Collection<Integer>, C> supplier : suppliers)
try { try {
final Collection<Integer> empty = type.get(); cases.add(new TestCase<>("empty", supplier, supplier.apply(Collections.emptyList())));
cases.add(new TestCase("empty", empty));
final Collection<Integer> single = type.get(); cases.add(new TestCase<>("single", supplier, supplier.apply(Arrays.asList(42))));
single.add(42);
cases.add(new TestCase("single", single));
final Collection<Integer> regular = type.get(); final Collection<Integer> regular = new ArrayList<>();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
regular.add(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--) { for (int i = size; i >= 0; i--) {
reverse.add(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++) { for (int i = 0; i < size; i++) {
odds.add((i * 2) + 1); 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++) { for (int i = 0; i < size; i++) {
evens.add(i * 2); 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 prev2 = 0;
int prev1 = 1; int prev1 = 1;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
...@@ -166,58 +170,62 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements ...@@ -166,58 +170,62 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements
prev2 = prev1; prev2 = prev1;
prev1 = n; 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 // created by removing half of the elements
final Collection<Integer> emptyWithSlack = type.get(); final C emptyWithSlack = supplier.apply(Collections.emptyList());
emptyWithSlack.add(42); emptyWithSlack.add(42);
assertTrue(emptyWithSlack.remove(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(42);
singleWithSlack.add(43); singleWithSlack.add(43);
assertTrue(singleWithSlack.remove(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++) { for (int i = 0; i < (2 * size); i++) {
regularWithSlack.add(i); regularWithSlack.add(i);
} }
assertTrue(regularWithSlack.removeIf((x) -> { assertTrue(regularWithSlack.removeIf(x -> x < size));
return x >= size; cases.add(new TestCase<>("regularWithSlack", supplier, regularWithSlack));
}));
cases.add(new TestCase("regularWithSlack", regularWithSlack));
final Collection<Integer> reverseWithSlack = type.get(); final C reverseWithSlack = supplier.apply(Collections.emptyList());
for (int i = 2 * size; i >= 0; i--) { for (int i = 2 * size; i >= 0; i--) {
reverseWithSlack.add(i); reverseWithSlack.add(i);
} }
assertTrue(reverseWithSlack.removeIf((x) -> { assertTrue(reverseWithSlack.removeIf(x -> x < size));
return x < size; cases.add(new TestCase<>("reverseWithSlack", supplier, reverseWithSlack));
}));
cases.add(new TestCase("reverseWithSlack", reverseWithSlack));
final Collection<Integer> oddsWithSlack = type.get(); final C oddsWithSlack = supplier.apply(Collections.emptyList());
for (int i = 0; i < 2 * size; i++) { for (int i = 0; i < 2 * size; i++) {
oddsWithSlack.add((i * 2) + 1); oddsWithSlack.add((i * 2) + 1);
} }
assertTrue(oddsWithSlack.removeIf((x) -> { assertTrue(oddsWithSlack.removeIf(x -> x >= size));
return x >= size; cases.add(new TestCase<>("oddsWithSlack", supplier, oddsWithSlack));
}));
cases.add(new TestCase("oddsWithSlack", oddsWithSlack));
final Collection<Integer> evensWithSlack = type.get(); final C evensWithSlack = supplier.apply(Collections.emptyList());
for (int i = 0; i < 2 * size; i++) { for (int i = 0; i < 2 * size; i++) {
evensWithSlack.add(i * 2); evensWithSlack.add(i * 2);
} }
assertTrue(evensWithSlack.removeIf((x) -> { assertTrue(evensWithSlack.removeIf(x -> x >= size));
return x >= size; cases.add(new TestCase<>("evensWithSlack", supplier, evensWithSlack));
}));
cases.add(new TestCase("evensWithSlack", evensWithSlack));
final Collection<Integer> fibonacciWithSlack = type.get(); final C fibonacciWithSlack = supplier.apply(Collections.emptyList());
prev2 = 0; prev2 = 0;
prev1 = 1; prev1 = 1;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
...@@ -229,15 +237,12 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements ...@@ -229,15 +237,12 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements
prev2 = prev1; prev2 = prev1;
prev1 = n; prev1 = n;
} }
assertTrue(fibonacciWithSlack.removeIf((x) -> { assertTrue(fibonacciWithSlack.removeIf(x -> x < 20));
return x < 20; cases.add(new TestCase<>("fibonacciWithSlack", supplier, fibonacciWithSlack));
})); }
cases.add(new TestCase("fibonacciWithSlack", catch (Exception failed) {
fibonacciWithSlack));
} catch (Exception failed) {
throw new TestException(failed); throw new TestException(failed);
} }
}
return cases; return cases;
} }
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
...@@ -43,31 +44,45 @@ import static org.testng.Assert.fail; ...@@ -43,31 +44,45 @@ import static org.testng.Assert.fail;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.ConcurrentModificationException; import java.util.ConcurrentModificationException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* @test * @test
* @summary Unit tests for extension methods on List * @summary Unit tests for extension methods on List
* @bug 8023367 * @bug 8023367 8037106
* @library ../Collection/testlibrary * @library ../Collection/testlibrary
* @build CollectionAsserts CollectionSupplier ExtendsAbstractList * @build CollectionAsserts CollectionSupplier ExtendsAbstractList
* @run testng ListDefaults * @run testng ListDefaults
*/ */
public class ListDefaults { public class ListDefaults {
private static final Supplier<?>[] LIST_CLASSES = { // Suppliers of lists that can support structural modifications
java.util.ArrayList::new, private static final List<Function<Collection, List>> LIST_STRUCT_MOD_SUPPLIERS = Arrays.asList(
java.util.LinkedList::new, java.util.ArrayList::new,
java.util.Vector::new, java.util.LinkedList::new,
java.util.concurrent.CopyOnWriteArrayList::new, java.util.Vector::new,
ExtendsAbstractList::new java.util.concurrent.CopyOnWriteArrayList::new,
}; ExtendsAbstractList::new
);
private static final Supplier<?>[] LIST_CME_CLASSES = {
java.util.ArrayList::new, // Suppliers of lists that can support in place modifications
java.util.Vector::new 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> pEven = x -> 0 == x % 2;
private static final Predicate<Integer> pOdd = x -> 1 == x % 2; private static final Predicate<Integer> pOdd = x -> 1 == x % 2;
...@@ -83,17 +98,13 @@ public class ListDefaults { ...@@ -83,17 +98,13 @@ public class ListDefaults {
private static final int SUBLIST_TO = SIZE - 5; private static final int SUBLIST_TO = SIZE - 5;
private static final int SUBLIST_SIZE = SUBLIST_TO - SUBLIST_FROM; 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 // 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(); int size = list.size();
if (size > 1) { if (size > 1) {
// trim 1 element from both ends // trim 1 element from both ends
final List<Integer> subList = list.subList(1, size - 1); final List<Integer> subList = list.subList(1, size - 1);
callback.call(subList); callback.accept(subList);
trimmedSubList(subList, callback); trimmedSubList(subList, callback);
} }
} }
...@@ -107,17 +118,21 @@ public class ListDefaults { ...@@ -107,17 +118,21 @@ public class ListDefaults {
cases.add(new Object[] { new Vector<>() }); cases.add(new Object[] { new Vector<>() });
cases.add(new Object[] { new Stack<>() }); cases.add(new Object[] { new Stack<>() });
cases.add(new Object[] { new CopyOnWriteArrayList<>() }); 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);}} }); List<Integer> l = Arrays.asList(42);
cases.add(new Object[] { new Vector(){{add(42);}} }); cases.add(new Object[] { new ArrayList<>(l) });
cases.add(new Object[] { new Stack(){{add(42);}} }); cases.add(new Object[] { new LinkedList<>(l) });
cases.add(new Object[] { new CopyOnWriteArrayList(){{add(42);}} }); 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()]); return cases.toArray(new Object[0][cases.size()]);
} }
@Test(dataProvider = "listProvider") @Test(dataProvider = "listProvider")
public void testProvidedWithNull(final List<Integer> list) throws Exception { public void testProvidedWithNull(final List<Integer> list) {
try { try {
list.forEach(null); list.forEach(null);
fail("expected NPE not thrown"); fail("expected NPE not thrown");
...@@ -138,11 +153,12 @@ public class ListDefaults { ...@@ -138,11 +153,12 @@ public class ListDefaults {
} }
@Test @Test
public void testForEach() throws Exception { public void testForEach() {
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()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> original = ((List<Integer>) test.expected); final List<Integer> original = test.expected;
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
try { try {
list.forEach(null); list.forEach(null);
...@@ -165,23 +181,21 @@ public class ListDefaults { ...@@ -165,23 +181,21 @@ public class ListDefaults {
} }
} }
trimmedSubList(list, new Callback() { trimmedSubList(list, l -> {
@Override final List<Integer> a = new LinkedList<>();
public void call(final List<Integer> list) { l.forEach(a::add);
final List<Integer> actual = new LinkedList<>(); CollectionAsserts.assertContents(a, l);
list.forEach(actual::add); });
CollectionAsserts.assertContents(actual, list);
}
});
} }
} }
@Test @Test
public void testRemoveIf() throws Exception { public void testRemoveIf() {
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE); @SuppressWarnings("unchecked")
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_STRUCT_MOD_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> original = ((List<Integer>) test.expected); final List<Integer> original = test.expected;
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
try { try {
list.removeIf(null); list.removeIf(null);
...@@ -195,9 +209,9 @@ public class ListDefaults { ...@@ -195,9 +209,9 @@ public class ListDefaults {
} }
} }
for (final CollectionSupplier.TestCase test : supplier.get()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> original = ((List<Integer>) test.expected); final List<Integer> original = test.expected;
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
list.removeIf(pOdd); list.removeIf(pOdd);
for (int i : list) { for (int i : list) {
assertTrue((i % 2) == 0); assertTrue((i % 2) == 0);
...@@ -211,9 +225,9 @@ public class ListDefaults { ...@@ -211,9 +225,9 @@ public class ListDefaults {
assertTrue(list.isEmpty()); assertTrue(list.isEmpty());
} }
for (final CollectionSupplier.TestCase test : supplier.get()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> original = ((List<Integer>) test.expected); final List<Integer> original = test.expected;
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
final List<Integer> listCopy = new ArrayList<>(list); final List<Integer> listCopy = new ArrayList<>(list);
if (original.size() > SUBLIST_SIZE) { if (original.size() > SUBLIST_SIZE) {
final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO); final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
...@@ -237,22 +251,19 @@ public class ListDefaults { ...@@ -237,22 +251,19 @@ public class ListDefaults {
} }
} }
for (final CollectionSupplier.TestCase test : supplier.get()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
trimmedSubList(list, new Callback() { trimmedSubList(list, l -> {
@Override final List<Integer> copy = new ArrayList<>(l);
public void call(final List<Integer> list) { l.removeIf(pOdd);
final List<Integer> copy = new ArrayList<>(list); for (int i : l) {
list.removeIf(pOdd); assertTrue((i % 2) == 0);
for (int i : list) { }
assertTrue((i % 2) == 0); for (int i : copy) {
} if (i % 2 == 0) {
for (int i : copy) { assertTrue(l.contains(i));
if (i % 2 == 0) { } else {
assertTrue(list.contains(i)); assertFalse(l.contains(i));
} else {
assertFalse(list.contains(i));
}
} }
} }
}); });
...@@ -267,12 +278,13 @@ public class ListDefaults { ...@@ -267,12 +278,13 @@ public class ListDefaults {
} }
@Test @Test
public void testReplaceAll() throws Exception { public void testReplaceAll() {
final int scale = 3; 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()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> original = ((List<Integer>) test.expected); final List<Integer> original = test.expected;
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
try { try {
list.replaceAll(null); list.replaceAll(null);
...@@ -281,7 +293,7 @@ public class ListDefaults { ...@@ -281,7 +293,7 @@ public class ListDefaults {
CollectionAsserts.assertContents(list, original); CollectionAsserts.assertContents(list, original);
list.replaceAll(x -> scale * x); 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); assertTrue(list.get(i) == (scale * original.get(i)), "mismatch at index " + i);
} }
...@@ -306,28 +318,26 @@ public class ListDefaults { ...@@ -306,28 +318,26 @@ public class ListDefaults {
} }
} }
for (final CollectionSupplier.TestCase test : supplier.get()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
trimmedSubList(list, new Callback() { trimmedSubList(list, l -> {
@Override final List<Integer> copy = new ArrayList<>(l);
public void call(final List<Integer> list) { final int offset = 5;
final List<Integer> copy = new ArrayList<>(list); l.replaceAll(x -> offset + x);
final int offset = 5; for (int i = 0; i < copy.size(); i++) {
list.replaceAll(x -> offset + x); assertTrue(l.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
for (int i=0; i < copy.size(); i++) {
assertTrue(list.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
}
} }
}); });
} }
} }
@Test @Test
public void testSort() throws Exception { public void testSort() {
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()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> original = ((List<Integer>) test.expected); final List<Integer> original = test.expected;
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
CollectionSupplier.shuffle(list); CollectionSupplier.shuffle(list);
list.sort(Integer::compare); list.sort(Integer::compare);
CollectionAsserts.assertSorted(list, Integer::compare); CollectionAsserts.assertSorted(list, Integer::compare);
...@@ -338,23 +348,23 @@ public class ListDefaults { ...@@ -338,23 +348,23 @@ public class ListDefaults {
CollectionSupplier.shuffle(list); CollectionSupplier.shuffle(list);
list.sort(null); list.sort(null);
CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder()); CollectionAsserts.assertSorted(list, Comparator.naturalOrder());
if (test.name.startsWith("reverse")) { if (test.name.startsWith("reverse")) {
Collections.reverse(list); Collections.reverse(list);
} }
CollectionAsserts.assertContents(list, original); CollectionAsserts.assertContents(list, original);
CollectionSupplier.shuffle(list); CollectionSupplier.shuffle(list);
list.sort(Comparator.<Integer>naturalOrder()); list.sort(Comparator.naturalOrder());
CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder()); CollectionAsserts.assertSorted(list, Comparator.naturalOrder());
if (test.name.startsWith("reverse")) { if (test.name.startsWith("reverse")) {
Collections.reverse(list); Collections.reverse(list);
} }
CollectionAsserts.assertContents(list, original); CollectionAsserts.assertContents(list, original);
CollectionSupplier.shuffle(list); CollectionSupplier.shuffle(list);
list.sort(Comparator.<Integer>reverseOrder()); list.sort(Comparator.reverseOrder());
CollectionAsserts.assertSorted(list, Comparator.<Integer>reverseOrder()); CollectionAsserts.assertSorted(list, Comparator.reverseOrder());
if (!test.name.startsWith("reverse")) { if (!test.name.startsWith("reverse")) {
Collections.reverse(list); Collections.reverse(list);
} }
...@@ -365,32 +375,35 @@ public class ListDefaults { ...@@ -365,32 +375,35 @@ public class ListDefaults {
CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR); CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR);
// check sort by verifying that bitCount increases and never drops // check sort by verifying that bitCount increases and never drops
int minBitCount = 0; int minBitCount = 0;
int bitCount = 0;
for (final Integer i : list) { for (final Integer i : list) {
bitCount = Integer.bitCount(i); int bitCount = Integer.bitCount(i);
assertTrue(bitCount >= minBitCount); assertTrue(bitCount >= minBitCount);
minBitCount = bitCount; 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") @SuppressWarnings("unchecked")
final Constructor<? extends List<?>> defaultConstructor = ((Class<? extends List<?>>)test.collection.getClass()).getConstructor(); List<AtomicInteger> incomparables = (List<AtomicInteger>) f.apply(incomparablesData);
final List<AtomicInteger> incomparables = (List<AtomicInteger>) defaultConstructor.newInstance();
for (int i=0; i < test.expected.size(); i++) {
incomparables.add(new AtomicInteger(i));
}
CollectionSupplier.shuffle(incomparables); CollectionSupplier.shuffle(incomparables);
incomparables.sort(ATOMIC_INTEGER_COMPARATOR); 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()); assertEquals(i, incomparables.get(i).intValue());
} }
if (original.size() > SUBLIST_SIZE) { if (original.size() > SUBLIST_SIZE) {
final List<Integer> copy = new ArrayList<>(list); final List<Integer> copy = new ArrayList<>(list);
final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO); final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
CollectionSupplier.shuffle(subList); CollectionSupplier.shuffle(subList);
subList.sort(Comparator.<Integer>naturalOrder()); subList.sort(Comparator.naturalOrder());
CollectionAsserts.assertSorted(subList, Comparator.<Integer>naturalOrder()); CollectionAsserts.assertSorted(subList, Comparator.naturalOrder());
// verify that elements [0, from) remain unmodified // verify that elements [0, from) remain unmodified
for (int i = 0; i < SUBLIST_FROM; i++) { for (int i = 0; i < SUBLIST_FROM; i++) {
assertTrue(list.get(i) == copy.get(i), assertTrue(list.get(i) == copy.get(i),
...@@ -404,25 +417,22 @@ public class ListDefaults { ...@@ -404,25 +417,22 @@ public class ListDefaults {
} }
} }
for (final CollectionSupplier.TestCase test : supplier.get()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> list = ((List<Integer>) test.collection); final List<Integer> list = test.collection;
trimmedSubList(list, new Callback() { trimmedSubList(list, l -> {
@Override CollectionSupplier.shuffle(l);
public void call(final List<Integer> list) { l.sort(Comparator.naturalOrder());
final List<Integer> copy = new ArrayList<>(list); CollectionAsserts.assertSorted(l, Comparator.naturalOrder());
CollectionSupplier.shuffle(list);
list.sort(Comparator.<Integer>naturalOrder());
CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
}
}); });
} }
} }
@Test @Test
public void testForEachThrowsCME() throws Exception { public void testForEachThrowsCME() {
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE); @SuppressWarnings("unchecked")
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) { 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) { if (list.size() <= 1) {
continue; continue;
...@@ -430,7 +440,7 @@ public class ListDefaults { ...@@ -430,7 +440,7 @@ public class ListDefaults {
boolean gotException = false; boolean gotException = false;
try { try {
// bad predicate that modifies its list, should throw CME // bad predicate that modifies its list, should throw CME
list.forEach((x) -> {list.add(x);}); list.forEach(list::add);
} catch (ConcurrentModificationException cme) { } catch (ConcurrentModificationException cme) {
gotException = true; gotException = true;
} }
...@@ -441,11 +451,11 @@ public class ListDefaults { ...@@ -441,11 +451,11 @@ public class ListDefaults {
} }
@Test @Test
public void testRemoveIfThrowsCME() throws Exception { public void testRemoveIfThrowsCME() {
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE); @SuppressWarnings("unchecked")
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) { for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
final List<Integer> original = ((List<Integer>) test.expected); final List<Integer> list = test.collection;
final List<Integer> list = ((List<Integer>) test.collection);
if (list.size() <= 1) { if (list.size() <= 1) {
continue; continue;
...@@ -453,7 +463,7 @@ public class ListDefaults { ...@@ -453,7 +463,7 @@ public class ListDefaults {
boolean gotException = false; boolean gotException = false;
try { try {
// bad predicate that modifies its list, should throw CME // bad predicate that modifies its list, should throw CME
list.removeIf((x) -> {return list.add(x);}); list.removeIf(list::add);
} catch (ConcurrentModificationException cme) { } catch (ConcurrentModificationException cme) {
gotException = true; gotException = true;
} }
...@@ -464,10 +474,11 @@ public class ListDefaults { ...@@ -464,10 +474,11 @@ public class ListDefaults {
} }
@Test @Test
public void testReplaceAllThrowsCME() throws Exception { public void testReplaceAllThrowsCME() {
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE); @SuppressWarnings("unchecked")
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) { 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) { if (list.size() <= 1) {
continue; continue;
...@@ -486,10 +497,11 @@ public class ListDefaults { ...@@ -486,10 +497,11 @@ public class ListDefaults {
} }
@Test @Test
public void testSortThrowsCME() throws Exception { public void testSortThrowsCME() {
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE); @SuppressWarnings("unchecked")
final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier(LIST_CME_SUPPLIERS, SIZE);
for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) { 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) { if (list.size() <= 1) {
continue; continue;
...@@ -523,7 +535,7 @@ public class ListDefaults { ...@@ -523,7 +535,7 @@ public class ListDefaults {
} }
@Test(dataProvider = "shortIntListProvider") @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); final List<Integer> sublist = list.subList(3, 6);
assertTrue(sublist.removeIf(x -> x == 4)); assertTrue(sublist.removeIf(x -> x == 4));
CollectionAsserts.assertContents(list, SLICED_EXPECTED); CollectionAsserts.assertContents(list, SLICED_EXPECTED);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册