Java: Erstes Element aus einer Sammlung abrufen

277

Wenn ich eine Sammlung habe, Collection<String> strswie kann ich den ersten Artikel herausbringen? Ich könnte einfach einen anrufen Iterator, seinen ersten nehmen next()und dann den wegwerfen Iterator. Gibt es einen weniger verschwenderischen Weg, dies zu tun?

Nick Heiner
quelle
1
Natürlich gibt es möglicherweise eine bessere Möglichkeit, auf das erste Element zuzugreifen, wenn Sie die implementierende Containerklasse kennen ...
Rooke
Verallgemeinerung für jeden Index: stackoverflow.com/questions/1047957/…
Ciro Santilli 法轮功 冠状 病 六四 事件 23
1
Es klingt wie Sie brauchen Queue.peek ()
Johannes

Antworten:

131

Iterables.get (yourC, indexYouWant)

Wenn Sie Sammlungen verwenden, sollten Sie Google Sammlungen verwenden.

Carl
quelle
7
Das macht das gleiche, es prüft nur zuerst, ob es sich um eine Liste handelt, und erhält sie anhand des Index, wenn dies der Fall ist. Es gibt auch Code, mit dem versucht werden kann, bei einer tatsächlichen Sammlung schneller fehlzuschlagen (dh wenn der Index zu groß ist, wird versucht, dies herauszufinden, ohne das Ganze zu durchlaufen und die Ausnahme am Ende auszulösen).
Yishai
1
In Bezug auf die Leistung ist es möglicherweise etwas langsamer als c.iterator (). Next () - aber der Code ist viel klarer und einfacher zu ändern.
Carl
2
Ich bin mir sicher einig, dass es sauberer ist, aber das OP war verschwenderisch, aber ich denke, da Ihre Antwort akzeptiert wurde, war dies das, was gewünscht wurde.
Yishai
8
Für diejenigen, die (noch) hier ankommen: Ich denke, die Antwort von jheddings ist wahrscheinlich die beste Antwort auf "Get it done", obwohl ich @ DonaldRaab's (ganz unten auf der Seite) für Fälle vorziehen würde, in denen ich bereits die GC-Bibliothek verwende. Meine Antwort ist wirklich für den Fall, dass man für später flexibel schreiben möchte (z. B. wenn man entscheidet, dass das zweite Element die neue Schärfe ist).
Carl
4
Manchmal verwenden Sie nur Code, der Sammlungen verwendet, sodass nicht viel zu tun ist.
Erickrf
436

Sieht so aus, als wäre das der beste Weg, dies zu tun:

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

Gute Frage ... Auf den ersten Blick scheint es ein Versehen für die Collection Benutzeroberfläche zu sein.

Beachten Sie, dass "first" nicht immer das erste zurückgibt, was Sie in die Sammlung aufgenommen haben, und möglicherweise nur für bestellte Sammlungen sinnvoll ist. Vielleicht gibt es deshalb keinen get(item)Anruf, da die Reihenfolge nicht unbedingt erhalten bleibt.

Es mag ein bisschen verschwenderisch erscheinen, aber es ist vielleicht nicht so schlimm, wie Sie denken. Das Iteratorenthält wirklich nur Indizierungsinformationen in der Sammlung, normalerweise keine Kopie der gesamten Sammlung. Das Aufrufen dieser Methode instanziiert das IteratorObjekt, aber das ist wirklich der einzige Overhead (nicht wie das Kopieren aller Elemente).

Wenn ArrayList<String>.iterator()wir uns beispielsweise den von der Methode zurückgegebenen Typ ansehen, sehen wir, dass dies der Fall istArrayList::Itr . Dies ist eine interne Klasse, die nur direkt auf die Elemente der Liste zugreift, anstatt sie zu kopieren.

Stellen Sie nur sicher, dass Sie die Rückgabe von überprüfen, iterator()da diese möglicherweise leer ist oder nullvon der Implementierung abhängt.

jheddings
quelle
3
Es ist wichtig zu beachten, dass dieser "Trick" nur funktioniert, wenn die Sammlung tatsächlich Inhalt enthält. Wenn es leer ist, gibt der Iterator möglicherweise einen Fehler zurück, bei dem die Sammlungsgröße vorher überprüft werden muss.
Raumbewegung
20
Dies sollte die richtige Antwort sein. Ich verstehe nicht, warum die Antwort immer "benutze eine andere Bibliothek!" .
Kuzeko
Wie wäre es mit dem zweiten Element der Sammlung? Warum funktioniert first-> next () nicht? Was soll ich machen? Vielen Dank!
pb772
Nicht sicher genug, es kann nicht garantiert werden, dass die Sammlung immer auf das 1. Element verweist.
Nächster Entwickler
84

In Java 8:

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

Für ältere Versionen von Java gibt es in Guava Iterables eine getFirst-Methode :

Iterables.getFirst(iterable, defaultValue)
Vitalii Fedorenko
quelle
6
Die Java 8-Lösung ist besonders nützlich, da sie den Fall behandelt, in dem die Sammlung ordnungsgemäß leer ist.
SpaceTrucker
4
Nicht gut. Sie fügen den Overhead von stream () hinzu, um get (0) zu erhalten, nur weil Sie faul sind, 4 Codezeilen zu schreiben. if (! CollectionUtils.isEmpty (productList)) {return Optional.of (productList.get (0)); } return Optional.empty ();
RS
Ich habe keine getFirstMethode zur Verfügung. Es gibt getund getLastMethoden
user1209216
4
@RS und was passiert, wenn Sie productList.get (0) nicht aufrufen können, da es sich um eine Sammlung handelt? (Gemäß OP-Frage)
Denham Coote
40

Es gibt kein "erstes" Element in einem Collection weil es ... einfach eine Sammlung ist.

Aus der Collection.iterator () -Methode des Java-Dokuments :

Es gibt keine Garantie für die Reihenfolge, in der die Elemente zurückgegeben werden ...

Also kannst du nicht.

Wenn Sie eine andere Schnittstelle wie List verwenden , können Sie Folgendes tun:

String first = strs.get(0);

Direkt aus einer Sammlung ist dies jedoch nicht möglich.

OscarRyz
quelle
11
Ich glaube nicht, dass get(int n)fürCollection
Nick Heiner
2
Du hast recht, ich vermisse diesen Punkt. Ich habe die Antwort aktualisiert. Das kannst du nicht! (es sei denn, die Sammlung wird von einer Unterlageklasse implementiert, die die Garantie bietet)
OscarRyz
get ist nicht in der Collection-Oberfläche
Andy Gherna
21
Oscar, ich denke du übertreibst den Fall. Das erste Element einer Sammlung kann in einigen Fällen wie HashSet beliebig sein, ist jedoch genau definiert: Es ist .iterator (). Next (). Es ist auch stabil in jeder Sammlungsimplementierung, die ich je gesehen habe. (Verwandte: Beachten Sie, dass Set zwar keine Reihenfolge garantiert, aber jeder einzelne Subtyp von Set im JDK außer HashSet dies tut.)
Kevin Bourrillion
3
Es mag sein, aber wenn Sie der Sammlung ein neues Element hinzufügen, wissen Sie (über die Schnittstelle) nicht, ob dieses Element das erste, das letzte ist oder in die Mitte eingefügt wird. Für genaue Ergebnisse sollten Sie eine andere Schnittstelle verwenden. Wahrscheinlich ist das, was Rosarch braucht, das erste Element, egal was passiert. Die Kenntnis der darunter liegenden Sammlung kann hilfreich sein, verhindert jedoch, dass Sie sie ändern.
OscarRyz
4

Es hört sich so an, als ob Ihre Sammlung listenartig sein möchte, also würde ich vorschlagen:

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

In Java 8 müssen Sie einige Operatoren verwenden, z. B. 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
quelle
2
@Vitalii Fedorenkos Antwort stackoverflow.com/a/18165855/1562662 ist besser.
Chacko Mathew
2

Guava bietet ein onlyElement Collector, aber verwenden Sie es nur, wenn Sie erwarten, dass die Sammlung genau ein Element enthält.

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

Wenn Sie sich nicht sicher sind, wie viele Elemente vorhanden sind, verwenden Sie findFirst.

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

Sie können ein Casting machen. Wenn beispielsweise eine Methode mit dieser Definition vorhanden ist und Sie wissen, dass diese Methode eine Liste zurückgibt:

Collection<String> getStrings();

Und nachdem Sie es aufgerufen haben, benötigen Sie das erste Element. Sie können dies folgendermaßen tun:

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

Wenn Sie wissen, dass es sich bei der Sammlung um eine Warteschlange handelt, können Sie die Sammlung in eine Warteschlange umwandeln und problemlos abrufen.

Es gibt verschiedene Strukturen, mit denen Sie die Bestellung abrufen können, die Sie jedoch bearbeiten müssen.

James Black
quelle
Ich bin damit einverstanden, wenn Sie nicht iterieren möchten, verwenden Sie keine Sammlung. Verwenden Sie stattdessen eine andere spezifischere Schnittstelle.
Adeel Ansari
1
Ich frage mich allerdings ... Nehmen wir an, die tatsächlich zugrunde liegenden Daten sind ein SortedSet. Die Reihenfolge ist also sinnvoll, aber Sie haben nur eine Sammlungsansicht davon (aus einem nicht dummen Grund, sagen wir). Wenn Sie die Sammlung in eine Liste, eine Warteschlange usw. umwandeln und versuchen, / poll / etc abzurufen, kommt es dann zu einer Katastrophe? Ebenso, wenn die zugrunde liegende Struktur eine Liste ist, so weiter, so weiter.
Carl
@Cal - Ich habe es nicht ausprobiert, aber wenn Sie eine Sammlung in einen ganz anderen Typ als ursprünglich umwandeln, sollten Sie eine Fehlermeldung erhalten, aber ich habe es nicht ausprobiert, sodass ich mich irren könnte.
James Black
0

Es hängt ganz davon ab, welche Implementierung Sie verwendet haben, ob die Arraylist-Linkliste oder andere Implementierungen von Set.

Wenn es gesetzt ist, können Sie direkt das erste Element abrufen, es kann eine Trickschleife über die Sammlung sein, eine Variable mit dem Wert 1 erstellen und den Wert abrufen, wenn der Flag-Wert 1 ist, nachdem diese Schleife unterbrochen wurde.

Wenn es sich um die Implementierung einer Liste handelt, ist es einfach, die Indexnummer zu definieren.

Sindhoo Oad
quelle
0

Funktionsweise:

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

obiges Code-Snippet aus NullPointerException und IndexOutOfBoundsException erhalten

Farhad Baghirov
quelle
1
Ihre Wahl von List<T>erfüllt nicht die Bedingung, dass es für a funktionieren sollte Collection<String>, aber das kann natürlich Collection<T>mit der zusätzlichen Änderung behoben werden : .map(Collection::stream).
Scratte
-2

Sie könnten dies tun:

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

Das Javadoc für die Sammlung enthält die folgenden Einschränkungen hinsichtlich der Reihenfolge der Elemente des Arrays:

Wenn diese Sammlung garantiert, in welcher Reihenfolge ihre Elemente von ihrem Iterator zurückgegeben werden, muss diese Methode die Elemente in derselben Reihenfolge zurückgeben.

Andy Gherna
quelle
2
Dadurch wird ein neues String-Array erstellt, das viel teurer ist als das Erstellen eines Iterators.
Jim Ferrans
Ja, ich habe darüber nachgedacht, nachdem ich das gepostet habe. Unabhängig von der verwendeten Methode hängt die Reihenfolge von der zugrunde liegenden Implementierung der Sammlung ab. "Zuerst" wird dann ein relativer Begriff. In den meisten Fällen ist die iterator () -Methode jedoch wahrscheinlich besser.
Andy Gherna
2
Ich kam hierher, weil dies die Lösung war, die ich hatte und die ich hässlich fand.
haansn08