String[] stringArray = streamString.toArray(size -> new String[size]);
How it takes the size as stream's size automatically?
String[] stringArray = streamString.toArray(size -> new String[size]);
How it takes the size as stream's size automatically?
The Stream
API is formed around Spliterator
which is an advanced form of iterators. These can report certain characteristics, allowing optimizations of the operations a Stream
will apply. They may also report the expected number of elements, either estimated or exact. A Spliterator
will report a SIZED
characteristic if it knows the number of elements in advance.
You can test which knowledge about its elements a Stream
has, given the encapsulated operations, using the following method:
public static <T> Stream<T> printProperties(String op, Stream<T> s) {
System.out.print("characteristics after "+op+": ");
Spliterator<T> sp=s.spliterator();
int characteristics=sp.characteristics();
if(characteristics==0) System.out.println("0");
else {
String str;
for(;;) {
int flag=Integer.highestOneBit(characteristics);
switch(flag) {
case ORDERED: str="ORDERED"; break;
case DISTINCT: str="DISTINCT"; break;
case SORTED: str="SORTED"; break;
case SIZED: str="SIZED"; break;
case NONNULL: str="NONNULL"; break;
case IMMUTABLE: str="IMMUTABLE"; break;
case CONCURRENT: str="CONCURRENT"; break;
case SUBSIZED: str="SUBSIZED"; break;
default: str=String.format("0x%X", flag);
}
characteristics-=flag;
if(characteristics==0) break;
System.out.append(str).append('|');
}
System.out.println(str);
}
return StreamSupport.stream(sp, s.isParallel());
}
You can use it to learn how certain operations influence the knowledge about the elements. E.g., when you use this method with the following test program:
Stream<Object> stream;
stream=printProperties("received from TreeSet", new TreeSet<>().stream() );
stream=printProperties("applying map", stream.map(x->x) );
stream=printProperties("applying distinct", stream.distinct() );
stream=printProperties("filtering", stream.filter(x->true) );
stream=printProperties("applying sort", stream.sorted() );
stream=printProperties("requesting unordered", stream.unordered() );
System.out.println();
stream=printProperties("received from varargs array", Stream.of("foo", "bar") );
stream=printProperties("applying sort", stream.sorted() );
stream=printProperties("applying map", stream.map(x->x) );
stream=printProperties("applying distinct", stream.distinct() );
stream=printProperties("requesting unordered", stream.unordered() );
System.out.println();
printProperties("ConcurrentHashMap.keySet().stream()",
new ConcurrentHashMap<>().keySet().stream() );
it will print:
characteristics after received from TreeSet: SIZED|ORDERED|SORTED|DISTINCT
characteristics after applying map: SIZED|ORDERED
characteristics after applying distinct: ORDERED|DISTINCT
characteristics after filtering: ORDERED|DISTINCT
characteristics after applying sort: ORDERED|SORTED|DISTINCT
characteristics after requesting unordered: SORTED|DISTINCT
characteristics after received from varargs array: SUBSIZED|IMMUTABLE|SIZED|ORDERED
characteristics after applying sort: SUBSIZED|SIZED|ORDERED|SORTED
characteristics after applying map: SUBSIZED|SIZED|ORDERED
characteristics after applying distinct: ORDERED|DISTINCT
characteristics after requesting unordered: DISTINCT
characteristics after ConcurrentHashMap.keySet().stream(): CONCURRENT|NONNULL|DISTINCT
As JB Nizet explained, if a stream does not know the size in advance, it has to use a strategy for collecting the elements which might include reallocating arrays. As the documentation says:
… using the provided generator function to allocate the returned array, as well as any additional arrays that might be required for a partitioned execution or for resizing.
size -> new String[size]
is a lambda, which is an instance of IntFunction<A[]> generator
, as the signature of the method is
<A> A[] toArray(IntFunction<A[]> generator)
So this line creates an instance of IntFunction, and passes it as argument to the stream. The stream is the one which calls the function (i.e. invokes the method apply(int)), and the stream is thus the one passing the size as argument. And the stream knows its own size.