2014-10-30 2 views
7

Während ich an einem Projekt mit den neuen Streams von Java 8 arbeitete, bemerkte ich, dass, wenn ich Stream#toArray() in einem Stream anrief, es Object[] anstelle von T[] zurückgab. Überrascht wie ich war, fing ich an, in den Quellcode von Java 8 zu graben und konnte keinen Grund finden, warum sie Object[] toArray(); nicht als T[] toArray(); implementiert haben. Gibt es Gründe dafür, oder ist es nur eine (un) Konsistenz?Warum geben die neuen Java 8-Streams ein Object Array anArray-Aufrufe zurück?

EDIT 1: Ich bemerkte in den Antworten, dass viele Leute sagten, dass dies nicht möglich wäre, aber dieses Code-Snippet kompiliert und das erwartete Ergebnis zurückgibt?

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())); 
    } 

} 
+2

Wie würde es 'R' wissen? Wenn bestimmte Typen zurückgegeben werden sollen, übergeben Sie einen Generator an die Methode. Führen Sie beispielsweise für ein String-Array die folgenden Schritte aus: 'streamString.toArray (String [] :: new)' – meskobalazs

+0

'R' ist der Typparameter der Stream-Schnittstelle. Ich habe "R" in meiner Frage verwendet, aber es sollte "T" sein. Wird das aktualisieren. – Martijn

+0

@meskobalazs Aber, schlimmstenfalls Szenario, könnten Sie es auf den gewünschten Typ umwandeln. Warum haben sie sich dafür entschieden, anstelle des eingegebenen Pfades den Platzhalterpfad zu wählen? Ich habe manchmal das Gefühl, dass es dem Programmierer nicht bekannt ist, welchen Typ-Stream er hat, um den besten Code zu erstellen. Und der Strom ist immer noch derjenige, der genau weiß, welchen Typ er enthält. – Martijn

Antwort

8

Dies ist das gleiche Problem, das List#toArray() hat. Type Erase verhindert, dass wir den Array-Typ kennen, den wir zurückgeben sollten. Betrachten Sie die folgende

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 

Ein Object[] ist nicht ein String[] und daher nicht auf eine zugeordnet werden können, und zwar unabhängig von der Besetzung. Dieselbe Idee gilt für Stream und List. Verwenden Sie die überladene Methode toArray(..).

+0

Sehen Sie sich meinen Schnitt an. Können Sie erklären, warum das funktioniert? – Martijn

+1

Ihr Code ist in Ordnung, weil 'items' eigentlich ein' Integer [] 'ist, kein' Object [] ', das in etwas anderes umgewandelt wurde. –

+2

@MartijnRiemers In Ihrem Beispiel geben Sie das Array zurück, das Sie bereits erstellt haben (für das Sie den Typ kennen). Ein "Stream" (oder eine "Liste") ist nicht garantiert, von einem Array unterstützt zu werden. Es kann auf andere Weise konstruiert werden. Dies bedeutet, dass ein ** neues ** Array erstellt werden muss, aber welcher Typ nicht bekannt ist. –

5

Über den Grund, warum toArray()Object[] zurückgibt: es ist wegen Typ löschen. Generische Typen verlieren ihre Typparameter zur Laufzeit, so dass Stream<Integer>, Stream<String> und Stream dieselben Typen werden. Daher gibt es keine Möglichkeit, den Komponententyp des zu erstellenden Arrays zu bestimmen. Eigentlich könnte man Arten von Array-Elementen mit Reflektion analysieren und dann versuchen, ihre least upper bound zu finden, aber das ist zu kompliziert und langsam.

Es gibt einen Weg, R[] Array mit überladener toArray(IntFunction<A[]> generator) Methode zu erhalten. Diese Methode gibt dem Aufrufer die Möglichkeit, den Typ des Arrays zu wählen. Sehen Sie sich diese SO-Frage für Codebeispiele an: How to Convert a Java 8 Stream to an Array?.

18

Versuchen:

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

Die No-arg toArray() -Methode wird nur ein Objekt zurückgeben [], aber wenn Sie ein Array Fabrik übergeben (die als Array-Konstruktor Referenz bequem dargestellt werden kann), können Sie kann bekommen, was auch immer (kompatibel) Sie mögen.

+0

Obwohl dies die Frage von OP nicht direkt anspricht, ist dies die Antwort, nach der ich gesucht habe. –

Verwandte Themen