# HG changeset patch # User smarks # Date 1529594703 25200 # Node ID 3ef0862bbb3d9abd200530b3083291f8a9274d66 # Parent 5c886cfc6ef5abbc185b3e3ba75a3771a893a165 8060192: Add default method A[] Collection.toArray(IntFunction generator) Reviewed-by: martin, forax, psandoz, briangoetz diff -r 5c886cfc6ef5 -r 3ef0862bbb3d src/java.base/share/classes/java/util/Collection.java --- a/src/java.base/share/classes/java/util/Collection.java Thu Jun 21 11:10:44 2018 -0400 +++ b/src/java.base/share/classes/java/util/Collection.java Thu Jun 21 08:25:03 2018 -0700 @@ -25,6 +25,7 @@ package java.util; +import java.util.function.IntFunction; import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -276,8 +277,12 @@ * allocate a new array even if this collection is backed by an array). * The caller is thus free to modify the returned array. * - *

This method acts as bridge between array-based and collection-based - * APIs. + * @apiNote + * 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 * type} is {@code Object}, containing all of the elements in this collection @@ -302,19 +307,27 @@ * are returned by its iterator, this method must return the elements in * the same order. * - *

Like the {@link #toArray()} method, this method acts as bridge between - * array-based and collection-based APIs. Further, this method allows - * precise control over the runtime type of the output array, and may, - * under certain circumstances, be used to save allocation costs. + * @apiNote + * This method acts as a bridge between array-based and collection-based APIs. + * It allows an existing array to be reused under certain circumstances. + * 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. * *

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}: + * The following code can be used to dump the collection into a previously + * allocated {@code String} array: * *

-     *     String[] y = x.toArray(new String[0]);
+ * String[] y = new String[SIZE]; + * ... + * y = x.toArray(y); * - * Note that {@code toArray(new Object[0])} is identical in function to + *

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}. + * + *

Note that {@code toArray(new Object[0])} is identical in function to * {@code toArray()}. * * @param the component type of the array to contain the collection @@ -329,6 +342,45 @@ */ 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. + * + *

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. + * + *

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}: + * + *

+     *     String[] y = x.toArray(String[]::new);
+ * + * @implSpec + * The default implementation calls the generator function with zero + * and then passes the resulting array to {@link #toArray(Object[]) toArray(T[])}. + * + * @param 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[] toArray(IntFunction generator) { + return toArray(generator.apply(0)); + } + // Modification Operations /** diff -r 5c886cfc6ef5 -r 3ef0862bbb3d src/java.base/share/classes/java/util/Collections.java --- a/src/java.base/share/classes/java/util/Collections.java Thu Jun 21 11:10:44 2018 -0400 +++ b/src/java.base/share/classes/java/util/Collections.java Thu Jun 21 08:25:03 2018 -0700 @@ -33,6 +33,7 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.IntFunction; import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.stream.IntStream; @@ -1028,12 +1029,13 @@ this.c = c; } - public int size() {return c.size();} - public boolean isEmpty() {return c.isEmpty();} - public boolean contains(Object o) {return c.contains(o);} - public Object[] toArray() {return c.toArray();} - public T[] toArray(T[] a) {return c.toArray(a);} - public String toString() {return c.toString();} + public int size() {return c.size();} + public boolean isEmpty() {return c.isEmpty();} + public boolean contains(Object o) {return c.contains(o);} + public Object[] toArray() {return c.toArray();} + public T[] toArray(T[] a) {return c.toArray(a);} + public T[] toArray(IntFunction f) {return c.toArray(f);} + public String toString() {return c.toString();} public Iterator iterator() { return new Iterator() { @@ -2020,6 +2022,9 @@ public T[] toArray(T[] a) { synchronized (mutex) {return c.toArray(a);} } + public T[] toArray(IntFunction f) { + synchronized (mutex) {return c.toArray(f);} + } public Iterator iterator() { return c.iterator(); // Must be manually synched by user! @@ -3049,14 +3054,15 @@ this.type = Objects.requireNonNull(type, "type"); } - public int size() { return c.size(); } - public boolean isEmpty() { return c.isEmpty(); } - public boolean contains(Object o) { return c.contains(o); } - public Object[] toArray() { return c.toArray(); } - public T[] toArray(T[] a) { return c.toArray(a); } - public String toString() { return c.toString(); } - public boolean remove(Object o) { return c.remove(o); } - public void clear() { c.clear(); } + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains(Object o) { return c.contains(o); } + public Object[] toArray() { return c.toArray(); } + public T[] toArray(T[] a) { return c.toArray(a); } + public T[] toArray(IntFunction f) { return c.toArray(f); } + public String toString() { return c.toString(); } + public boolean remove(Object o) { return c.remove(o); } + public void clear() { c.clear(); } public boolean containsAll(Collection coll) { return c.containsAll(coll); @@ -5559,25 +5565,26 @@ implements Queue, Serializable { private static final long serialVersionUID = 1802017725587941708L; private final Deque q; - AsLIFOQueue(Deque q) { this.q = q; } - public boolean add(E e) { q.addFirst(e); return true; } - public boolean offer(E e) { return q.offerFirst(e); } - public E poll() { return q.pollFirst(); } - public E remove() { return q.removeFirst(); } - public E peek() { return q.peekFirst(); } - public E element() { return q.getFirst(); } - public void clear() { q.clear(); } - public int size() { return q.size(); } - public boolean isEmpty() { return q.isEmpty(); } - public boolean contains(Object o) { return q.contains(o); } - public boolean remove(Object o) { return q.remove(o); } - public Iterator iterator() { return q.iterator(); } - public Object[] toArray() { return q.toArray(); } - public T[] toArray(T[] a) { return q.toArray(a); } - public String toString() { return q.toString(); } - public boolean containsAll(Collection c) {return q.containsAll(c);} - public boolean removeAll(Collection c) {return q.removeAll(c);} - public boolean retainAll(Collection c) {return q.retainAll(c);} + AsLIFOQueue(Deque q) { this.q = q; } + public boolean add(E e) { q.addFirst(e); return true; } + public boolean offer(E e) { return q.offerFirst(e); } + public E poll() { return q.pollFirst(); } + public E remove() { return q.removeFirst(); } + public E peek() { return q.peekFirst(); } + public E element() { return q.getFirst(); } + public void clear() { q.clear(); } + public int size() { return q.size(); } + public boolean isEmpty() { return q.isEmpty(); } + public boolean contains(Object o) { return q.contains(o); } + public boolean remove(Object o) { return q.remove(o); } + public Iterator iterator() { return q.iterator(); } + public Object[] toArray() { return q.toArray(); } + public T[] toArray(T[] a) { return q.toArray(a); } + public T[] toArray(IntFunction f) { return q.toArray(f); } + public String toString() { return q.toString(); } + public boolean containsAll(Collection c) { return q.containsAll(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 // Override default methods in Collection diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/Collection/MOAT.java --- a/test/jdk/java/util/Collection/MOAT.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/Collection/MOAT.java Thu Jun 21 08:25:03 2018 -0700 @@ -415,6 +415,7 @@ equal(c.toString(),"[]"); equal(c.toArray().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); Object[] a = new Object[1]; a[0] = Boolean.TRUE; @@ -690,6 +691,13 @@ 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)); if (c instanceof Serializable) { //System.out.printf("Serializing %s%n", c.getClass().getName()); diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/concurrent/tck/ArrayDequeTest.java --- a/test/jdk/java/util/concurrent/tck/ArrayDequeTest.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/concurrent/tck/ArrayDequeTest.java Thu Jun 21 08:25:03 2018 -0700 @@ -772,7 +772,7 @@ ArrayDeque l = new ArrayDeque(); l.add(new Object()); try { - l.toArray(null); + l.toArray((Object[])null); shouldThrow(); } catch (NullPointerException success) {} } diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/concurrent/tck/BlockingQueueTest.java --- a/test/jdk/java/util/concurrent/tck/BlockingQueueTest.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/concurrent/tck/BlockingQueueTest.java Thu Jun 21 08:25:03 2018 -0700 @@ -161,7 +161,7 @@ public void testToArray_NullArray() { final Collection q = emptyCollection(); try { - q.toArray(null); + q.toArray((Object[])null); shouldThrow(); } catch (NullPointerException success) {} } diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/concurrent/tck/Collection8Test.java --- a/test/jdk/java/util/concurrent/tck/Collection8Test.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/concurrent/tck/Collection8Test.java Thu Jun 21 08:25:03 2018 -0700 @@ -209,7 +209,7 @@ () -> c.iterator().forEachRemaining(null), () -> c.spliterator().forEachRemaining(null), () -> c.spliterator().tryAdvance(null), - () -> c.toArray(null)); + () -> c.toArray((Object[])null)); if (!impl.permitsNulls()) { assertThrows( diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java --- a/test/jdk/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java Thu Jun 21 08:25:03 2018 -0700 @@ -712,7 +712,7 @@ public void testToArray_NullArg() { ConcurrentLinkedDeque q = populatedDeque(SIZE); try { - q.toArray(null); + q.toArray((Object[])null); shouldThrow(); } catch (NullPointerException success) {} } diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java --- a/test/jdk/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java Thu Jun 21 08:25:03 2018 -0700 @@ -439,7 +439,7 @@ public void testToArray_NullArg() { ConcurrentLinkedQueue q = populatedQueue(SIZE); try { - q.toArray(null); + q.toArray((Object[])null); shouldThrow(); } catch (NullPointerException success) {} } diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/concurrent/tck/LinkedListTest.java --- a/test/jdk/java/util/concurrent/tck/LinkedListTest.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/concurrent/tck/LinkedListTest.java Thu Jun 21 08:25:03 2018 -0700 @@ -409,7 +409,7 @@ LinkedList l = new LinkedList(); l.add(new Object()); try { - l.toArray(null); + l.toArray((Object[])null); shouldThrow(); } catch (NullPointerException success) {} } diff -r 5c886cfc6ef5 -r 3ef0862bbb3d test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java --- a/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java Thu Jun 21 11:10:44 2018 -0400 +++ b/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java Thu Jun 21 08:25:03 2018 -0700 @@ -464,7 +464,7 @@ public void testToArray_null(boolean fair) { final SynchronousQueue q = new SynchronousQueue(fair); try { - Object[] o = q.toArray(null); + Object[] o = q.toArray((Object[])null); shouldThrow(); } catch (NullPointerException success) {} }