8060192: Add default method <A> A[] Collection.toArray(IntFunction<A[]> generator)

Reviewed-by: martin, forax, psandoz, briangoetz
This commit is contained in:
Stuart Marks 2018-06-21 08:25:03 -07:00
parent 5be0048099
commit 693a6dd27a
10 changed files with 117 additions and 50 deletions

View File

@ -25,6 +25,7 @@
package java.util; package java.util;
import java.util.function.IntFunction;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
@ -276,8 +277,12 @@ public interface Collection<E> extends Iterable<E> {
* allocate a new array even if this collection is backed by an array). * allocate a new array even if this collection is backed by an array).
* The caller is thus free to modify the returned array. * The caller is thus free to modify the returned array.
* *
* <p>This method acts as bridge between array-based and collection-based * @apiNote
* APIs. * This method acts as a bridge between array-based and collection-based APIs.
* It returns an array whose runtime type is {@code Object[]}.
* Use {@link #toArray(Object[]) toArray(T[])} to reuse an existing
* array, or use {@link #toArray(IntFunction)} to control the runtime type
* of the array.
* *
* @return an array, whose {@linkplain Class#getComponentType runtime component * @return an array, whose {@linkplain Class#getComponentType runtime component
* type} is {@code Object}, containing all of the elements in this collection * type} is {@code Object}, containing all of the elements in this collection
@ -302,19 +307,27 @@ public interface Collection<E> extends Iterable<E> {
* are returned by its iterator, this method must return the elements in * are returned by its iterator, this method must return the elements in
* the same order. * the same order.
* *
* <p>Like the {@link #toArray()} method, this method acts as bridge between * @apiNote
* array-based and collection-based APIs. Further, this method allows * This method acts as a bridge between array-based and collection-based APIs.
* precise control over the runtime type of the output array, and may, * It allows an existing array to be reused under certain circumstances.
* under certain circumstances, be used to save allocation costs. * Use {@link #toArray()} to create an array whose runtime type is {@code Object[]},
* or use {@link #toArray(IntFunction)} to control the runtime type of
* the array.
* *
* <p>Suppose {@code x} is a collection known to contain only strings. * <p>Suppose {@code x} is a collection known to contain only strings.
* The following code can be used to dump the collection into a newly * The following code can be used to dump the collection into a previously
* allocated array of {@code String}: * allocated {@code String} array:
* *
* <pre> * <pre>
* String[] y = x.toArray(new String[0]);</pre> * String[] y = new String[SIZE];
* ...
* y = x.toArray(y);</pre>
* *
* Note that {@code toArray(new Object[0])} is identical in function to * <p>The return value is reassigned to the variable {@code y}, because a
* new array will be allocated and returned if the collection {@code x} has
* too many elements to fit into the existing array {@code y}.
*
* <p>Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}. * {@code toArray()}.
* *
* @param <T> the component type of the array to contain the collection * @param <T> the component type of the array to contain the collection
@ -329,6 +342,45 @@ public interface Collection<E> extends Iterable<E> {
*/ */
<T> T[] toArray(T[] a); <T> T[] toArray(T[] a);
/**
* Returns an array containing all of the elements in this collection,
* using the provided {@code generator} function to allocate the returned array.
*
* <p>If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements in
* the same order.
*
* @apiNote
* This method acts as a bridge between array-based and collection-based APIs.
* It allows creation of an array of a particular runtime type. Use
* {@link #toArray()} to create an array whose runtime type is {@code Object[]},
* or use {@link #toArray(Object[]) toArray(T[])} to reuse an existing array.
*
* <p>Suppose {@code x} is a collection known to contain only strings.
* The following code can be used to dump the collection into a newly
* allocated array of {@code String}:
*
* <pre>
* String[] y = x.toArray(String[]::new);</pre>
*
* @implSpec
* The default implementation calls the generator function with zero
* and then passes the resulting array to {@link #toArray(Object[]) toArray(T[])}.
*
* @param <T> the component type of the array to contain the collection
* @param generator a function which produces a new array of the desired
* type and the provided length
* @return an array containing all of the elements in this collection
* @throws ArrayStoreException if the runtime type of any element in this
* collection is not assignable to the {@linkplain Class#getComponentType
* runtime component type} of the generated array
* @throws NullPointerException if the generator function is null
* @since 11
*/
default <T> T[] toArray(IntFunction<T[]> generator) {
return toArray(generator.apply(0));
}
// Modification Operations // Modification Operations
/** /**

View File

@ -33,6 +33,7 @@ import java.util.function.BiConsumer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -1028,12 +1029,13 @@ public class Collections {
this.c = c; this.c = c;
} }
public int size() {return c.size();} public int size() {return c.size();}
public boolean isEmpty() {return c.isEmpty();} public boolean isEmpty() {return c.isEmpty();}
public boolean contains(Object o) {return c.contains(o);} public boolean contains(Object o) {return c.contains(o);}
public Object[] toArray() {return c.toArray();} public Object[] toArray() {return c.toArray();}
public <T> T[] toArray(T[] a) {return c.toArray(a);} public <T> T[] toArray(T[] a) {return c.toArray(a);}
public String toString() {return c.toString();} public <T> T[] toArray(IntFunction<T[]> f) {return c.toArray(f);}
public String toString() {return c.toString();}
public Iterator<E> iterator() { public Iterator<E> iterator() {
return new Iterator<E>() { return new Iterator<E>() {
@ -2020,6 +2022,9 @@ public class Collections {
public <T> T[] toArray(T[] a) { public <T> T[] toArray(T[] a) {
synchronized (mutex) {return c.toArray(a);} synchronized (mutex) {return c.toArray(a);}
} }
public <T> T[] toArray(IntFunction<T[]> f) {
synchronized (mutex) {return c.toArray(f);}
}
public Iterator<E> iterator() { public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user! return c.iterator(); // Must be manually synched by user!
@ -3049,14 +3054,15 @@ public class Collections {
this.type = Objects.requireNonNull(type, "type"); this.type = Objects.requireNonNull(type, "type");
} }
public int size() { return c.size(); } public int size() { return c.size(); }
public boolean isEmpty() { return c.isEmpty(); } public boolean isEmpty() { return c.isEmpty(); }
public boolean contains(Object o) { return c.contains(o); } public boolean contains(Object o) { return c.contains(o); }
public Object[] toArray() { return c.toArray(); } public Object[] toArray() { return c.toArray(); }
public <T> T[] toArray(T[] a) { return c.toArray(a); } public <T> T[] toArray(T[] a) { return c.toArray(a); }
public String toString() { return c.toString(); } public <T> T[] toArray(IntFunction<T[]> f) { return c.toArray(f); }
public boolean remove(Object o) { return c.remove(o); } public String toString() { return c.toString(); }
public void clear() { c.clear(); } public boolean remove(Object o) { return c.remove(o); }
public void clear() { c.clear(); }
public boolean containsAll(Collection<?> coll) { public boolean containsAll(Collection<?> coll) {
return c.containsAll(coll); return c.containsAll(coll);
@ -5559,25 +5565,26 @@ public class Collections {
implements Queue<E>, Serializable { implements Queue<E>, Serializable {
private static final long serialVersionUID = 1802017725587941708L; private static final long serialVersionUID = 1802017725587941708L;
private final Deque<E> q; private final Deque<E> q;
AsLIFOQueue(Deque<E> q) { this.q = q; } AsLIFOQueue(Deque<E> q) { this.q = q; }
public boolean add(E e) { q.addFirst(e); return true; } public boolean add(E e) { q.addFirst(e); return true; }
public boolean offer(E e) { return q.offerFirst(e); } public boolean offer(E e) { return q.offerFirst(e); }
public E poll() { return q.pollFirst(); } public E poll() { return q.pollFirst(); }
public E remove() { return q.removeFirst(); } public E remove() { return q.removeFirst(); }
public E peek() { return q.peekFirst(); } public E peek() { return q.peekFirst(); }
public E element() { return q.getFirst(); } public E element() { return q.getFirst(); }
public void clear() { q.clear(); } public void clear() { q.clear(); }
public int size() { return q.size(); } public int size() { return q.size(); }
public boolean isEmpty() { return q.isEmpty(); } public boolean isEmpty() { return q.isEmpty(); }
public boolean contains(Object o) { return q.contains(o); } public boolean contains(Object o) { return q.contains(o); }
public boolean remove(Object o) { return q.remove(o); } public boolean remove(Object o) { return q.remove(o); }
public Iterator<E> iterator() { return q.iterator(); } public Iterator<E> iterator() { return q.iterator(); }
public Object[] toArray() { return q.toArray(); } public Object[] toArray() { return q.toArray(); }
public <T> T[] toArray(T[] a) { return q.toArray(a); } public <T> T[] toArray(T[] a) { return q.toArray(a); }
public String toString() { return q.toString(); } public <T> T[] toArray(IntFunction<T[]> f) { return q.toArray(f); }
public boolean containsAll(Collection<?> c) {return q.containsAll(c);} public String toString() { return q.toString(); }
public boolean removeAll(Collection<?> c) {return q.removeAll(c);} public boolean containsAll(Collection<?> c) { return q.containsAll(c); }
public boolean retainAll(Collection<?> c) {return q.retainAll(c);} 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 // We use inherited addAll; forwarding addAll would be wrong
// Override default methods in Collection // Override default methods in Collection

View File

@ -415,6 +415,7 @@ public class MOAT {
equal(c.toString(),"[]"); equal(c.toString(),"[]");
equal(c.toArray().length, 0); equal(c.toArray().length, 0);
equal(c.toArray(new Object[0]).length, 0); equal(c.toArray(new Object[0]).length, 0);
equal(c.toArray(Object[]::new).length, 0);
check(c.toArray(new Object[]{42})[0] == null); check(c.toArray(new Object[]{42})[0] == null);
Object[] a = new Object[1]; a[0] = Boolean.TRUE; Object[] a = new Object[1]; a[0] = Boolean.TRUE;
@ -690,6 +691,13 @@ public class MOAT {
check(a.getClass() == Integer[].class); check(a.getClass() == Integer[].class);
} }
{
Integer[] a = c.toArray(Integer[]::new);
equal(c.size(), a.length);
check(a.getClass() == Integer[].class);
check(Arrays.equals(c.toArray(new Integer[0]), a));
}
check(c.equals(c)); check(c.equals(c));
if (c instanceof Serializable) { if (c instanceof Serializable) {
//System.out.printf("Serializing %s%n", c.getClass().getName()); //System.out.printf("Serializing %s%n", c.getClass().getName());

View File

@ -772,7 +772,7 @@ public class ArrayDequeTest extends JSR166TestCase {
ArrayDeque l = new ArrayDeque(); ArrayDeque l = new ArrayDeque();
l.add(new Object()); l.add(new Object());
try { try {
l.toArray(null); l.toArray((Object[])null);
shouldThrow(); shouldThrow();
} catch (NullPointerException success) {} } catch (NullPointerException success) {}
} }

View File

@ -161,7 +161,7 @@ public abstract class BlockingQueueTest extends JSR166TestCase {
public void testToArray_NullArray() { public void testToArray_NullArray() {
final Collection q = emptyCollection(); final Collection q = emptyCollection();
try { try {
q.toArray(null); q.toArray((Object[])null);
shouldThrow(); shouldThrow();
} catch (NullPointerException success) {} } catch (NullPointerException success) {}
} }

View File

@ -209,7 +209,7 @@ public class Collection8Test extends JSR166TestCase {
() -> c.iterator().forEachRemaining(null), () -> c.iterator().forEachRemaining(null),
() -> c.spliterator().forEachRemaining(null), () -> c.spliterator().forEachRemaining(null),
() -> c.spliterator().tryAdvance(null), () -> c.spliterator().tryAdvance(null),
() -> c.toArray(null)); () -> c.toArray((Object[])null));
if (!impl.permitsNulls()) { if (!impl.permitsNulls()) {
assertThrows( assertThrows(

View File

@ -712,7 +712,7 @@ public class ConcurrentLinkedDequeTest extends JSR166TestCase {
public void testToArray_NullArg() { public void testToArray_NullArg() {
ConcurrentLinkedDeque q = populatedDeque(SIZE); ConcurrentLinkedDeque q = populatedDeque(SIZE);
try { try {
q.toArray(null); q.toArray((Object[])null);
shouldThrow(); shouldThrow();
} catch (NullPointerException success) {} } catch (NullPointerException success) {}
} }

View File

@ -439,7 +439,7 @@ public class ConcurrentLinkedQueueTest extends JSR166TestCase {
public void testToArray_NullArg() { public void testToArray_NullArg() {
ConcurrentLinkedQueue q = populatedQueue(SIZE); ConcurrentLinkedQueue q = populatedQueue(SIZE);
try { try {
q.toArray(null); q.toArray((Object[])null);
shouldThrow(); shouldThrow();
} catch (NullPointerException success) {} } catch (NullPointerException success) {}
} }

View File

@ -409,7 +409,7 @@ public class LinkedListTest extends JSR166TestCase {
LinkedList l = new LinkedList(); LinkedList l = new LinkedList();
l.add(new Object()); l.add(new Object());
try { try {
l.toArray(null); l.toArray((Object[])null);
shouldThrow(); shouldThrow();
} catch (NullPointerException success) {} } catch (NullPointerException success) {}
} }

View File

@ -464,7 +464,7 @@ public class SynchronousQueueTest extends JSR166TestCase {
public void testToArray_null(boolean fair) { public void testToArray_null(boolean fair) {
final SynchronousQueue q = new SynchronousQueue(fair); final SynchronousQueue q = new SynchronousQueue(fair);
try { try {
Object[] o = q.toArray(null); Object[] o = q.toArray((Object[])null);
shouldThrow(); shouldThrow();
} catch (NullPointerException success) {} } catch (NullPointerException success) {}
} }