2014-10-30 10 views
7

Mentre stavo lavorando a un progetto che coinvolge i nuovi stream di Java 8, ho notato che quando ho chiamato Stream#toArray() su uno stream, restituisce uno Object[] anziché uno T[]. Sorpreso com'ero, ho iniziato a scavare nel codice sorgente di Java 8 e non ho trovato alcun motivo per cui non implementassero Object[] toArray(); come T[] toArray();. C'è qualche ragionamento dietro questo, o è solo una (in) coerenza?Perché i nuovi stream Java 8 restituiscono una matrice di oggetti sulle chiamate toArray?

MODIFICA 1: Ho notato nelle risposte che molte persone hanno affermato che ciò non sarebbe possibile, ma questo frammento di codice viene compilato e restituisce il risultato previsto?

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

Come farebbe a sapere "R"? Se vuoi che vengano restituiti tipi specifici, passa un generatore al metodo. Ad esempio per un array di stringhe, effettuare quanto segue: 'streamString.toArray (String [] :: new)' – meskobalazs

+0

'R' è il parametro type dell'interfaccia Stream. Ho usato 'R' nella mia domanda, ma dovrebbe essere' T'. Aggiornerà quello – Martijn

+0

@meskobalazs Ma ancora, nel peggiore dei casi, potresti lanciarlo sul tipo desiderato. Perché hanno scelto di percorrere il percorso con caratteri jolly anziché il percorso digitato? A volte mi rendo conto che non è noto al programmatore che tipo di stream abbia dovuto occuparsene, non è il miglior codice. E il flusso è ancora quello che sa esattamente che tipo contiene. – Martijn

risposta

8

Questo è lo stesso problema che ha lo List#toArray(). La cancellazione dei caratteri ci impedisce di conoscere il tipo di array che dovremmo restituire. Si consideri il seguente

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 

Un Object[] è non un String[] e quindi non possono essere assegnati a uno, a prescindere dal cast. La stessa idea si applica a Stream e List. Utilizzare il metodo sovraccarico toArray(..).

+0

Guarda la mia modifica. Potresti spiegare perché funziona così? – Martijn

+1

Il tuo codice va bene perché 'items' è in realtà un' Integer [] ', non un' Object [] 'che è stato lanciato su qualcos'altro. –

+2

@MartijnRiemers Nel tuo esempio, stai restituendo l'array che hai già creato (di cui conosci il tipo). Non è garantito che un 'Stream' (o un' List') sia supportato da un array. Può essere costruito con qualsiasi altro mezzo. Ciò significa che deve essere creato un ** nuovo ** array, ma non possiamo sapere quale tipo. –

5

Circa il motivo per cui toArray() restituisce Object[]: è a causa della cancellazione di tipo. I tipi generici perdono i parametri di tipo durante il runtime, quindi Stream<Integer>, Stream<String> e Stream diventano gli stessi tipi. Pertanto non è possibile determinare il tipo di componente dell'array da creare. In realtà, si possono analizzare i tipi di elementi dell'array usando la reflection e quindi provare a trovare il loro least upper bound, ma questo è troppo complicato e lento.

C'è un modo per ottenere l'array R[] utilizzando il metodo sovraccarico toArray(IntFunction<A[]> generator). Questo metodo offre al chiamante l'opportunità di scegliere il tipo dell'array. Vedere questa domanda SO per gli esempi di codice: How to Convert a Java 8 Stream to an Array?.

18

Prova:

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

Il metodo no-arg toArray() sarà solo restituire un oggetto [], ma se si passa una fabbrica array (che può essere rappresentato comodamente come un riferimento di costruzione Array), è puoi ottenere qualsiasi tipo (compatibile) che ti piace.

+0

Anche se questo non affronta direttamente la domanda dell'OP, questa è la risposta che stavo cercando. –