提交 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,8 +60,7 @@ public class CollectionDefaults { ...@@ -59,8 +60,7 @@ 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,
...@@ -78,7 +78,7 @@ public class CollectionDefaults { ...@@ -78,7 +78,7 @@ public class CollectionDefaults {
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)));
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 // 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,14 +237,11 @@ public final class CollectionSupplier<C extends Collection<Integer>> implements ...@@ -229,14 +237,11 @@ 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",
fibonacciWithSlack));
} catch (Exception failed) {
throw new TestException(failed);
} }
catch (Exception failed) {
throw new TestException(failed);
} }
return cases; return cases;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册