简体   繁体   中英

Why do the new Java 8 streams return an Object Array on toArray calls?

Whilst I was working on a project involving Java 8's new streams, I noticed that when I called Stream#toArray() on a stream, it return an Object[] instead of a T[] . Surprised as I was, I started digging into the source code of Java 8 and couldn't find any reason why they didn't implement Object[] toArray(); as T[] toArray(); . Is there any reasoning behind this, or is it just an (in)consistency?

EDIT 1: I noticed in the answers that a lot of people said this would not be possible, but this code snippet compiles and return the expected result?

import java.util.Arrays;

public class Test<R> {

    private Object[] items;

    public Test(R[] items) {
        this.items = items;
    }

    public R[] toArray() {
        return (R[]) items;
    }

    public static void main(String[] args) {
        Test<Integer> integerTest = new Test<>(new Integer[]{
            1, 2, 3, 4
        });

        System.out.println(Arrays.toString(integerTest.toArray()));
    }

}

Try:

String[] = IntStream.range(0, 10).mapToObj(Object::toString).toArray(String[]::new);

The no-arg toArray() method will just return an Object[], but if you pass an array factory (which can be conveniently represented as an array constructor reference), you can get whatever (compatible) type you like.

This is the same problem that List#toArray() has. Type erasure prevents us from knowing the type of array we should return. Consider the following

class Custom<T> {
    private T t;
    public Custom (T t) {this.t = t;}
    public T[] toArray() {return (T[]) new Object[] {t};} // if not Object[], what type?
}

Custom<String> custom = new Custom("hey");
String[] arr = custom.toArray(); // fails

An Object[] is not a String[] and therefore cannot be assigned to one, regardless of the cast. The same idea applies to Stream and List . Use the overloaded toArray(..) method.

About the reason why toArray() returns Object[] : it is because of type erasure. Generic types lose their type parameters at runtime so Stream<Integer> , Stream<String> and Stream become the same types. Therefore there is no way to determine component type of array to create. Actually, one could analyze types of array's elements using reflection and then try to find their least upper bound , but this is too complicated and slow.

There is a way to get R[] array by using overloaded toArray(IntFunction<A[]> generator) method. This method gives the caller an opportunity to choose type of the array. See this SO question for code examples: How to Convert a Java 8 Stream to an Array? .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM