8180352: Add Stream.toList() method
Reviewed-by: psandoz
This commit is contained in:
parent
89690699b2
commit
41dbc139ab
@ -93,26 +93,27 @@ class ImmutableCollections {
|
|||||||
private static Object[] archivedObjects;
|
private static Object[] archivedObjects;
|
||||||
|
|
||||||
private static final Object EMPTY;
|
private static final Object EMPTY;
|
||||||
|
|
||||||
static final ListN<?> EMPTY_LIST;
|
static final ListN<?> EMPTY_LIST;
|
||||||
|
static final ListN<?> EMPTY_LIST_NULLS;
|
||||||
static final SetN<?> EMPTY_SET;
|
static final SetN<?> EMPTY_SET;
|
||||||
|
|
||||||
static final MapN<?,?> EMPTY_MAP;
|
static final MapN<?,?> EMPTY_MAP;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CDS.initializeFromArchive(ImmutableCollections.class);
|
CDS.initializeFromArchive(ImmutableCollections.class);
|
||||||
if (archivedObjects == null) {
|
if (archivedObjects == null) {
|
||||||
EMPTY = new Object();
|
EMPTY = new Object();
|
||||||
EMPTY_LIST = new ListN<>(new Object[0]);
|
EMPTY_LIST = new ListN<>(new Object[0], false);
|
||||||
|
EMPTY_LIST_NULLS = new ListN<>(new Object[0], true);
|
||||||
EMPTY_SET = new SetN<>();
|
EMPTY_SET = new SetN<>();
|
||||||
EMPTY_MAP = new MapN<>();
|
EMPTY_MAP = new MapN<>();
|
||||||
archivedObjects = new Object[] { EMPTY, EMPTY_LIST, EMPTY_SET, EMPTY_MAP };
|
archivedObjects =
|
||||||
|
new Object[] { EMPTY, EMPTY_LIST, EMPTY_LIST_NULLS, EMPTY_SET, EMPTY_MAP };
|
||||||
} else {
|
} else {
|
||||||
EMPTY = archivedObjects[0];
|
EMPTY = archivedObjects[0];
|
||||||
EMPTY_LIST = (ListN)archivedObjects[1];
|
EMPTY_LIST = (ListN)archivedObjects[1];
|
||||||
EMPTY_SET = (SetN)archivedObjects[2];
|
EMPTY_LIST_NULLS = (ListN)archivedObjects[2];
|
||||||
EMPTY_MAP = (MapN)archivedObjects[3];
|
EMPTY_SET = (SetN)archivedObjects[3];
|
||||||
|
EMPTY_MAP = (MapN)archivedObjects[4];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +121,10 @@ class ImmutableCollections {
|
|||||||
static {
|
static {
|
||||||
SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() {
|
SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() {
|
||||||
public <E> List<E> listFromTrustedArray(Object[] array) {
|
public <E> List<E> listFromTrustedArray(Object[] array) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(array);
|
return ImmutableCollections.listFromTrustedArray(array);
|
||||||
|
}
|
||||||
|
public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) {
|
||||||
|
return ImmutableCollections.listFromTrustedArrayNullsAllowed(array);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -148,18 +152,101 @@ class ImmutableCollections {
|
|||||||
@Override public boolean retainAll(Collection<?> c) { throw uoe(); }
|
@Override public boolean retainAll(Collection<?> c) { throw uoe(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- List Implementations ----------
|
// ---------- List Static Factory Methods ----------
|
||||||
|
|
||||||
// make a copy, short-circuiting based on implementation class
|
/**
|
||||||
|
* Copies a collection into a new List, unless the arg is already a safe,
|
||||||
|
* null-prohibiting unmodifiable list, in which case the arg itself is returned.
|
||||||
|
* Null argument or null elements in the argument will result in NPE.
|
||||||
|
*
|
||||||
|
* @param <E> the List's element type
|
||||||
|
* @param input the input array
|
||||||
|
* @return the new list
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <E> List<E> listCopy(Collection<? extends E> coll) {
|
static <E> List<E> listCopy(Collection<? extends E> coll) {
|
||||||
if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
|
if (coll instanceof List12 || (coll instanceof ListN && ! ((ListN<?>)coll).allowNulls)) {
|
||||||
return (List<E>)coll;
|
return (List<E>)coll;
|
||||||
} else {
|
} else {
|
||||||
return (List<E>)List.of(coll.toArray());
|
return (List<E>)List.of(coll.toArray()); // implicit nullcheck of coll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new List from an untrusted array, creating a new array for internal
|
||||||
|
* storage, and checking for and rejecting null elements.
|
||||||
|
*
|
||||||
|
* @param <E> the List's element type
|
||||||
|
* @param input the input array
|
||||||
|
* @return the new list
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
static <E> List<E> listFromArray(E... input) {
|
||||||
|
// copy and check manually to avoid TOCTOU
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
|
||||||
|
for (int i = 0; i < input.length; i++) {
|
||||||
|
tmp[i] = Objects.requireNonNull(input[i]);
|
||||||
|
}
|
||||||
|
return new ListN<>(tmp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new List from a trusted array, checking for and rejecting null
|
||||||
|
* elements.
|
||||||
|
*
|
||||||
|
* <p>A trusted array has no references retained by the caller. It can therefore be
|
||||||
|
* safely reused as the List's internal storage, avoiding a defensive copy. The array's
|
||||||
|
* class must be Object[].class. This method is declared with a parameter type of
|
||||||
|
* Object... instead of E... so that a varargs call doesn't accidentally create an array
|
||||||
|
* of some class other than Object[].class.
|
||||||
|
*
|
||||||
|
* @param <E> the List's element type
|
||||||
|
* @param input the input array
|
||||||
|
* @return the new list
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <E> List<E> listFromTrustedArray(Object... input) {
|
||||||
|
assert input.getClass() == Object[].class;
|
||||||
|
for (Object o : input) { // implicit null check of 'input' array
|
||||||
|
Objects.requireNonNull(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
return switch (input.length) {
|
||||||
|
case 0 -> (List<E>) ImmutableCollections.EMPTY_LIST;
|
||||||
|
case 1 -> (List<E>) new List12<>(input[0]);
|
||||||
|
case 2 -> (List<E>) new List12<>(input[0], input[1]);
|
||||||
|
default -> (List<E>) new ListN<>(input, false);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new List from a trusted array, allowing null elements.
|
||||||
|
*
|
||||||
|
* <p>A trusted array has no references retained by the caller. It can therefore be
|
||||||
|
* safely reused as the List's internal storage, avoiding a defensive copy. The array's
|
||||||
|
* class must be Object[].class. This method is declared with a parameter type of
|
||||||
|
* Object... instead of E... so that a varargs call doesn't accidentally create an array
|
||||||
|
* of some class other than Object[].class.
|
||||||
|
*
|
||||||
|
* <p>Avoids creating a List12 instance, as it cannot accommodate null elements.
|
||||||
|
*
|
||||||
|
* @param <E> the List's element type
|
||||||
|
* @param input the input array
|
||||||
|
* @return the new list
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <E> List<E> listFromTrustedArrayNullsAllowed(Object... input) {
|
||||||
|
assert input.getClass() == Object[].class;
|
||||||
|
if (input.length == 0) {
|
||||||
|
return (List<E>) EMPTY_LIST_NULLS;
|
||||||
|
} else {
|
||||||
|
return new ListN<>((E[])input, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- List Implementations ----------
|
||||||
|
|
||||||
static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
|
static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
|
||||||
implements List<E>, RandomAccess {
|
implements List<E>, RandomAccess {
|
||||||
|
|
||||||
@ -219,40 +306,18 @@ class ImmutableCollections {
|
|||||||
|
|
||||||
Iterator<?> oit = ((List<?>) o).iterator();
|
Iterator<?> oit = ((List<?>) o).iterator();
|
||||||
for (int i = 0, s = size(); i < s; i++) {
|
for (int i = 0, s = size(); i < s; i++) {
|
||||||
if (!oit.hasNext() || !get(i).equals(oit.next())) {
|
if (!oit.hasNext() || !Objects.equals(get(i), oit.next())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !oit.hasNext();
|
return !oit.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int indexOf(Object o) {
|
|
||||||
Objects.requireNonNull(o);
|
|
||||||
for (int i = 0, s = size(); i < s; i++) {
|
|
||||||
if (o.equals(get(i))) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int lastIndexOf(Object o) {
|
|
||||||
Objects.requireNonNull(o);
|
|
||||||
for (int i = size() - 1; i >= 0; i--) {
|
|
||||||
if (o.equals(get(i))) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int hash = 1;
|
int hash = 1;
|
||||||
for (int i = 0, s = size(); i < s; i++) {
|
for (int i = 0, s = size(); i < s; i++) {
|
||||||
hash = 31 * hash + get(i).hashCode();
|
hash = 31 * hash + Objects.hashCode(get(i));
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
@ -361,7 +426,7 @@ class ImmutableCollections {
|
|||||||
implements RandomAccess {
|
implements RandomAccess {
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
private final List<E> root;
|
private final AbstractImmutableList<E> root;
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
private final int offset;
|
private final int offset;
|
||||||
@ -369,7 +434,8 @@ class ImmutableCollections {
|
|||||||
@Stable
|
@Stable
|
||||||
private final int size;
|
private final int size;
|
||||||
|
|
||||||
private SubList(List<E> root, int offset, int size) {
|
private SubList(AbstractImmutableList<E> root, int offset, int size) {
|
||||||
|
assert root instanceof List12 || root instanceof ListN;
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
@ -386,7 +452,7 @@ class ImmutableCollections {
|
|||||||
* Constructs a sublist of an arbitrary AbstractImmutableList, which is
|
* Constructs a sublist of an arbitrary AbstractImmutableList, which is
|
||||||
* not a SubList itself.
|
* not a SubList itself.
|
||||||
*/
|
*/
|
||||||
static <E> SubList<E> fromList(List<E> list, int fromIndex, int toIndex) {
|
static <E> SubList<E> fromList(AbstractImmutableList<E> list, int fromIndex, int toIndex) {
|
||||||
return new SubList<>(list, fromIndex, toIndex - fromIndex);
|
return new SubList<>(list, fromIndex, toIndex - fromIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,6 +485,36 @@ class ImmutableCollections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean allowNulls() {
|
||||||
|
return root instanceof ListN && ((ListN<?>)root).allowNulls;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object o) {
|
||||||
|
if (!allowNulls() && o == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
for (int i = 0, s = size(); i < s; i++) {
|
||||||
|
if (Objects.equals(o, get(i))) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object o) {
|
||||||
|
if (!allowNulls() && o == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
for (int i = size() - 1; i >= 0; i--) {
|
||||||
|
if (Objects.equals(o, get(i))) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] toArray() {
|
public Object[] toArray() {
|
||||||
Object[] array = new Object[size];
|
Object[] array = new Object[size];
|
||||||
@ -456,7 +552,7 @@ class ImmutableCollections {
|
|||||||
List12(E e0) {
|
List12(E e0) {
|
||||||
this.e0 = Objects.requireNonNull(e0);
|
this.e0 = Objects.requireNonNull(e0);
|
||||||
// Use EMPTY as a sentinel for an unused element: not using null
|
// Use EMPTY as a sentinel for an unused element: not using null
|
||||||
// enable constant folding optimizations over single-element lists
|
// enables constant folding optimizations over single-element lists
|
||||||
this.e1 = EMPTY;
|
this.e1 = EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,6 +582,30 @@ class ImmutableCollections {
|
|||||||
throw outOfBounds(index);
|
throw outOfBounds(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object o) {
|
||||||
|
Objects.requireNonNull(o);
|
||||||
|
if (o.equals(e0)) {
|
||||||
|
return 0;
|
||||||
|
} else if (e1 != EMPTY && o.equals(e1)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object o) {
|
||||||
|
Objects.requireNonNull(o);
|
||||||
|
if (e1 != EMPTY && o.equals(e1)) {
|
||||||
|
return 1;
|
||||||
|
} else if (o.equals(e0)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@java.io.Serial
|
@java.io.Serial
|
||||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
throw new InvalidObjectException("not serial proxy");
|
throw new InvalidObjectException("not serial proxy");
|
||||||
@ -532,31 +652,13 @@ class ImmutableCollections {
|
|||||||
@Stable
|
@Stable
|
||||||
private final E[] elements;
|
private final E[] elements;
|
||||||
|
|
||||||
private ListN(E[] array) {
|
@Stable
|
||||||
elements = array;
|
private final boolean allowNulls;
|
||||||
}
|
|
||||||
|
|
||||||
// creates a new internal array, and checks and rejects null elements
|
// caller must ensure that elements has no nulls if allowNulls is false
|
||||||
@SafeVarargs
|
private ListN(E[] elements, boolean allowNulls) {
|
||||||
static <E> List<E> fromArray(E... input) {
|
this.elements = elements;
|
||||||
// copy and check manually to avoid TOCTOU
|
this.allowNulls = allowNulls;
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
|
|
||||||
for (int i = 0; i < input.length; i++) {
|
|
||||||
tmp[i] = Objects.requireNonNull(input[i]);
|
|
||||||
}
|
|
||||||
return new ListN<>(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoids creating a new array, but checks and rejects null elements.
|
|
||||||
// Declared with Object... arg so that varargs calls don't accidentally
|
|
||||||
// create an array of a subtype.
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static <E> List<E> fromTrustedArray(Object... input) {
|
|
||||||
for (Object o : input) {
|
|
||||||
Objects.requireNonNull(o);
|
|
||||||
}
|
|
||||||
return new ListN<>((E[])input);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -581,7 +683,7 @@ class ImmutableCollections {
|
|||||||
|
|
||||||
@java.io.Serial
|
@java.io.Serial
|
||||||
private Object writeReplace() {
|
private Object writeReplace() {
|
||||||
return new CollSer(CollSer.IMM_LIST, elements);
|
return new CollSer(allowNulls ? CollSer.IMM_LIST_NULLS : CollSer.IMM_LIST, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -603,6 +705,34 @@ class ImmutableCollections {
|
|||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object o) {
|
||||||
|
if (!allowNulls && o == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
Object[] es = elements;
|
||||||
|
for (int i = 0; i < es.length; i++) {
|
||||||
|
if (Objects.equals(o, es[i])) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object o) {
|
||||||
|
if (!allowNulls && o == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
Object[] es = elements;
|
||||||
|
for (int i = es.length - 1; i >= 0; i--) {
|
||||||
|
if (Objects.equals(o, es[i])) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Set Implementations ----------
|
// ---------- Set Implementations ----------
|
||||||
@ -1228,12 +1358,16 @@ final class CollSer implements Serializable {
|
|||||||
static final int IMM_LIST = 1;
|
static final int IMM_LIST = 1;
|
||||||
static final int IMM_SET = 2;
|
static final int IMM_SET = 2;
|
||||||
static final int IMM_MAP = 3;
|
static final int IMM_MAP = 3;
|
||||||
|
static final int IMM_LIST_NULLS = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates the type of collection that is serialized.
|
* Indicates the type of collection that is serialized.
|
||||||
* The low order 8 bits have the value 1 for an immutable
|
* The low order 8 bits have the value 1 for an immutable
|
||||||
* {@code List}, 2 for an immutable {@code Set}, and 3 for
|
* {@code List}, 2 for an immutable {@code Set}, 3 for
|
||||||
* an immutable {@code Map}. Any other value causes an
|
* an immutable {@code Map}, and 4 for an immutable
|
||||||
|
* {@code List} that allows null elements.
|
||||||
|
*
|
||||||
|
* Any other value causes an
|
||||||
* {@link InvalidObjectException} to be thrown. The high
|
* {@link InvalidObjectException} to be thrown. The high
|
||||||
* order 24 bits are zero when an instance is serialized,
|
* order 24 bits are zero when an instance is serialized,
|
||||||
* and they are ignored when an instance is deserialized.
|
* and they are ignored when an instance is deserialized.
|
||||||
@ -1352,6 +1486,9 @@ final class CollSer implements Serializable {
|
|||||||
switch (tag & 0xff) {
|
switch (tag & 0xff) {
|
||||||
case IMM_LIST:
|
case IMM_LIST:
|
||||||
return List.of(array);
|
return List.of(array);
|
||||||
|
case IMM_LIST_NULLS:
|
||||||
|
return ImmutableCollections.listFromTrustedArrayNullsAllowed(
|
||||||
|
Arrays.copyOf(array, array.length, Object[].class));
|
||||||
case IMM_SET:
|
case IMM_SET:
|
||||||
return Set.of(array);
|
return Set.of(array);
|
||||||
case IMM_MAP:
|
case IMM_MAP:
|
||||||
|
@ -842,7 +842,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3) {
|
static <E> List<E> of(E e1, E e2, E e3) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3);
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -861,7 +861,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4);
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -881,7 +881,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5);
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -902,7 +902,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6);
|
e6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -925,7 +925,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7);
|
e6, e7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,7 +949,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7, e8);
|
e6, e7, e8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,7 +974,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7, e8, e9);
|
e6, e7, e8, e9);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,7 +1000,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
|
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
|
||||||
return ImmutableCollections.ListN.fromTrustedArray(e1, e2, e3, e4, e5,
|
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
|
||||||
e6, e7, e8, e9, e10);
|
e6, e7, e8, e9, e10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1042,7 +1042,7 @@ public interface List<E> extends Collection<E> {
|
|||||||
case 2:
|
case 2:
|
||||||
return new ImmutableCollections.List12<>(elements[0], elements[1]);
|
return new ImmutableCollections.List12<>(elements[0], elements[1]);
|
||||||
default:
|
default:
|
||||||
return ImmutableCollections.ListN.fromArray(elements);
|
return ImmutableCollections.listFromArray(elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ package java.util.stream;
|
|||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
@ -44,6 +45,7 @@ import java.util.function.Supplier;
|
|||||||
import java.util.function.ToDoubleFunction;
|
import java.util.function.ToDoubleFunction;
|
||||||
import java.util.function.ToIntFunction;
|
import java.util.function.ToIntFunction;
|
||||||
import java.util.function.ToLongFunction;
|
import java.util.function.ToLongFunction;
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for an intermediate pipeline stage or pipeline source
|
* Abstract base class for an intermediate pipeline stage or pipeline source
|
||||||
@ -620,6 +622,11 @@ abstract class ReferencePipeline<P_IN, P_OUT>
|
|||||||
return toArray(Object[]::new);
|
return toArray(Object[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<P_OUT> toList() {
|
||||||
|
return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArrayNullsAllowed(this.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean anyMatch(Predicate<? super P_OUT> predicate) {
|
public final boolean anyMatch(Predicate<? super P_OUT> predicate) {
|
||||||
return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ANY));
|
return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ANY));
|
||||||
|
@ -1162,6 +1162,40 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> {
|
|||||||
*/
|
*/
|
||||||
<R, A> R collect(Collector<? super T, A, R> collector);
|
<R, A> R collect(Collector<? super T, A, R> collector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates the elements of this stream into a {@code List}. The elements in
|
||||||
|
* the list will be in this stream's encounter order, if one exists. The returned List
|
||||||
|
* is unmodifiable; calls to any mutator method will always cause
|
||||||
|
* {@code UnsupportedOperationException} to be thrown. There are no
|
||||||
|
* guarantees on the implementation type or serializability of the returned List.
|
||||||
|
*
|
||||||
|
* <p>The returned instance may be <a href="../lang/doc-files/ValueBased.html">value-based</a>.
|
||||||
|
* Callers should make no assumptions about the identity of the returned instances.
|
||||||
|
* Identity-sensitive operations on these instances (reference equality ({@code ==}),
|
||||||
|
* identity hash code, and synchronization) are unreliable and should be avoided.
|
||||||
|
*
|
||||||
|
* <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
|
||||||
|
*
|
||||||
|
* @apiNote If more control over the returned object is required, use
|
||||||
|
* {@link Collectors#toCollection(Supplier)}.
|
||||||
|
*
|
||||||
|
* @implSpec The implementation in this interface returns a List produced as if by the following:
|
||||||
|
* <pre>{@code
|
||||||
|
* Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @implNote Most instances of Stream will override this method and provide an implementation
|
||||||
|
* that is highly optimized compared to the implementation in this interface.
|
||||||
|
*
|
||||||
|
* @return a List containing the stream elements
|
||||||
|
*
|
||||||
|
* @since 16
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
default List<T> toList() {
|
||||||
|
return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the minimum element of this stream according to the provided
|
* Returns the minimum element of this stream according to the provided
|
||||||
* {@code Comparator}. This is a special case of a
|
* {@code Comparator}. This is a special case of a
|
||||||
|
@ -29,4 +29,5 @@ import java.util.List;
|
|||||||
|
|
||||||
public interface JavaUtilCollectionAccess {
|
public interface JavaUtilCollectionAccess {
|
||||||
<E> List<E> listFromTrustedArray(Object[] array);
|
<E> List<E> listFromTrustedArray(Object[] array);
|
||||||
|
<E> List<E> listFromTrustedArrayNullsAllowed(Object[] array);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2020, 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
|
||||||
@ -229,7 +229,16 @@ public class MOAT {
|
|||||||
List.of(1, 2, 3, 4, 5, 6, 7, 8),
|
List.of(1, 2, 3, 4, 5, 6, 7, 8),
|
||||||
List.of(1, 2, 3, 4, 5, 6, 7, 8, 9),
|
List.of(1, 2, 3, 4, 5, 6, 7, 8, 9),
|
||||||
List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
|
List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
|
||||||
List.of(integerArray))) {
|
List.of(integerArray),
|
||||||
|
Stream.<Integer>empty().toList(),
|
||||||
|
Stream.of(1).toList(),
|
||||||
|
Stream.of(1, 2).toList(),
|
||||||
|
Stream.of(1, 2, 3).toList(),
|
||||||
|
Stream.of(1, 2, 3, 4).toList(),
|
||||||
|
Stream.of((Integer)null).toList(),
|
||||||
|
Stream.of(1, null).toList(),
|
||||||
|
Stream.of(1, null, 3).toList(),
|
||||||
|
Stream.of(1, null, 3, 4).toList())) {
|
||||||
testCollection(list);
|
testCollection(list);
|
||||||
testImmutableList(list);
|
testImmutableList(list);
|
||||||
testListMutatorsAlwaysThrow(list);
|
testListMutatorsAlwaysThrow(list);
|
||||||
@ -1096,6 +1105,15 @@ public class MOAT {
|
|||||||
catch (UnsupportedOperationException ignored) {/* OK */}
|
catch (UnsupportedOperationException ignored) {/* OK */}
|
||||||
catch (Throwable t) { unexpected(t); }
|
catch (Throwable t) { unexpected(t); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hashCode = 1;
|
||||||
|
for (Integer i : l)
|
||||||
|
hashCode = 31 * hashCode + (i == null ? 0 : i.hashCode());
|
||||||
|
check(l.hashCode() == hashCode);
|
||||||
|
|
||||||
|
var t = new ArrayList<>(l);
|
||||||
|
check(t.equals(l));
|
||||||
|
check(l.equals(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testCollection(Collection<Integer> c) {
|
private static void testCollection(Collection<Integer> c) {
|
||||||
@ -1131,6 +1149,13 @@ public class MOAT {
|
|||||||
if (c instanceof List)
|
if (c instanceof List)
|
||||||
testList((List<Integer>)c);
|
testList((List<Integer>)c);
|
||||||
|
|
||||||
|
if (c instanceof Set) {
|
||||||
|
int hashCode = 0;
|
||||||
|
for (Integer i : c)
|
||||||
|
hashCode = hashCode + (i == null ? 0 : i.hashCode());
|
||||||
|
check(c.hashCode() == hashCode);
|
||||||
|
}
|
||||||
|
|
||||||
check(supportsRemove(c));
|
check(supportsRemove(c));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1230,6 +1255,15 @@ public class MOAT {
|
|||||||
private static void testMap(Map<Integer,Integer> m) {
|
private static void testMap(Map<Integer,Integer> m) {
|
||||||
System.out.println("\n==> " + m.getClass().getName());
|
System.out.println("\n==> " + m.getClass().getName());
|
||||||
|
|
||||||
|
int hashCode = 0;
|
||||||
|
for (var e : m.entrySet()) {
|
||||||
|
int entryHash = (e.getKey() == null ? 0 : e.getKey().hashCode()) ^
|
||||||
|
(e.getValue() == null ? 0 : e.getValue().hashCode());
|
||||||
|
check(e.hashCode() == entryHash);
|
||||||
|
hashCode += entryHash;
|
||||||
|
}
|
||||||
|
check(m.hashCode() == hashCode);
|
||||||
|
|
||||||
if (m instanceof ConcurrentMap)
|
if (m instanceof ConcurrentMap)
|
||||||
testConcurrentMap((ConcurrentMap<Integer,Integer>) m);
|
testConcurrentMap((ConcurrentMap<Integer,Integer>) m);
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import java.util.Collections;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.testng.annotations.DataProvider;
|
import org.testng.annotations.DataProvider;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
@ -359,6 +360,19 @@ public class ListFactories {
|
|||||||
List<Integer> list = List.copyOf(Arrays.asList(1, null, 3));
|
List<Integer> list = List.copyOf(Arrays.asList(1, null, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions=NullPointerException.class)
|
||||||
|
public void copyOfRejectsNullElements2() {
|
||||||
|
List<String> list = List.copyOf(Stream.of("a", null, "c").toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void copyOfCopiesNullAllowingList() {
|
||||||
|
List<String> orig = Stream.of("a", "b", "c").toList();
|
||||||
|
List<String> copy = List.copyOf(orig);
|
||||||
|
|
||||||
|
assertNotSame(orig, copy);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void iteratorShouldNotBeListIterator() {
|
public void iteratorShouldNotBeListIterator() {
|
||||||
List<Integer> list = List.of(1, 2, 3, 4, 5);
|
List<Integer> list = List.of(1, 2, 3, 4, 5);
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, 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.
|
||||||
|
*/
|
||||||
|
package org.openjdk.tests.java.util.stream;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.*;
|
||||||
|
|
||||||
|
import static java.util.stream.LambdaTestHelpers.*;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertFalse;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToListOpTest
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public class ToListOpTest extends OpTestCase {
|
||||||
|
|
||||||
|
public void testToList() {
|
||||||
|
assertCountSum(countTo(0).stream().toList(), 0, 0);
|
||||||
|
assertCountSum(countTo(10).stream().toList(), 10, 55);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUnmodifiable(List<Integer> list) {
|
||||||
|
try {
|
||||||
|
list.add(Integer.MIN_VALUE);
|
||||||
|
fail("List.add did not throw UnsupportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException ignore) { }
|
||||||
|
|
||||||
|
if (list.size() > 0) {
|
||||||
|
try {
|
||||||
|
list.set(0, Integer.MAX_VALUE);
|
||||||
|
fail("List.set did not throw UnsupportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException ignore) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
|
||||||
|
public void testOps(String name, TestData.OfRef<Integer> data) {
|
||||||
|
List<Integer> objects = exerciseTerminalOps(data, s -> s.toList());
|
||||||
|
checkUnmodifiable(objects);
|
||||||
|
assertFalse(objects.contains(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "withNull:StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
|
||||||
|
public void testOpsWithNull(String name, TestData.OfRef<Integer> data) {
|
||||||
|
List<Integer> objects = exerciseTerminalOps(data, s -> s.toList());
|
||||||
|
checkUnmodifiable(objects);
|
||||||
|
assertTrue(objects.contains(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
|
||||||
|
public void testDefaultOps(String name, TestData.OfRef<Integer> data) {
|
||||||
|
List<Integer> objects = exerciseTerminalOps(data, s -> DefaultMethodStreams.delegateTo(s).toList());
|
||||||
|
checkUnmodifiable(objects);
|
||||||
|
assertFalse(objects.contains(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "withNull:StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
|
||||||
|
public void testDefaultOpsWithNull(String name, TestData.OfRef<Integer> data) {
|
||||||
|
List<Integer> objects = exerciseTerminalOps(data, s -> DefaultMethodStreams.delegateTo(s).toList());
|
||||||
|
checkUnmodifiable(objects);
|
||||||
|
assertTrue(objects.contains(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user