Java: obtener el primer elemento de una colección


277

Si tengo una colección, como Collection<String> strs, ¿cómo puedo obtener el primer artículo? Podría llamar a un Iterator, tomar el primero next()y luego tirarlo Iterator. ¿Hay una manera menos derrochadora de hacerlo?


1
Por supuesto que puede haber una mejor manera de acceder al primer elemento si conoce la clase de contenedor implementar ...
Rooke


1
Parece que necesitas Queue.peek ()
Johannes

Respuestas:


131

Iterables.get (yourC, indexYouWant)

Porque realmente, si estás usando Colecciones, deberías estar usando Google Collections.


77
Eso hace lo mismo, solo comprueba si es una lista primero y obtiene por índice si lo es. También tiene algo de código para intentar fallar más rápido en una Colección real (es decir, si el índice es demasiado grande, trata de resolverlo sin iterar todo y arrojar la excepción al final).
Yishai el

1
Honestamente, en cuanto al rendimiento, puede ser un poco más lento que c.iterator (). Next (), pero el código es mucho más claro y sencillo de modificar.
Carl el

2
Ciertamente estoy de acuerdo en que es más limpio, pero el OP fue un desperdicio, pero supongo que desde que su respuesta fue aceptada, eso es lo que se deseaba.
Yishai el

8
Para aquellos (todavía) que llegan aquí: creo que la respuesta de jheddings es probablemente la mejor respuesta "hazlo", aunque preferiría @ DonaldRaab (en la última página) para los casos en los que ya estoy usando la biblioteca GC. Mi respuesta es realmente para el caso en que uno quiera escribir con flexibilidad para más adelante (por ejemplo, si uno decide que el segundo elemento es el nuevo atractivo).
Carl

44
A veces solo estás usando código que usa Colecciones, por lo que no hay mucho que hacer.
erickrf

436

Parece que esa es la mejor manera de hacerlo:

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

Gran pregunta ... Al principio, parece un descuido de la Collectioninterfaz.

Tenga en cuenta que "primero" no siempre devolverá lo primero que ponga en la colección, y solo puede tener sentido para las colecciones ordenadas. Quizás es por eso que no hay una get(item)llamada, ya que el orden no se conserva necesariamente.

Si bien puede parecer un poco derrochador, puede que no sea tan malo como crees. El Iteratorrealmente solo contiene información de indexación en la colección, generalmente no es una copia de toda la colección. Invocar este método crea una instancia del Iteratorobjeto, pero esa es realmente la única sobrecarga (no como copiar todos los elementos).

Por ejemplo, al observar el tipo devuelto por el ArrayList<String>.iterator()método, vemos que es así ArrayList::Itr. Esta es una clase interna que solo accede a los elementos de la lista directamente, en lugar de copiarlos.

Solo asegúrese de verificar el retorno de, iterator()ya que puede estar vacío o nulldependiendo de la implementación.


3
Es importante tener en cuenta que este "truco" solo funciona cuando la colección realmente tiene contenido. Si está vacío, el iterador puede devolver un error, en el que hay que verificar el tamaño de la colección de antemano.
spaceemotion

20
Esta debería ser la respuesta correcta. No entiendo por qué la respuesta siempre es "¡usa otra biblioteca!" .
Kuzeko

¿Qué tal el segundo elemento de la colección? ¿Por qué primero-> next () no funciona? ¿Qué tengo que hacer? ¡Gracias!
pb772

no es lo suficientemente seguro, no se garantiza que la colección siempre apunte al primer elemento.
Siguiente desarrollador

84

En java 8:

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

Para versiones anteriores de Java, hay un método en GetFirst guayaba iterables :

Iterables.getFirst(iterable, defaultValue)

66
La solución java 8 es especialmente útil, ya que maneja el caso donde la colección está vacía con gracia.
SpaceTrucker

44
No está bien. Agregas sobrecarga de stream () para obtener un get (0) solo porque eres flojo para escribir 4 líneas de código. if (! CollectionUtils.isEmpty (productList)) {return Opcional.of (productList.get (0)); } return Opcional.empty ();
RS

No tengo getFirstmétodo disponible. Hay gety getLastmétodos
user1209216

44
@RS y ¿qué sucede si no puede llamar a productList.get (0), ya que es una Colección ...? (Según la pregunta de OP)
Denham Coote

40

No hay tal cosa como el "primer" elemento en un Collectionporque es ... bueno, simplemente una colección.

Del método Collection.iterator () de Java doc :

No hay garantías sobre el orden en que se devuelven los elementos ...

Entonces no puedes.

Si usa otra interfaz como Lista , puede hacer lo siguiente:

String first = strs.get(0);

Pero directamente desde una Colección esto no es posible.


11
No creo que get(int n)se define paraCollection
Nick Heiner

2
Tienes razón, extraño ese punto. He actualizado la respuesta. No puedes! (a menos que la Colección sea implementada por alguna clase subyacente que permita proporcionar la garantía)
OscarRyz el

get no está en la interfaz de la Colección
Andy Gherna el

21
Oscar, creo que estás exagerando el caso. El primer elemento de una Colección puede ser arbitrario en algunos casos como HashSet, pero está bien definido: es .iterator (). Next (). También es estable , en cada implementación de colección que he visto. (relacionadas: nota que mientras Conjunto no garantiza el orden, cada subtipo de Set en el JDK, excepto HashSet hace.)
Kevin Bourrillion

3
Puede ser, pero considere el caso cuando agrega un nuevo elemento a la colección, no sabe (por la interfaz) si ese elemento es el primero, el último o si se insertaría en el medio. Para obtener resultados precisos, debe usar otra interfaz. Sin embargo, probablemente lo que Rosarch necesita es el primer elemento, pase lo que pase. Conocer la colección subyacente puede ayudar, pero evita que la cambie.
OscarRyz el

4

Parece que su colección quiere ser como una lista, por lo que sugeriría:

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

2

En Java 8 tiene muchos operadores para usar, por ejemplo, límite

     /**
 * 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);
}

2
La respuesta de @Vitalii Fedorenko stackoverflow.com/a/18165855/1562662 es mejor.
Chacko Mathew

2

Guava proporciona una onlyElement Collector, pero solo úsela si espera que la colección tenga exactamente un elemento.

Collection<String> stringCollection = ...;
String string = collection.stream().collect(MoreCollectors.onlyElement())

Si no está seguro de cuántos elementos hay, úselos findFirst.

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

1

Puedes hacer un casting. Por ejemplo, si existe un método con esta definición, y sabe que este método está devolviendo una Lista:

Collection<String> getStrings();

Y después de invocarlo, necesita el primer elemento, puede hacerlo así:

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

0

Si sabe que la colección es una cola, puede convertirla en una cola y obtenerla fácilmente.

Hay varias estructuras que puede usar para obtener el pedido, pero deberá emitirlo.


Estoy de acuerdo, si no quieres iterar, no uses la colección. Utilice alguna otra interfaz más específica en su lugar.
Adeel Ansari el

1
Sin embargo, me pregunto ... digamos que los datos subyacentes reales son un SortedSet, por lo que el orden tiene sentido, pero solo tiene una vista de Colección (por una razón no tonta, digamos); si echas la Colección a una Lista, Cola, etc. e intentas obtener / sondeo / etc., ¿se produce un desastre? Del mismo modo, si la estructura subyacente es una Lista, etc., etc.
Carl

@Cal: no lo he probado, pero si convierte una colección en un tipo muy diferente al original, debería recibir un error, pero no lo he probado, por lo que podría estar equivocado.
James Black el

0

Depende totalmente de la implementación que haya utilizado, ya sea la lista de listas enlazadas u otras implementaciones de set.

si está configurado, puede obtener directamente el primer elemento, puede ser un bucle engañoso sobre la colección, crear una variable de valor 1 y obtener un valor cuando el valor del indicador es 1 después de ese salto.

si es la implementación de la lista, entonces es fácil definiendo el número de índice.


0

Forma funcional:

public static <T> Optional<T> findFirst(List<T> result) {
    return Optional.ofNullable(result)
            .map(List::stream)
            .flatMap(Stream::findFirst);
}

fragmento de código anterior preservado de NullPointerException e IndexOutOfBoundsException


1
Su elección de List<T>no satisface la condición de que se debe trabajar para una Collection<String>, pero por supuesto que se puede fijar utilizando Collection<T>, con el cambio adicional: .map(Collection::stream).
Scratte

-2

Podrías hacer esto:

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

El javadoc para Collection ofrece el siguiente orden de advertencia de los elementos de la matriz:

Si esta colección garantiza el orden en que sus iteradores devuelven sus elementos, este método debe devolver los elementos en el mismo orden.


2
Esto crea una nueva matriz de cadenas, mucho más costosa que crear un iterador.
Jim Ferrans el

Sí, pensé en eso después de publicar esto. Independientemente del método utilizado, el orden depende de la implementación subyacente de la Colección. "Primero" luego se convierte en un término relativo. Sin embargo, la forma de hacerlo iterador () es probablemente mejor en la mayoría de los casos.
Andy Gherna

2
Vine aquí porque esta era la solución que tenía y me pareció fea.
haansn08
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.