Java: Koleksiyondan ilk öğeyi alma


277

Bir koleksiyonum varsa Collection<String> strs, ilk öğeyi nasıl çıkarabilirim? Sadece bir tane arayabilir Iterator, ilkini alabilir next(), sonra atabilirim Iterator. Bunu yapmanın daha az savurgan bir yolu var mı?


1
Tabii ki, uygulama kabı sınıfını biliyorsanız ilk öğeye erişmenin daha iyi bir yolu olabilir ...
Rooke


1
Queue.peek ()
Johannes'e

Yanıtlar:


131

Iterables.get (yourC, indexYouWant)

Çünkü gerçekten, Koleksiyonlar kullanıyorsanız Google Koleksiyonlar'ı kullanmalısınız.


7
Bu aynı şeyi yapar, sadece önce bir liste olup olmadığını kontrol eder ve varsa indeksle alır. Ayrıca gerçek bir Koleksiyonda daha hızlı başarısız olmaya çalışmak için bazı kodları vardır (yani dizin çok büyükse, her şeyi yinelemeden ve sonunda istisnayı atmadan anlamaya çalışır).
Yishai

1
Dürüst olmak gerekirse, performans açısından c.iterator (). Next () 'den biraz daha yavaş olabilir, ancak kodun değiştirilmesi çok daha açık ve basittir.
Carl

2
Kesinlikle daha temiz olduğunu kabul ediyorum, ama OP israf hakkındaydı, ama sanırım cevabınız kabul edildiğinden bu istenen şeydi.
Yishai

8
Buraya (hala) gelenler için: Ben zaten GC kütüphanesini kullandığım durumlarda @ DonaldRaab'ın (sayfanın aşağısında) tercih etsem de jheddings'in cevabı muhtemelen en iyi "olsun" cevabıdır. Cevabım gerçekten daha sonra esneklik için yazmak isteyebilecek durumda (örneğin, ikinci elementin yeni sıcaklık olduğuna karar verirse ).
Carl

4
Bazen sadece Koleksiyonlar kullanan bir kod kullanıyorsunuz, bu yüzden yapacak fazla bir şey yok.
erickrf

436

Görünüşe göre bunu yapmanın en iyi yolu:

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

Harika bir soru ... İlk başta, Collectionarayüz için bir gözetim gibi görünüyor .

"İlk" öğesinin her zaman koleksiyona koyduğunuz ilk şeyi döndürmeyeceğini ve yalnızca sipariş edilen koleksiyonlar için anlamlı olabileceğini unutmayın. Belki de bu yüzden bir get(item)çağrı yoktur, çünkü sipariş mutlaka korunmaz.

Biraz savurgan gibi görünse de, düşündüğünüz kadar kötü olmayabilir. IteratorGerçekten sadece toplama, tüm koleksiyonun değil genellikle bir kopyası içine indeksleme bilgilerini içerir. Bu yöntemi çağırmak Iteratornesneyi başlatır , ancak bu gerçekten tek yüktür (tüm öğeleri kopyalamak gibi değil).

Örneğin, ArrayList<String>.iterator()yöntem tarafından döndürülen türe baktığımızda bunun olduğunu görüyoruz ArrayList::Itr. Bu, listenin öğelerine kopyalamak yerine doğrudan erişen dahili bir sınıftır.

Sadece iterator()boş olduğundan veya nulluygulamaya bağlı olabileceğinden dönüşünü kontrol ettiğinizden emin olun .


3
Bu "numara" nın yalnızca koleksiyonun gerçekten içeriği olduğunda işe yaradığını belirtmek önemlidir. Boşsa, yineleyici, koleksiyon boyutunu önceden kontrol etmek zorunda olan bir hata döndürebilir.
spaceemotion

20
Bu doğru cevap olmalı. Cevabın neden her zaman "başka bir kütüphane kullan!" Olduğunu anlamıyorum. .
Kuzeko

Koleksiyonun ikinci elementine ne dersin? Neden ilk-> sonraki () çalışmıyor? Ne yapmalıyım? Teşekkürler!
pb772

yeterince güvenli değil, koleksiyonun her zaman 1. öğeyi göstereceği garanti edilmez.
Sonraki Geliştirici

84

Java 8'de:

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

Java'nın eski sürümleri için Guava Iterables'da bir getFirst yöntemi vardır :

Iterables.getFirst(iterable, defaultValue)

6
Java 8 çözümü özellikle kullanışlıdır, çünkü koleksiyonun zarif bir şekilde boş olduğu durumu işler.
SpaceTrucker

4
İyi değil. Sadece 4 satır kod yazmak için tembel olduğunuz için get (0) elde etmek için stream () ek yükünü eklersiniz. if (! CollectionUtils.isEmpty (productList)) {return Optional.of (productList.get (0)); } return Optional.empty ();
RS

getFirstKullanabileceğim bir yöntem yok . Var getve getLastyöntemler
user1209216

4
@RS ve bir Koleksiyon olduğu için productList.get (0) öğesini arayamazsanız ne olur? (OP sorusuna göre)
Denham Coote

40

Bir şey "ilk" öğe diye bir şey yoktur Collectionçünkü o .. iyi bir koleksiyon.

Java doc's Collection.iterator () yönteminden:

Elemanların iade edilme sırası ile ilgili hiçbir garanti yoktur ...

Yani yapamazsın.

Liste gibi başka bir arabirim kullanıyorsanız , aşağıdakileri yapabilirsiniz:

String first = strs.get(0);

Ancak doğrudan bir Koleksiyondan bu mümkün değildir.


11
Ben bunun get(int n)için tanımlanmış olduğunu sanmıyorumCollection
Nick Heiner

2
Haklısın, bu noktayı özlüyorum. Cevabı güncelledim. Yapamazsın! (Koleksiyon, garantiyi sağlayan bazı alt sınıflar tarafından uygulanmadığı sürece)
OscarRyz

get Koleksiyon arayüzünde değil
Andy Gherna

21
Oscar, bence vakayı abarttın. Bir Koleksiyonun ilk öğesi HashSet gibi birkaç durumda keyfi olabilir, ancak iyi tanımlanmıştır: it .iterator (). Next (). Ayrıca , gördüğüm her koleksiyon uygulamasında da kararlıdır . (ilgili: Set siparişi garanti
etmezken

3
Öyle olabilir, ancak koleksiyona yeni bir öğe eklediğinizde, o öğenin ilk mi, sonuncusu mu yoksa ortasına mı ekleneceğini bilmiyorsunuz (arayüz tarafından). Kesin sonuçlar için başka bir arayüz kullanmalısınız. Yine de, muhtemelen ne olursa olsun Rosarch'ın ihtiyacı olan ilk unsurdur. Underlaying koleksiyonunu bilmek yardımcı olabilir, ancak değiştirmenizi engeller.
OscarRyz

4

Koleksiyonunuz Liste benzeri olmak istiyor gibi görünüyor, bu yüzden şunu öneririm:

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

2

Java 8'de kullanacağınız birçok işleç var, örneğin 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);
}

2
@Vitalii Fedorenko'nun cevabı stackoverflow.com/a/18165855/1562662 daha iyi.
Chacko Mathew

2

Guava bir sağlar onlyElement Collector, ancak yalnızca koleksiyonun tam olarak bir öğeye sahip olmasını bekliyorsanız kullanın.

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

Kaç tane eleman olduğundan emin değilseniz kullanın findFirst.

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

1

Bir döküm yapabilirsiniz. Örneğin, bu tanıma sahip bir yöntem varsa ve bu yöntemin bir Liste döndürdüğünü biliyorsanız:

Collection<String> getStrings();

Ve çağırdıktan sonra, ilk öğeye ihtiyacınız var, bunu şöyle yapabilirsiniz:

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

0

Koleksiyonun bir kuyruk olduğunu biliyorsanız, koleksiyonu bir kuyruğa atabilir ve kolayca alabilirsiniz.

Siparişi almak için kullanabileceğiniz birkaç yapı var, ancak buna atmanız gerekecek.


Katılıyorum, eğer tekrarlamak istemiyorsanız, koleksiyonu kullanmayın. Bunun yerine daha spesifik bir arayüz kullanın.
Adeel Ansari

1
Yine de merak ediyorum ... diyelim ki asıl temel veri bir SortedSet, bu yüzden sipariş mantıklı, ama sadece Koleksiyon görünümü var (aptal olmayan bir nedenle, diyelim); Koleksiyonu bir Listeye, Kuyruğa vb. koyarsanız ve / anket / vb. almaya çalışırsanız, felaket meydana gelir mi? Benzer şekilde, altta yatan yapı bir Liste ise, böyle devam eder.
Carl

@Cal - Ben denemedim, ama bir koleksiyonu orijinalinden çok farklı bir türe dökerseniz bir hata almalısınız, ama denemedim, bu yüzden yanlış olabilirim.
James Black

0

Tamamen hangi uygulamayı kullandığınıza, arraylist bağlantılı listesine veya diğer set uygulamalarına bağlıdır.

ayarlanmışsa, ilk öğeyi doğrudan alabilirsiniz, koleksiyon üzerinde hile döngüsü olabilir, 1 değerinde bir değişken oluşturabilir ve bu döngüden sonra bayrak değeri 1 olduğunda değer elde edebilirsiniz.

listenin uygulanması ise, dizin numarasını tanımlamak kolaydır.


0

Fonksiyonel yolu:

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

yukarıdaki kod snippet'i NullPointerException ve IndexOutOfBoundsException öğesinden korur


1
Seçiminiz List<T>bir için çalışması gerektiğini koşulunu yerine getirmediği Collection<String>, ancak kullanılarak sabitlenebilir tabii Collection<T>ek değişiklikle,: .map(Collection::stream).
Scratte

-2

Bunu yapabilirsin:

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

Koleksiyon için javadoc, dizinin elemanlarının aşağıdaki uyarı sırasını verir:

Bu koleksiyon, öğelerinin yineleyicisi tarafından hangi sırayla döndürüleceğine dair herhangi bir garanti veriyorsa, bu yöntemin öğeleri aynı sırayla döndürmesi gerekir.


2
Bu, bir yineleyici oluşturmaktan çok daha pahalı olan yeni bir String dizisi oluşturur.
Jim Ferrans

Evet, bunu gönderdikten sonra bunu düşündüm. Kullanılan yönteme bakılmaksızın, sıralama, Koleksiyonun altında yatan uygulamaya bağlıdır. "İlk" daha sonra göreceli bir terim olur. Ancak, iterator () yöntemi muhtemelen çoğu durumda daha iyidir.
Andy Gherna

2
Buraya geldim çünkü sahip olduğum ve çirkin bulduğum çözüm buydu.
haansn08
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.