Java: obtenir le premier élément d'une collection

277

Si j'ai une collection, par exemple Collection<String> strs, comment puis-je retirer le premier article? Je pourrais simplement appeler un Iterator, prendre son premier next(), puis jeter le Iterator. Y a-t-il une façon moins inutile de le faire?

Nick Heiner
la source
1
Bien sûr, il peut y avoir un meilleur moyen d'accéder au premier élément si vous connaissez la classe de conteneur d'implémentation ...
Rooke
Généralisation pour tout index: stackoverflow.com/questions/1047957/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Il semble que vous ayez besoin de Queue.peek ()
Johannes

Réponses:

131

Iterables.get (yourC, indexYouWant)

Parce que vraiment, si vous utilisez des collections, vous devriez utiliser Google Collections.

Carl
la source
7
Cela fait la même chose, il vérifie simplement s'il s'agit d'une liste en premier et obtient par index si c'est le cas. Il a également du code pour essayer d'échouer plus rapidement sur une collection réelle (c'est-à-dire que si l'index est trop volumineux, il essaie de comprendre cela sans itérer tout le problème et lever l'exception à la fin).
Yishai
1
Honnêtement, en termes de performances, il pourrait être légèrement plus lent que c.iterator (). Next () - mais le code est beaucoup plus clair et plus simple à modifier.
Carl
2
Je suis certainement d'accord pour dire que c'est plus propre, mais le PO était un gaspillage, mais je suppose que puisque votre réponse a été acceptée, c'est ce qui était souhaité.
Yishai
8
Pour ceux qui arrivent (encore) ici: Je pense que la réponse de jheddings est probablement la meilleure réponse "get it done", bien que je préfère @ DonaldRaab (en bas de la page) pour les cas où j'utilise déjà la bibliothèque GC. Ma réponse est vraiment pour le cas où l'on peut vouloir écrire dans la flexibilité pour plus tard (disons, si l'on décide que le deuxième élément est la nouvelle chaleur).
Carl
4
Parfois, vous utilisez simplement du code qui utilise des collections, il n'y a donc pas grand-chose à faire.
erickrf
436

On dirait que c'est la meilleure façon de le faire:

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

Grande question ... Au début, cela ressemble à un oubli pour Collection interface.

Notez que "premier" ne retournera pas toujours la première chose que vous avez mise dans la collection, et peut seulement avoir un sens pour les collections ordonnées. C'est peut-être pour cela qu'il n'y a pas d' get(item)appel, car l'ordre n'est pas nécessairement conservé.

Bien que cela puisse sembler un peu inutile, ce n'est peut-être pas aussi mauvais que vous le pensez. Le Iteratorcontient vraiment juste des informations d'indexation dans la collection, pas habituellement une copie de la collection entière. L'invocation de cette méthode instancie l' Iteratorobjet, mais c'est vraiment la seule surcharge (pas comme copier tous les éléments).

Par exemple, en regardant le type retourné par la ArrayList<String>.iterator()méthode, nous voyons qu'il l'est ArrayList::Itr. Il s'agit d'une classe interne qui accède simplement aux éléments de la liste directement, plutôt que de les copier.

Assurez-vous simplement de vérifier le retour de iterator()car il peut être vide ou nulldépendre de l'implémentation.

jheddings
la source
3
Il est important de noter que cette "astuce" ne fonctionne que lorsque la collection contient réellement du contenu. S'il est vide, l'itérateur peut retourner une erreur, dans laquelle il faut vérifier la taille de la collection au préalable.
spaceemotion
20
Ce devrait être la bonne réponse. Je ne comprends pas pourquoi la réponse est toujours "utilisez une autre bibliothèque!" .
Kuzeko
Et le deuxième élément de la collection? Pourquoi first-> next () ne fonctionne pas? Que devrais-je faire? Merci!
pb772
pas assez sûr, il n'est pas garanti que la collection pointe toujours vers le 1er élément.
Prochain développeur
84

En java 8:

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

Pour les anciennes versions de java, il existe une méthode getFirst dans Guava Iterables :

Iterables.getFirst(iterable, defaultValue)
Vitalii Fedorenko
la source
6
La solution java 8 est particulièrement utile, car elle gère le cas où la collection est vide gracieusement.
SpaceTrucker
4
Pas bon. Vous ajoutez la surcharge de stream () pour obtenir un get (0) juste parce que vous êtes paresseux pour écrire 4 lignes de code. if (! CollectionUtils.isEmpty (productList)) {return Optional.of (productList.get (0)); } return Optional.empty ();
RS
Je n'ai pas de getFirstméthode disponible. Il existe getet des getLastméthodes
user1209216
4
@RS et que se passe-t-il si vous ne pouvez pas appeler productList.get (0), car c'est une collection ..? (Selon la question OP)
Denham Coote
40

Il n'y a pas de "premier" article dans un Collectionparce que c'est ... enfin simplement une collection.

À partir de la méthode Collection.iterator () du document Java :

Il n'y a aucune garantie quant à l'ordre dans lequel les éléments sont retournés ...

Vous ne pouvez donc pas.

Si vous utilisez une autre interface telle que List , vous pouvez effectuer les opérations suivantes:

String first = strs.get(0);

Mais directement à partir d'une collection, ce n'est pas possible.

OscarRyz
la source
11
Je ne pense pas que get(int n)c'est défini pourCollection
Nick Heiner
2
Vous avez raison, ce point me manque. J'ai mis à jour la réponse. Tu ne peux pas! (sauf si la collection est implémentée par une classe de sous
jacents
get n'est pas dans l'interface Collection
Andy Gherna
21
Oscar, je pense que vous exagérez l'affaire. Le premier élément d'une collection peut être arbitraire dans quelques cas comme HashSet, mais il est bien défini: c'est .iterator (). Next (). Il est également stable , dans chaque implémentation de collection que j'ai jamais vue. (lié: notez que même si Set ne garantit pas l'ordre, tous les sous-types de Set dans le JDK sauf HashSet le font.)
Kevin Bourrillion
3
C'est possible, mais considérez le cas lorsque vous ajoutez un nouvel élément à la collection, vous ne savez pas (par l'interface) si cet élément est le premier, le dernier ou s'il serait inséré au milieu. Pour des résultats précis, vous devez utiliser une autre interface. Pourtant, ce dont Rosarch a probablement besoin est le 1er élément quoi qu'il arrive. La connaissance de la collection sous-jacente peut être utile, mais elle vous empêche de la modifier.
OscarRyz
4

Il semble que votre collection veuille ressembler à une liste, je suggère donc:

List<String> myList = new ArrayList<String>();
...
String first = myList.get(0);
Jim Ferrans
la source
2

Dans Java 8, vous avez de nombreux opérateurs à utiliser, par exemple limit

     /**
 * 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);
}
Paul
la source
2
La réponse de @Vitalii Fedorenko stackoverflow.com/a/18165855/1562662 est meilleure.
Chacko Mathew
2

Guava fournit un onlyElement Collector, mais ne l'utilisez que si vous vous attendez à ce que la collection ait exactement un élément.

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

Si vous n'êtes pas sûr du nombre d'éléments, utilisez findFirst.

Optional<String> optionalString = collection.stream().findFirst();
ambigu
la source
1

Vous pouvez faire un casting. Par exemple, s'il existe une méthode avec cette définition et que vous savez que cette méthode renvoie une liste:

Collection<String> getStrings();

Et après l'avoir invoqué, vous avez besoin du premier élément, vous pouvez le faire comme ceci:

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

Si vous savez que la collection est une file d'attente, vous pouvez caster la collection dans une file d'attente et l'obtenir facilement.

Il existe plusieurs structures que vous pouvez utiliser pour obtenir la commande, mais vous devrez y caster.

James Black
la source
Je suis d'accord, si vous ne voulez pas répéter, n'utilisez pas la collection. Utilisez plutôt une autre interface plus spécifique.
Adeel Ansari
1
Je me demande cependant ... disons que les données sous-jacentes réelles sont un SortedSet, donc l'ordre est logique, mais vous n'en avez qu'une vue Collection (pour une raison non idiote, disons); si vous transformez la collection en une liste, une file d'attente, etc. et essayez d'obtenir / poll / etc, un désastre s'ensuit-il? De même, si la structure sous-jacente est une liste, ainsi de suite, etc.
Carl
@Cal - Je ne l'ai pas essayé, mais si vous transformez une collection en un type très différent de ce qu'elle était à l'origine, vous devriez obtenir une erreur, mais je ne l'ai pas essayé, donc je peux me tromper.
James Black
0

Cela dépend totalement de l'implémentation que vous avez utilisée, qu'il s'agisse d'une liste de liens arraylist ou d'autres implémentations de set.

s'il est défini, vous pouvez directement obtenir le premier élément, leur boucle peut être trompeuse sur la collection, créer une variable de valeur 1 et obtenir la valeur lorsque la valeur de l'indicateur est 1 après cette rupture de cette boucle.

s'il s'agit d'une implémentation de liste, il est facile de définir le numéro d'index.

Sindhoo Oad
la source
0

Manière fonctionnelle:

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

au-dessus d'extrait de code préservé de NullPointerException et IndexOutOfBoundsException

Farhad Baghirov
la source
1
Votre choix List<T>ne satisfait pas à la condition que cela devrait fonctionner pour un Collection<String>, mais bien sûr , qui peut être fixé à l' aide Collection<T>, avec le changement supplémentaire: .map(Collection::stream).
Scratte
-2

Vous pouvez faire ceci:

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

Le javadoc pour Collection donne l'ordre de mise en garde suivant des éléments du tableau:

Si cette collection donne des garanties quant à l'ordre dans lequel ses éléments sont retournés par son itérateur, cette méthode doit renvoyer les éléments dans le même ordre.

Andy Gherna
la source
2
Cela crée un nouveau tableau String, beaucoup plus cher que la création d'un itérateur.
Jim Ferrans
Ouais, j'y ai pensé après avoir posté ça. Quelle que soit la méthode utilisée, la commande dépend de l'implémentation sous-jacente de la collection. "D'abord" devient alors un terme relatif. Cependant, la méthode iterator () est probablement meilleure dans la plupart des cas.
Andy Gherna
2
Je suis venu ici parce que c'était la solution que j'avais et que j'ai trouvée moche.
haansn08