2009-11-04 15 views
196

Se ho una collezione, come Collection<String> strs, come posso ottenere il primo oggetto? Potrei semplicemente chiamare uno Iterator, prendere il suo primo next(), quindi buttare via lo Iterator. C'è un modo meno dispendioso per farlo?Java: Ottieni il primo elemento da una collezione

+1

Ovviamente potrebbe esserci un modo migliore per accedere al primo elemento se si conosce la classe del contenitore di implementazione ... – Rooke

+0

Generalizzazione per qualsiasi indice: http://stackoverflow.com/questions/1047957/best-way-to- get-value-from-collection-by-index –

+1

Sembra che tu abbia bisogno di Queue.peek() – Johannes

risposta

101

Iterables.get(yourC, indexYouWant)

Perché in realtà, se si sta utilizzando Collezioni, si dovrebbe utilizzare Google Collezioni .

+6

Che fa la stessa cosa, controlla solo se è una lista prima, e ottiene per indice se lo è. Ha anche del codice per provare a fallire più velocemente su una Collection effettiva (cioè se l'indice è troppo grande cerca di capirlo senza fare iterazioni per tutta la faccenda e lanciare l'eccezione alla fine). – Yishai

+1

Onestamente, per quanto riguarda le prestazioni potrebbe essere leggermente più lento di c.iterator(). Next() - ma il codice è molto più chiaro e più semplice da modificare. – Carl

+2

Sicuramente sono d'accordo che è più pulito, ma l'OP era uno spreco, ma suppongo che, poiché la tua risposta è stata accettata, è ciò che si desiderava. – Yishai

36

Non esiste una cosa come "primo" elemento in un Collection perché è .. beh semplicemente una raccolta.

Dal metodo del dottore Java Collection.iterator():

Non ci sono garanzie che regolano l'ordine in cui vengono restituiti gli elementi ...

così non si può.

Se si utilizza un altro interfaccia come Lista, è possibile effettuare le seguenti operazioni:

String first = strs.get(0); 

ma direttamente da una raccolta questo non è possibile.

+9

Non credo che 'get (int n)' sia definito per 'Collection' –

+1

Hai ragione, mi manca quel punto. Ho aggiornato la risposta. Non puoi! (a meno che la raccolta non sia implementata da una classe di underlaying che consente di fornire la garanzia) – OscarRyz

+0

get non è nell'interfaccia Collection –

-2

Si potrebbe fare questo:

String strz[] = strs.toArray(String[strs.size()]); 
String theFirstOne = strz[0]; 

Javadoc per Collection ha pronunciato la seguente WRT ordinamento avvertimento degli elementi dell'array:

Se questa collezione rende alcuna garanzia su cosa ordinare la sua gli elementi vengono restituiti dal relativo iteratore, questo metodo deve restituire gli elementi nello stesso ordine.

+2

Questo crea un nuovo array di String, molto più costoso della creazione di un iteratore. –

+0

Sì, ci ho pensato dopo aver postato questo. Indipendentemente dal metodo utilizzato, l'ordine dipende dall'implementazione sottostante della Collezione. "Primo" diventa quindi un termine relativo. Tuttavia, il modo iteratore() per farlo è probabilmente migliore nella maggior parte dei casi. –

+4

-1 perché questo è * mai * migliore di iterator(). Next(). –

313

Sembra che è il modo migliore per farlo:

String first = strs.iterator().next(); 

Grande domanda ... In un primo momento, sembra una svista per l'interfaccia Collection.

Si noti che "prima" non restituirà sempre la prima cosa che si inserisce nella raccolta e potrebbe avere senso solo per le raccolte ordinate. Forse è per questo che non c'è una chiamata get(item), dal momento che l'ordine non è necessariamente conservato.

Mentre potrebbe sembrare un po 'dispendioso, potrebbe non essere così male come pensi. Lo Iterator contiene solo informazioni di indicizzazione nella raccolta, non una copia di solito dell'intera raccolta. Invocare questo metodo crea un'istanza dell'oggetto Iterator, ma quello è davvero l'unico sovraccarico (non come copiare tutti gli elementi).

Ad esempio, guardando il tipo restituito dal metodo ArrayList<String>.iterator(), vediamo che è ArrayList::Itr. Questa è una classe interna che accede direttamente agli elementi della lista, anziché copiarli.

+9

strano che questa non è la risposta accettata –

+2

È importante notare che questo "trucco" funziona solo quando la raccolta ha effettivamente contenuti. Se è vuoto, l'iteratore potrebbe restituire un errore, in cui si deve controllare preventivamente la dimensione della raccolta. – spaceemotion

+5

Questa dovrebbe essere la risposta corretta. Non capisco perché la risposta sia sempre "usa un'altra libreria!" . – Kuzeko

0

Se si sa che la raccolta è una coda, è possibile trasmettere la raccolta a una coda e ottenerla facilmente.

Ci sono diverse strutture che è possibile utilizzare per ottenere l'ordine, ma è necessario eseguire il cast su di esso.

+0

Sono d'accordo, se non vuoi iterare, non usare la raccolta. Utilizza invece un'altra interfaccia più specifica. –

+1

Mi chiedo però ... diciamo che i dati reali sottostanti sono un SortedSet, quindi l'ordine ha senso, ma hai solo una vista Raccolta di esso (per una ragione non sciocca, diciamo); se lanci la collezione in una lista, in coda, ecc. e provi a ottenere/poll/etc, si verifica un disastro? Allo stesso modo, se la struttura sottostante è una lista, così via, così via. – Carl

+0

@Cal - Non l'ho provato, ma se lanci una raccolta in un tipo molto diverso da quello originario dovresti ricevere un errore, ma non l'ho provato, quindi potrei sbagliarmi. –

3

Sembra tua collezione vuole essere List-like, quindi consiglio:

List<String> myList = new ArrayList<String>(); 
... 
String first = myList.get(0); 
45

in Java 8:

Optional<String> firstElement = collection.stream().findFirst(); 

Per le versioni precedenti di Java, v'è un metodo getFirst in Guava Iterables:

Iterables.getFirst(iterable, defaultValue) 
+3

La soluzione java 8 è particolarmente utile, poiché gestisce il caso in cui la raccolta è vuota con garbo. – SpaceTrucker

+2

Non buono. Aggiungi overhead di stream() per ottenere un get (0) solo perché sei pigro per scrivere 4 righe di codice. if (! CollectionUtils.isEmpty (productList)) { \t \t return Optional.of (productList.get (0)); } reso facoltativo.vuoto(); –

+1

Ottima e semplice soluzione. Grazie. –

0

E 'del tutto dipende da quale applicazione è stata utilizzata, se LinkedList arraylist o altre implementazioni del set.

se è impostato allora si può ottenere direttamente il primo elemento, la loro può essere anello di trucco sulla raccolta, creare una variabile di valore di 1 e ottenere valore quando il valore flag è 1, dopo che rompere quel ciclo.

se è l'implementazione della lista, è facile definendo il numero di indice.

2

In Java 8 si dispone di alcuni molti operatori di utilizzare, per esempio limite

 /** 
* Operator that limit the total number of items emitted through the pipeline 
* Shall print 
* [1] 
* @throws InterruptedException 
*/ 
@Test 
public void limitStream() throws InterruptedException { 
    List<Integer> list = Arrays.asList(1, 2, 3, 1, 4, 2, 3) 
           .stream() 
           .limit(1) 
           .collect(toList()); 
    System.out.println(list); 
} 
+0

@Vitalii La risposta di Fedorenko http://stackoverflow.com/a/18165855/1562662 è migliore. –

2

Si può fare un casting. Per esempio, se esiste un metodo con questa definizione, e si sa che questo metodo restituisce un elenco:

Collection<String> getStrings(); 

E dopo invocarlo, è necessario il primo elemento, si può fare in questo modo:

List<String> listString = (List) getStrings(); 
String firstElement = (listString.isEmpty() ? null : listString.get(0)); 
Problemi correlati