Java: Dapatkan item pertama dari koleksi


277

Jika saya memiliki koleksi, seperti Collection<String> strs, bagaimana saya bisa mengeluarkan barang pertama? Saya bisa memanggil Iterator, mengambil yang pertama next(), lalu membuangnya Iterator. Apakah ada cara yang kurang boros untuk melakukannya?


1
Tentu saja mungkin ada cara yang lebih baik untuk mengakses elemen pertama jika Anda tahu kelas kontainer menerapkan ...
Rooke


1
Sepertinya Anda perlu Queue.peek ()
Johannes

Jawaban:


131

Iterables.get (yourC, indexYouWant)

Karena sungguh, jika Anda menggunakan Koleksi, Anda harus menggunakan Google Koleksi.


7
Itu melakukan hal yang sama, hanya memeriksa apakah itu daftar terlebih dahulu, dan mendapat menurut indeks jika itu adalah daftar. Ini juga memiliki beberapa kode untuk mencoba gagal lebih cepat pada Koleksi aktual (yaitu jika indeks terlalu besar itu mencoba untuk mencari tahu tanpa mengulangi semuanya dan melemparkan pengecualian di akhir).
Yishai

1
Jujur, kinerja-bijaksana mungkin sedikit lebih lambat daripada c.iterator () next () - tetapi kode ini jauh lebih jelas dan lebih mudah untuk dimodifikasi.
Carl

2
Saya tentu setuju ini lebih bersih, tapi OP itu boros, tapi saya kira karena jawaban Anda diterima itulah yang diinginkan.
Yishai

8
Bagi mereka (masih) yang tiba di sini: Saya pikir jawaban jheddings mungkin merupakan jawaban "selesaikan" terbaik, meskipun saya lebih suka @ DonaldRaab (turun halaman) untuk kasus-kasus di mana saya sudah menggunakan perpustakaan GC. Jawaban saya benar-benar untuk kasus di mana seseorang mungkin ingin menulis dalam fleksibilitas untuk nanti (katakanlah, jika seseorang memutuskan bahwa elemen kedua adalah panas yang baru).
Carl

4
Terkadang Anda hanya menggunakan kode yang menggunakan Koleksi, jadi tidak banyak yang bisa dilakukan.
erickrf

436

Sepertinya itu adalah cara terbaik untuk melakukannya:

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

Pertanyaan yang bagus ... Pada awalnya, ini kelihatannya merupakan kekeliruan untuk Collectionantarmuka.

Perhatikan bahwa "pertama" tidak akan selalu mengembalikan hal pertama yang Anda masukkan ke dalam koleksi, dan mungkin hanya masuk akal untuk koleksi yang dipesan. Mungkin itu sebabnya tidak ada get(item)panggilan, karena pesanan belum tentu terpelihara.

Meskipun mungkin tampak sedikit sia-sia, itu mungkin tidak seburuk yang Anda pikirkan. IteratorBenar - benar hanya berisi informasi pengindeksan ke dalam koleksi, bukan biasanya salinan seluruh koleksi. Meminta metode ini membuat instantiate Iteratorobjek, tetapi itu benar-benar satu-satunya overhead (tidak seperti menyalin semua elemen).

Sebagai contoh, melihat jenis yang dikembalikan oleh ArrayList<String>.iterator()metode, kita melihat bahwa itu adalah ArrayList::Itr. Ini adalah kelas internal yang hanya mengakses elemen daftar secara langsung, daripada menyalinnya.

Pastikan Anda memeriksa pengembalian iterator()karena mungkin kosong atau nulltergantung pada implementasinya.


3
Penting untuk dicatat bahwa "trik" ini hanya berfungsi ketika koleksi sebenarnya memiliki konten. Jika kosong iterator mungkin mengembalikan kesalahan, di mana orang harus memeriksa ukuran koleksi sebelumnya.
spaceemotion

20
Ini seharusnya jawaban yang benar. Saya tidak mengerti mengapa jawabannya selalu "gunakan perpustakaan lain!" .
Kuzeko

Bagaimana dengan elemen kedua dari koleksi? Mengapa first-> next () tidak berfungsi? Apa yang harus saya lakukan? Terima kasih!
pb772

tidak cukup aman, itu tidak dijamin bahwa koleksi akan selalu menunjuk ke elemen 1.
Pengembang Selanjutnya

84

Di java 8:

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

Untuk versi java yang lebih lama, ada metode getFirst di Guava Iterables :

Iterables.getFirst(iterable, defaultValue)

6
Solusi java 8 sangat berguna, karena menangani kasus di mana koleksi kosong dengan anggun.
SpaceTrucker

4
Tidak baik. Anda menambahkan overhead stream () untuk mendapatkan get (0) hanya karena Anda malas menulis 4 baris kode. if (! CollectionUtils.isEmpty (productList)) {return Optional.of (productList.get (0)); } return Optional.empty ();
RS

Saya tidak memiliki getFirstmetode yang tersedia. Ada getdan getLastmetode
user1209216

4
@ RS dan apa yang terjadi jika Anda tidak dapat memanggil productList.get (0), karena itu adalah Koleksi ..? (Sesuai pertanyaan OP)
Denham Coote

40

Tidak ada yang namanya "pertama" item dalam Collectionkarena itu .. yah hanya koleksi.

Dari metode Java doc's Collection.iterator () :

Tidak ada jaminan mengenai urutan di mana elemen dikembalikan ...

Jadi kamu tidak bisa.

Jika Anda menggunakan antarmuka lain seperti Daftar , Anda dapat melakukan hal berikut:

String first = strs.get(0);

Tetapi langsung dari Koleksi ini tidak mungkin.


11
Saya tidak berpikir get(int n)didefinisikan untukCollection
Nick Heiner

2
Anda benar, saya merindukan hal itu. Saya telah memperbarui jawabannya. Kamu tidak bisa! (kecuali Koleksi diimplementasikan oleh beberapa kelas yang mendasari yang memungkinkan memberikan jaminan)
OscarRyz

dapatkan tidak ada di antarmuka Koleksi
Andy Gherna

21
Oscar, saya pikir Anda melebih-lebihkan kasus ini. Elemen pertama dari sebuah Koleksi dapat berubah-ubah dalam beberapa kasus seperti HashSet, tetapi ia didefinisikan dengan baik: itu .iterator (). Next (). Ini juga stabil , dalam setiap implementasi koleksi yang pernah saya lihat. (Berhubungan: perhatikan bahwa sementara Set tidak menjamin pesanan, setiap subtipe tunggal dari Set di JDK kecuali HashSet).
Kevin Bourrillion

3
Mungkin saja, tetapi perhatikan kasus ketika Anda menambahkan elemen baru ke koleksi, Anda tidak tahu (dengan antarmuka) jika elemen itu adalah yang pertama, yang terakhir, atau itu akan dimasukkan di tengah. Untuk hasil yang tepat, Anda harus menggunakan antarmuka lain. Namun, mungkin yang dibutuhkan Rosarch adalah elemen pertama, apa pun yang terjadi. Mengetahui koleksi yang mendasari mungkin membantu, tetapi mencegah Anda mengubahnya.
OscarRyz

4

Sepertinya Koleksi Anda ingin seperti Daftar, jadi saya sarankan:

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

2

Di Java 8 Anda memiliki beberapa operator untuk digunakan, misalnya batas

     /**
 * 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 menjawab stackoverflow.com/a/18165855/1562662 lebih baik.
Chacko Mathew

2

Jambu menyediakan onlyElement Collector, tetapi hanya menggunakannya jika Anda mengharapkan koleksi memiliki tepat satu elemen.

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

Jika Anda tidak yakin dengan berapa banyak elemen yang ada, gunakan findFirst.

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

1

Anda bisa melakukan casting. Misalnya, jika ada satu metode dengan definisi ini, dan Anda tahu bahwa metode ini mengembalikan Daftar:

Collection<String> getStrings();

Dan setelah memintanya, Anda perlu elemen pertama, Anda bisa melakukannya seperti ini:

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

0

Jika Anda tahu bahwa koleksi tersebut adalah antrian maka Anda dapat melemparkan koleksi ke antrian dan mendapatkannya dengan mudah.

Ada beberapa struktur yang bisa Anda gunakan untuk mendapatkan pesanan, tetapi Anda harus menggunakan itu.


Saya setuju, jika Anda tidak ingin melakukannya lagi, jangan gunakan koleksi. Gunakan beberapa antarmuka lain yang lebih spesifik.
Adeel Ansari

1
Saya ingin tahu ... katakanlah data yang mendasarinya sebenarnya adalah SortedSet, jadi pesanan masuk akal, tetapi Anda hanya memiliki pandangan Koleksi (untuk alasan yang tidak konyol, katakanlah); jika Anda melemparkan Koleksi ke Daftar, Antrian, dll dan mencoba untuk mendapatkan / polling / etc, apakah bencana terjadi kemudian? Demikian juga, jika struktur yang mendasari adalah Daftar, seterusnya, sebagainya.
Carl

@ Cal - Saya belum mencobanya, tetapi jika Anda memasukkan koleksi ke tipe yang sangat berbeda dari aslinya, Anda seharusnya mendapatkan kesalahan, tapi, saya belum mencobanya, jadi saya bisa saja salah.
James Black

0

Ini benar-benar tergantung pada implementasi mana yang Anda gunakan, apakah arraylist linkedlist, atau implementasi set lainnya.

jika diatur maka Anda bisa langsung mendapatkan elemen pertama, mereka bisa menjadi trik loop di atas koleksi, membuat variabel nilai 1 dan mendapatkan nilai ketika nilai flag 1 setelah itu istirahat loop itu.

jika implementasi daftar maka mudah dengan mendefinisikan nomor indeks.


0

Cara fungsional:

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

cuplikan kode di atas tersimpan dari NullPointerException dan IndexOutOfBoundsException


1
Pilihan Anda List<T>tidak memenuhi kondisi yang harus bekerja untuk Collection<String>, tapi tentu saja yang bisa diperbaiki menggunakan Collection<T>, dengan perubahan tambahan: .map(Collection::stream).
Scratte

-2

Anda bisa melakukan ini:

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

Javadoc for Collection memberikan perintah peringatan elemen elemen berikut:

Jika koleksi ini membuat jaminan apa pun urutan elemennya dikembalikan oleh iteratornya, metode ini harus mengembalikan elemen dalam urutan yang sama.


2
Ini menciptakan array String baru, jauh lebih mahal daripada membuat iterator.
Jim Ferrans

Ya, saya memikirkan hal itu setelah saya memposting ini. Terlepas dari metode yang digunakan, pemesanan tergantung pada implementasi mendasar dari Koleksi. "Pertama" kemudian menjadi istilah relatif. Namun, iterator () cara melakukannya mungkin lebih baik dalam banyak kasus.
Andy Gherna

2
Saya datang ke sini karena ini adalah solusi yang saya miliki dan ternyata jelek.
haansn08
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.