提交 62e402f4 编写于 作者: A akhil

8001647: default methods for Collections - forEach, removeIf, replaceAll, sort

Reviewed-by: alanb, dholmes, mduigou, psandoz, smarks
Contributed-by: NAkhil Arora &lt;akhil.arora@oracle.com&gt;, Arne Siegel &lt;v.a.ammodytes@googlemail.com&gt;, Brian Goetz <brian.goetz@oracle.com>
上级 dbe53532
......@@ -25,6 +25,10 @@
package java.util;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
* Resizable-array implementation of the <tt>List</tt> interface. Implements
* all optional list operations, and permits all elements, including
......@@ -1168,4 +1172,88 @@ public class ArrayList<E> extends AbstractList<E>
throw new ConcurrentModificationException();
}
}
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
// figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
if (filter.test(element)) {
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// shift surviving elements left over the spaces left by removed elements
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
final int newSize = size - removeCount;
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
for (int k=newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
this.size = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
@Override
@SuppressWarnings("unchecked")
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
}
......@@ -25,6 +25,8 @@
package java.util;
import java.util.function.Predicate;
/**
* The root interface in the <i>collection hierarchy</i>. A collection
* represents a group of objects, known as its <i>elements</i>. Some
......@@ -372,6 +374,40 @@ public interface Collection<E> extends Iterable<E> {
*/
boolean removeAll(Collection<?> c);
/**
* Removes all of the elements of this collection that satisfy the given
* predicate. Errors or runtime exceptions thrown by the predicate are
* relayed to the caller.
*
* @implSpec
* The default implementation traverses all elements of the collection using
* its {@link #iterator}. Each matching element is removed using
* {@link Iterator#remove()}. If the collection's iterator does not
* support removal then an {@code UnsupportedOperationException} will be
* thrown on the first matching element.
*
* @param filter a predicate which returns {@code true} for elements to be
* removed
* @return {@code true} if any elements were removed
* @throws NullPointerException if the specified filter is null
* @throws UnsupportedOperationException if the {@code remove}
* method is not supported by this collection's
* {@link #iterator}
* @since 1.8
*/
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
/**
* Retains only the elements in this collection that are contained in the
* specified collection (optional operation). In other words, removes from
......
......@@ -30,7 +30,10 @@ import java.io.IOException;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
* This class consists exclusively of static methods that operate on or return
......@@ -1110,6 +1113,15 @@ public class Collections {
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public void forEach(Consumer<? super E> action) {
c.forEach(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
}
/**
......@@ -1240,6 +1252,16 @@ public class Collections {
public boolean addAll(int index, Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
throw new UnsupportedOperationException();
}
@Override
public void sort(Comparator<? super E> c) {
throw new UnsupportedOperationException();
}
public ListIterator<E> listIterator() {return listIterator(0);}
public ListIterator<E> listIterator(final int index) {
......@@ -1742,6 +1764,15 @@ public class Collections {
private void writeObject(ObjectOutputStream s) throws IOException {
synchronized (mutex) {s.defaultWriteObject();}
}
@Override
public void forEach(Consumer<? super E> action) {
synchronized (mutex) {c.forEach(action);}
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
synchronized (mutex) {return c.removeIf(filter);}
}
}
/**
......@@ -1996,6 +2027,15 @@ public class Collections {
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
synchronized (mutex) {list.replaceAll(operator);}
}
@Override
public void sort(Comparator<? super E> c) {
synchronized (mutex) {list.sort(c);}
}
/**
* SynchronizedRandomAccessList instances are serialized as
* SynchronizedList instances to allow them to be deserialized
......@@ -2492,6 +2532,15 @@ public class Collections {
// element as we added it)
return c.addAll(checkedCopyOf(coll));
}
@Override
public void forEach(Consumer<? super E> action) {
c.forEach(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
return c.removeIf(filter);
}
}
/**
......@@ -2753,6 +2802,15 @@ public class Collections {
public List<E> subList(int fromIndex, int toIndex) {
return new CheckedList<>(list.subList(fromIndex, toIndex), type);
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
list.replaceAll(operator);
}
@Override
public void sort(Comparator<? super E> c) {
list.sort(c);
}
}
/**
......@@ -3416,6 +3474,16 @@ public class Collections {
return a;
}
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
return false;
}
// Preserves singleton property
private Object readResolve() {
return EMPTY_SET;
......@@ -3523,6 +3591,16 @@ public class Collections {
public E last() {
throw new NoSuchElementException();
}
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
return false;
}
}
/**
......@@ -3592,6 +3670,24 @@ public class Collections {
public int hashCode() { return 1; }
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
return false;
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
}
@Override
public void sort(Comparator<? super E> c) {
Objects.requireNonNull(c);
}
// Preserves singleton property
private Object readResolve() {
return EMPTY_LIST;
......@@ -3770,6 +3866,15 @@ public class Collections {
public int size() {return 1;}
public boolean contains(Object o) {return eq(o, element);}
@Override
public void forEach(Consumer<? super E> action) {
action.accept(element);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
}
/**
......@@ -3810,6 +3915,22 @@ public class Collections {
throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
return element;
}
@Override
public void forEach(Consumer<? super E> action) {
action.accept(element);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
throw new UnsupportedOperationException();
}
@Override
public void sort(Comparator<? super E> c) {
}
}
/**
......@@ -4408,6 +4529,15 @@ public class Collections {
public boolean retainAll(Collection<?> c) {return s.retainAll(c);}
// addAll is the only inherited implementation
@Override
public void forEach(Consumer<? super E> action) {
s.forEach(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
return s.removeIf(filter);
}
private static final long serialVersionUID = 2454657854757543876L;
private void readObject(java.io.ObjectInputStream stream)
......@@ -4466,5 +4596,14 @@ public class Collections {
public boolean removeAll(Collection<?> c) {return q.removeAll(c);}
public boolean retainAll(Collection<?> c) {return q.retainAll(c);}
// We use inherited addAll; forwarding addAll would be wrong
@Override
public void forEach(Consumer<? super E> action) {
q.forEach(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
return q.removeIf(filter);
}
}
}
......@@ -25,6 +25,8 @@
package java.util;
import java.util.function.UnaryOperator;
/**
* An ordered collection (also known as a <i>sequence</i>). The user of this
* interface has precise control over where in the list each element is
......@@ -374,6 +376,64 @@ public interface List<E> extends Collection<E> {
*/
boolean retainAll(Collection<?> c);
/**
* Replaces each element of this list with the result of applying the
* operator to that element. Errors or runtime exceptions thrown by
* the operator are relayed to the caller.
*
* @implSpec
* The default implementation is equivalent to, for this {@code list}:
* <pre>
* final ListIterator<E> li = list.listIterator();
* while (li.hasNext()) {
* li.set(operator.apply(li.next()));
* }
* </pre>
* If the list's list-iterator does not support the {@code set} operation
* then an {@code UnsupportedOperationException} will be thrown when
* replacing the first element.
*
* @param operator the operator to apply to each element
* @throws UnsupportedOperationException if the {@code set}
* operation is not supported by this list
* @throws NullPointerException if the specified operator is null or
* if the element is replaced with a null value and this list
* does not permit null elements
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @since 1.8
*/
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
/**
* Sorts this list using the supplied {@code Comparator} to compare elements.
*
* @implSpec
* The default implementation is equivalent to, for this {@code list}:
* <pre>Collections.sort(list, c)</pre>
*
* @param c the {@code Comparator} used to compare list elements.
* A {@code null} value indicates that the elements'
* {@linkplain Comparable natural ordering} should be used
* @throws ClassCastException if the list contains elements that are not
* <i>mutually comparable</i> using the specified comparator
* @throws UnsupportedOperationException if the list's list-iterator does
* not support the {@code set} operation
* @throws IllegalArgumentException
* (<a href="Collection.html#optional-restrictions">optional</a>)
* if the comparator is found to violate the {@link Comparator}
* contract
* @since 1.8
*/
default void sort(Comparator<? super E> c) {
Collections.sort(this, c);
}
/**
* Removes all of the elements from this list (optional operation).
* The list will be empty after this call returns.
......
......@@ -25,6 +25,10 @@
package java.util;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
* The {@code Vector} class implements a growable array of
* objects. Like an array, it contains components that can be
......@@ -1209,4 +1213,89 @@ public class Vector<E>
lastRet = -1;
}
}
@Override
public synchronized void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int elementCount = this.elementCount;
for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public synchronized boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
// figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final int size = elementCount;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
if (filter.test(element)) {
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// shift surviving elements left over the spaces left by removed elements
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
final int newSize = size - removeCount;
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
for (int k=newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
elementCount = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
@Override
@SuppressWarnings("unchecked")
public synchronized void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = elementCount;
for (int i=0; modCount == expectedModCount && i < size; i++) {
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
@Override
@SuppressWarnings("unchecked")
public synchronized void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, elementCount, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
}
......@@ -36,6 +36,9 @@
package java.util.concurrent;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
* A thread-safe variant of {@link java.util.ArrayList} in which all mutative
......@@ -1260,8 +1263,57 @@ public class CopyOnWriteArrayList<E>
}
}
}
@Override
public void forEach(Consumer<? super E> action) {
@SuppressWarnings("unchecked")
final E[] elements = (E[]) l.getArray();
checkForComodification();
l.forEach(action, elements, offset, offset + size);
}
@Override
public void sort(Comparator<? super E> c) {
final ReentrantLock lock = l.lock;
lock.lock();
try {
checkForComodification();
l.sort(c, offset, offset + size);
expectedArray = l.getArray();
} finally {
lock.unlock();
}
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
final ReentrantLock lock = l.lock;
lock.lock();
try {
checkForComodification();
final int removeCount =
l.removeIf(filter, offset, offset + size);
expectedArray = l.getArray();
size -= removeCount;
return removeCount > 0;
} finally {
lock.unlock();
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
final ReentrantLock lock = l.lock;
lock.lock();
try {
checkForComodification();
l.replaceAll(operator, offset, offset + size);
expectedArray = l.getArray();
} finally {
lock.unlock();
}
}
}
private static class COWSubListIterator<E> implements ListIterator<E> {
private final ListIterator<E> it;
......@@ -1333,4 +1385,139 @@ public class CopyOnWriteArrayList<E>
throw new Error(e);
}
}
@Override
@SuppressWarnings("unchecked")
public void forEach(Consumer<? super E> action) {
forEach(action, (E[]) getArray(), 0, size());
}
private void forEach(Consumer<? super E> action,
final E[] elements,
final int from, final int to) {
Objects.requireNonNull(action);
for (int i = from; i < to; i++) {
action.accept(elements[i]);
}
}
@Override
public void sort(Comparator<? super E> c) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
sort(c, 0, size());
} finally {
lock.unlock();
}
}
// must be called with this.lock held
@SuppressWarnings("unchecked")
private void sort(Comparator<? super E> c, final int from, final int to) {
final E[] elements = (E[]) getArray();
final E[] newElements = Arrays.copyOf(elements, elements.length);
// only elements [from, to) are sorted
Arrays.sort(newElements, from, to, c);
setArray(newElements);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
final ReentrantLock lock = this.lock;
lock.lock();
try {
return removeIf(filter, 0, size()) > 0;
} finally {
lock.unlock();
}
}
// must be called with this.lock held
private int removeIf(Predicate<? super E> filter, final int from, final int to) {
Objects.requireNonNull(filter);
final ReentrantLock lock = this.lock;
lock.lock();
try {
@SuppressWarnings("unchecked")
final E[] elements = (E[]) getArray();
// figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final int range = to - from;
final BitSet removeSet = new BitSet(range);
for (int i = 0; i < range; i++) {
final E element = elements[from + i];
if (filter.test(element)) {
// removeSet is zero-based to keep its size small
removeSet.set(i);
removeCount++;
}
}
// copy surviving elements into a new array
if (removeCount > 0) {
final int newSize = elements.length - removeCount;
final int newRange = newSize - from;
@SuppressWarnings("unchecked")
final E[] newElements = (E[]) new Object[newSize];
// copy elements before [from, to) unmodified
for (int i = 0; i < from; i++) {
newElements[i] = elements[i];
}
// elements [from, to) are subject to removal
int j = 0;
for (int i = 0; (i < range) && (j < newRange); i++) {
i = removeSet.nextClearBit(i);
if (i >= range) {
break;
}
newElements[from + (j++)] = elements[from + i];
}
// copy any remaining elements beyond [from, to)
j += from;
for (int i = to; (i < elements.length) && (j < newSize); i++) {
newElements[j++] = elements[i];
}
setArray(newElements);
}
return removeCount;
} finally {
lock.unlock();
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ReentrantLock lock = this.lock;
lock.lock();
try {
replaceAll(operator, 0, size());
} finally {
lock.unlock();
}
}
// must be called with this.lock held
@SuppressWarnings("unchecked")
private void replaceAll(UnaryOperator<E> operator, final int from, final int to) {
final E[] elements = (E[]) getArray();
final E[] newElements = (E[]) new Object[elements.length];
for (int i = 0; i < from; i++) {
newElements[i] = elements[i];
}
// the operator is only applied to elements [from, to)
for (int i = from; i < to; i++) {
newElements[i] = operator.apply(elements[i]);
}
for (int i = to; i < elements.length; i++) {
newElements[i] = elements[i];
}
setArray(newElements);
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Predicate;
/**
* @test
* @library testlibrary
* @build CollectionAsserts CollectionSupplier
* @run testng CollectionDefaults
* @summary Unit tests for extension methods on Collection
*/
public class CollectionDefaults {
public static final Predicate<Integer> pEven = x -> 0 == x % 2;
public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
private static final String[] SET_CLASSES = {
"java.util.HashSet",
"java.util.LinkedHashSet",
"java.util.TreeSet"
};
private static final int SIZE = 100;
@DataProvider(name="setProvider", parallel=true)
public static Object[][] setCases() {
final List<Object[]> cases = new LinkedList<>();
cases.add(new Object[] { new HashSet<>() });
cases.add(new Object[] { new LinkedHashSet<>() });
cases.add(new Object[] { new TreeSet<>() });
cases.add(new Object[] { Collections.newSetFromMap(new HashMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new LinkedHashMap()) });
cases.add(new Object[] { Collections.newSetFromMap(new TreeMap<>()) });
cases.add(new Object[] { new HashSet(){{add(42);}} });
cases.add(new Object[] { new LinkedHashSet(){{add(42);}} });
cases.add(new Object[] { new TreeSet(){{add(42);}} });
return cases.toArray(new Object[0][cases.size()]);
}
@Test(dataProvider = "setProvider")
public void testProvidedWithNull(final Set<Integer> set) throws Exception {
try {
set.forEach(null);
fail("expected NPE not thrown");
} catch (NullPointerException npe) {}
try {
set.removeIf(null);
fail("expected NPE not thrown");
} catch (NullPointerException npe) {}
}
@Test
public void testForEach() throws Exception {
final CollectionSupplier supplier = new CollectionSupplier(SET_CLASSES, SIZE);
for (final CollectionSupplier.TestCase test : supplier.get()) {
final Set<Integer> original = ((Set<Integer>) test.original);
final Set<Integer> set = ((Set<Integer>) test.collection);
try {
set.forEach(null);
fail("expected NPE not thrown");
} catch (NullPointerException npe) {}
if (test.className.equals("java.util.HashSet")) {
CollectionAsserts.assertContentsUnordered(set, original);
} else {
CollectionAsserts.assertContents(set, original);
}
final List<Integer> actual = new LinkedList<>();
set.forEach(actual::add);
if (test.className.equals("java.util.HashSet")) {
CollectionAsserts.assertContentsUnordered(actual, set);
CollectionAsserts.assertContentsUnordered(actual, original);
} else {
CollectionAsserts.assertContents(actual, set);
CollectionAsserts.assertContents(actual, original);
}
}
}
@Test
public void testRemoveIf() throws Exception {
final CollectionSupplier supplier = new CollectionSupplier(SET_CLASSES, SIZE);
for (final CollectionSupplier.TestCase test : supplier.get()) {
final Set<Integer> original = ((Set<Integer>) test.original);
final Set<Integer> set = ((Set<Integer>) test.collection);
try {
set.removeIf(null);
fail("expected NPE not thrown");
} catch (NullPointerException npe) {}
if (test.className.equals("java.util.HashSet")) {
CollectionAsserts.assertContentsUnordered(set, original);
} else {
CollectionAsserts.assertContents(set, original);
}
set.removeIf(pEven);
for (int i : set) {
assertTrue((i % 2) == 1);
}
for (int i : original) {
if (i % 2 == 1) {
assertTrue(set.contains(i));
}
}
set.removeIf(pOdd);
assertTrue(set.isEmpty());
}
}
}
此差异已折叠。
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
* @library
* CollectionAssert -- assertion methods for lambda test cases
*/
public class CollectionAsserts {
public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
assertCountSum(it.iterator(), count, sum);
}
public static void assertCountSum(Iterator<? super Integer> it, int count, int sum) {
int c = 0;
int s = 0;
while (it.hasNext()) {
int i = (Integer) it.next();
c++;
s += i;
}
assertEquals(c, count);
assertEquals(s, sum);
}
public static void assertConcat(Iterator<Character> it, String result) {
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
sb.append(it.next());
}
assertEquals(result, sb.toString());
}
public static<T extends Comparable<? super T>> void assertSorted(Iterator<T> i) {
if (!i.hasNext())
return;
T last = i.next();
while (i.hasNext()) {
T t = i.next();
assertTrue(last.compareTo(t) <= 0);
assertTrue(t.compareTo(last) >= 0);
last = t;
}
}
public static<T> void assertSorted(Iterator<T> i, Comparator<? super T> comp) {
if (!i.hasNext())
return;
T last = i.next();
while (i.hasNext()) {
T t = i.next();
assertTrue(comp.compare(last, t) <= 0);
assertTrue(comp.compare(t, last) >= 0);
last = t;
}
}
public static<T extends Comparable<? super T>> void assertSorted(Iterable<T> iter) {
assertSorted(iter.iterator());
}
public static<T> void assertSorted(Iterable<T> iter, Comparator<? super T> comp) {
assertSorted(iter.iterator(), comp);
}
public static <T> void assertUnique(Iterable<T> iter) {
assertUnique(iter.iterator());
}
public static<T> void assertUnique(Iterator<T> iter) {
if (!iter.hasNext()) {
return;
}
Set<T> uniq = new HashSet<>();
while(iter.hasNext()) {
T each = iter.next();
assertTrue(!uniq.contains(each));
uniq.add(each);
}
}
public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
assertContents(actual.iterator(), expected.iterator());
}
public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
List<T> history = new ArrayList<>();
while (expected.hasNext()) {
if (!actual.hasNext()) {
List<T> expectedData = new ArrayList<>(history);
while (expected.hasNext())
expectedData.add(expected.next());
fail(String.format("Premature end of data; expected=%s, found=%s", expectedData, history));
}
T a = actual.next();
T e = expected.next();
history.add(a);
if (!Objects.equals(a, e))
fail(String.format("Data mismatch; preceding=%s, nextExpected=%s, nextFound=%s", history, e, a));
}
if (actual.hasNext()) {
List<T> rest = new ArrayList<>();
while (actual.hasNext())
rest.add(actual.next());
fail(String.format("Unexpected data %s after %s", rest, history));
}
}
@SafeVarargs
@SuppressWarnings("varargs")
public static<T> void assertContents(Iterator<T> actual, T... expected) {
assertContents(actual, Arrays.asList(expected).iterator());
}
public static <T> boolean equalsContentsUnordered(Iterable<T> a, Iterable<T> b) {
Set<T> sa = new HashSet<>();
for (T t : a) {
sa.add(t);
}
Set<T> sb = new HashSet<>();
for (T t : b) {
sb.add(t);
}
return Objects.equals(sa, sb);
}
public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
ArrayList<T> one = new ArrayList<>();
for (T t : actual)
one.add(t);
ArrayList<T> two = new ArrayList<>();
for (T t : expected)
two.add(t);
Collections.sort(one);
Collections.sort(two);
assertContents(one, two);
}
static <T> void assertSplitContents(Iterable<Iterable<T>> splits, Iterable<T> list) {
Iterator<Iterable<T>> mI = splits.iterator();
Iterator<T> pI = null;
Iterator<T> lI = list.iterator();
while (lI.hasNext()) {
if (pI == null)
pI = mI.next().iterator();
while (!pI.hasNext()) {
if (!mI.hasNext()) {
break;
}
else {
pI = mI.next().iterator();
}
}
assertTrue(pI.hasNext());
T pT = pI.next();
T lT = lI.next();
assertEquals(pT, lT);
}
if (pI != null) {
assertTrue(!pI.hasNext());
}
while(mI.hasNext()) {
pI = mI.next().iterator();
assertTrue(!pI.hasNext());
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.Exception;
import java.lang.Integer;
import java.lang.Iterable;
import java.lang.Override;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.testng.TestException;
import static org.testng.Assert.assertTrue;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;
/**
* @library
* @summary A Supplier of test cases for Collection tests
*/
public final class CollectionSupplier implements Supplier<Iterable<CollectionSupplier.TestCase>> {
private final String[] classNames;
private final int size;
/**
* A Collection test case.
*/
public static final class TestCase {
/**
* The name of the test case.
*/
public final String name;
/**
* Class name of the instantiated Collection.
*/
public final String className;
/**
* Unmodifiable reference collection, useful for comparisons.
*/
public final Collection<Integer> original;
/**
* A modifiable test collection.
*/
public final Collection<Integer> collection;
/**
* Create a Collection test case.
* @param name name of the test case
* @param className class name of the instantiated collection
* @param original reference collection
* @param collection the modifiable test collection
*/
public TestCase(String name, String className,
Collection<Integer> original, Collection<Integer> collection) {
this.name = name;
this.className = className;
this.original =
List.class.isAssignableFrom(original.getClass()) ?
Collections.unmodifiableList((List<Integer>) original) :
Set.class.isAssignableFrom(original.getClass()) ?
Collections.unmodifiableSet((Set<Integer>) original) :
Collections.unmodifiableCollection(original);
this.collection = collection;
}
@Override
public String toString() {
return name + " " + className +
"\n original: " + original +
"\n target: " + collection;
}
}
/**
* Shuffle a list using a PRNG with known seed for repeatability
* @param list the list to be shuffled
*/
public static <E> void shuffle(final List<E> list) {
// PRNG with known seed for repeatable tests
final Random prng = new Random(13);
final int size = list.size();
for (int i=0; i < size; i++) {
// random index in interval [i, size)
final int j = i + prng.nextInt(size - i);
// swap elements at indices i & j
final E e = list.get(i);
list.set(i, list.get(j));
list.set(j, e);
}
}
/**
* Create a {@code Supplier} that creates instances of specified collection
* classes of specified length.
*
* @param classNames class names that implement {@code Collection}
* @param size the desired size of each collection
*/
public CollectionSupplier(String[] classNames, int size) {
this.classNames = Arrays.copyOf(classNames, classNames.length);
this.size = size;
}
@Override
public Iterable<TestCase> get() {
try {
return getThrows();
} catch (Exception e) {
throw new TestException(e);
}
}
private Iterable<TestCase> getThrows() throws Exception {
final Collection<TestCase> collections = new LinkedList<>();
for (final String className : classNames) {
@SuppressWarnings("unchecked")
final Class<? extends Collection<Integer>> type =
(Class<? extends Collection<Integer>>) Class.forName(className);
final Constructor<? extends Collection<Integer>>
defaultConstructor = type.getConstructor();
final Constructor<? extends Collection<Integer>>
copyConstructor = type.getConstructor(Collection.class);
final Collection<Integer> empty = defaultConstructor.newInstance();
collections.add(new TestCase("empty",
className,
copyConstructor.newInstance(empty),
empty));
final Collection<Integer> single = defaultConstructor.newInstance();
single.add(42);
collections.add(new TestCase("single",
className,
copyConstructor.newInstance(single),
single));
final Collection<Integer> regular = defaultConstructor.newInstance();
for (int i=0; i < size; i++) {
regular.add(i);
}
collections.add(new TestCase("regular",
className,
copyConstructor.newInstance(regular),
regular));
final Collection<Integer> reverse = defaultConstructor.newInstance();
for (int i=size; i >= 0; i--) {
reverse.add(i);
}
collections.add(new TestCase("reverse",
className,
copyConstructor.newInstance(reverse),
reverse));
final Collection<Integer> odds = defaultConstructor.newInstance();
for (int i=0; i < size; i++) {
odds.add((i * 2) + 1);
}
collections.add(new TestCase("odds",
className,
copyConstructor.newInstance(odds),
odds));
final Collection<Integer> evens = defaultConstructor.newInstance();
for (int i=0; i < size; i++) {
evens.add(i * 2);
}
collections.add(new TestCase("evens",
className,
copyConstructor.newInstance(evens),
evens));
final Collection<Integer> fibonacci = defaultConstructor.newInstance();
int prev2 = 0;
int prev1 = 1;
for (int i=0; i < size; i++) {
final int n = prev1 + prev2;
if (n < 0) { // stop on overflow
break;
}
fibonacci.add(n);
prev2 = prev1;
prev1 = n;
}
collections.add(new TestCase("fibonacci",
className,
copyConstructor.newInstance(fibonacci),
fibonacci));
// variants where the size of the backing storage != reported size
// created by removing half of the elements
final Collection<Integer> emptyWithSlack = defaultConstructor.newInstance();
emptyWithSlack.add(42);
assertTrue(emptyWithSlack.remove(42));
collections.add(new TestCase("emptyWithSlack",
className,
copyConstructor.newInstance(emptyWithSlack),
emptyWithSlack));
final Collection<Integer> singleWithSlack = defaultConstructor.newInstance();
singleWithSlack.add(42);
singleWithSlack.add(43);
assertTrue(singleWithSlack.remove(43));
collections.add(new TestCase("singleWithSlack",
className,
copyConstructor.newInstance(singleWithSlack),
singleWithSlack));
final Collection<Integer> regularWithSlack = defaultConstructor.newInstance();
for (int i=0; i < (2 * size); i++) {
regularWithSlack.add(i);
}
assertTrue(regularWithSlack.removeIf((x) -> {return x >= size;}));
collections.add(new TestCase("regularWithSlack",
className,
copyConstructor.newInstance(regularWithSlack),
regularWithSlack));
final Collection<Integer> reverseWithSlack = defaultConstructor.newInstance();
for (int i=2 * size; i >= 0; i--) {
reverseWithSlack.add(i);
}
assertTrue(reverseWithSlack.removeIf((x) -> {return x < size;}));
collections.add(new TestCase("reverseWithSlack",
className,
copyConstructor.newInstance(reverseWithSlack),
reverseWithSlack));
final Collection<Integer> oddsWithSlack = defaultConstructor.newInstance();
for (int i = 0; i < 2 * size; i++) {
oddsWithSlack.add((i * 2) + 1);
}
assertTrue(oddsWithSlack.removeIf((x) -> {return x >= size;}));
collections.add(new TestCase("oddsWithSlack",
className,
copyConstructor.newInstance(oddsWithSlack),
oddsWithSlack));
final Collection<Integer> evensWithSlack = defaultConstructor.newInstance();
for (int i = 0; i < 2 * size; i++) {
evensWithSlack.add(i * 2);
}
assertTrue(evensWithSlack.removeIf((x) -> {return x >= size;}));
collections.add(new TestCase("evensWithSlack",
className,
copyConstructor.newInstance(evensWithSlack),
evensWithSlack));
final Collection<Integer> fibonacciWithSlack = defaultConstructor.newInstance();
prev2 = 0;
prev1 = 1;
for (int i=0; i < size; i++) {
final int n = prev1 + prev2;
if (n < 0) { // stop on overflow
break;
}
fibonacciWithSlack.add(n);
prev2 = prev1;
prev1 = n;
}
assertTrue(fibonacciWithSlack.removeIf((x) -> {return x < 20;}));
collections.add(new TestCase("fibonacciWithSlack",
className,
copyConstructor.newInstance(fibonacciWithSlack),
fibonacciWithSlack));
}
return collections;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册