Null check di loop untuk ditingkatkan

172

Apa cara terbaik untuk melindungi dari null dalam for for loop di Jawa?

Ini sepertinya jelek:

if (someList != null) {
    for (Object object : someList) {
        // do whatever
    }
}

Atau

if (someList == null) {
    return; // Or throw ex
}
for (Object object : someList) {
    // do whatever
}

Mungkin tidak ada cara lain. Haruskah mereka memasukkannya ke dalam forkonstruk itu sendiri, jika itu nol maka jangan menjalankan loop?

fastcodejava
sumber
2
Anda mungkin lebih baik melempar NPE. nulltidak sama dengan koleksi kosong.
Tom Hawtin - tackline
6
@GregMattes Bagaimana pertanyaan Februari adalah duplikat dari pertanyaan Oktober?
Val
1
Hanya perlu menggunakan Collections.nonNullElementsIn (...): stackoverflow.com/a/34913556/5637185
Jeffrey Dilley

Jawaban:

228

Anda sebaiknya memverifikasi dari mana Anda mendapatkan daftar itu.

Yang Anda butuhkan hanyalah daftar kosong, karena daftar kosong tidak akan gagal.

Jika Anda mendapatkan daftar ini dari tempat lain dan tidak tahu apakah itu ok atau tidak, Anda dapat membuat metode utilitas dan menggunakannya seperti ini:

for( Object o : safe( list ) ) {
   // do whatever 
 }

Dan tentu saja safe:

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}
OscarRyz
sumber
57
Perhatikan bahwa Collections.emptyList () akan menghindari alokasi objek tambahan (IIRC).
Jon Skeet
7
@ Jon: Saya selalu bertanya pada diri saya, apa gunanya emptyList java.sun.com/j2se/1.5.0/docs/api/java/util/... Apa IIRC?
OscarRyz
11
IIRC = "Jika saya mengingatnya dengan benar". Dan ya, ada instance tunggal yang dikembalikan untuk semua panggilan ke Collections.emptyList ().
ColinD
Ini ... sebenarnya tidak menjawab pertanyaan. Mengapa itu diterima jawaban?
Christopher Wirt
1
@ChristopherWirt karena menjawab pertanyaan: D
Tarik
100

Anda berpotensi menulis metode pembantu yang mengembalikan urutan kosong jika Anda memasukkan nol:

public static <T> Iterable<T> emptyIfNull(Iterable<T> iterable) {
    return iterable == null ? Collections.<T>emptyList() : iterable;
}

Kemudian gunakan:

for (Object object : emptyIfNull(someList)) {
}

Saya tidak berpikir saya akan benar-benar melakukannya - saya biasanya menggunakan formulir kedua Anda. Secara khusus, "atau melempar mantan" adalah penting - jika benar-benar tidak boleh nol, Anda harus melempar pengecualian. Anda tahu bahwa ada sesuatu yang salah, tetapi Anda tidak tahu sejauh mana kerusakannya. Batalkan lebih awal.

Jon Skeet
sumber
3
Saya akan mengubah parameter daftar Iterable <T> menjadi Iterable <T> iterable, karena tidak setiap iterable adalah daftar.
Lombo
Hati-hati menggunakan metode ini: karena penggunaan kelas Koleksi, penggunaan metode ini melibatkan daftar Anda tidak berubah
Tanorix
@tanorix: Dengan cara apa?
Jon Skeet
@JonSkeet Anda dapat melihat bahwa emptyList () dari kelas Koleksi mengembalikan daftar yang tidak dapat diubah: docs.oracle.com/javase/8/docs/api/java/util/… jadi jika pengguna tidak ingin agar daftarnya tidak berubah, ia dapat menjadi bermasalah
Tanorix
@tanorix: Tapi inti dari pertanyaan ini adalah tentang mengulangi nilai yang dikembalikan. Itu tidak memodifikasinya. Itu sebabnya tipe kembalinya emptyIfNulladalah Iterable<T>- ada removemetode yang disayangkan Iterator<T>, tapi itu satu-satunya aspek yang bisa berubah-ubah (dan jika Anda punya koleksi kosong, mengapa Anda mencoba menghapus sesuatu darinya?) Tidak jelas apa yang Anda lakukan kembali ke sini.
Jon Skeet
29

Ini sudah 2017, dan sekarang Anda dapat menggunakan Apache Commons Collections4

Penggunaan:

for(Object obj : ListUtils.emptyIfNull(list1)){
    // Do your stuff
}

Anda dapat melakukan pemeriksaan nol-aman yang sama dengan kelas Koleksi lainnya CollectionUtils.emptyIfNull.

Fred Pym
sumber
2
Akan bekerja meskipun menciptakan objek daftar yang tidak perlu. CollectionUtils.ifNotEmpty mungkin lebih bertele-tele tetapi lebih efisien dan lebih cepat. Bukannya akan jadi masalah ...
Lawrence
2
Pada 2017 saya harapkan List.emptyIfNull (list1)
Dima
3
@Lawrence, metode ini tidak membuat objek daftar baru, ia menggunakan Collections.emptyList()internal, yang pada gilirannya selalu mengembalikan daftar kosong yang sama yang tidak dapat dimodifikasi yang sama yang dialokasikan sebelumnya.
Yoory N.
Bagaimana jika Anda memanggil myobject.getCompanies (). GetAddresses () dan keduanya mengembalikan Daftar dan keduanya bisa nol?
powder366
9

Dengan Java 8 Optional:

for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
    // do whatever
}
holmis83
sumber
1
Ini lebih verbose daripada operator ternary sederhana seperti someList != null ? someList : Collections.emptyList()dan juga menciptakan dan segera membuang instance Optionalobjek.
Yoory N.
2
bagaimana garis-garis monster ini lebih elegan daripada pernyataan if (someList == null) yang sederhana. Mari kita menulis aplikasi bank dalam satu baris ...
Andreas Panagiotidis
8

Gunakan ArrayUtils.nullToEmptydari commons-langperpustakaan untuk Array

for( Object o : ArrayUtils.nullToEmpty(list) ) {
   // do whatever 
}

Fungsi ini ada di commons-langperpustakaan, yang termasuk dalam sebagian besar proyek Java.

// ArrayUtils.nullToEmpty source code 
public static Object[] nullToEmpty(final Object[] array) {
    if (isEmpty(array)) {
        return EMPTY_OBJECT_ARRAY;
    }
    return array;
}

// ArrayUtils.isEmpty source code
public static boolean isEmpty(final Object[] array) {
    return array == null || array.length == 0;
}

Ini sama dengan jawaban yang diberikan oleh @OscarRyz, tetapi demi mantra KERING , saya percaya ini patut diperhatikan. Lihat halaman proyek commons-lang . Berikut adalah dokumentasi dan sumbernullToEmpty API

Entri Maven untuk dimasukkan commons-langdalam proyek Anda jika belum.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

Sayangnya, commons-langtidak menyediakan fungsionalitas ini untuk Listtipe. Dalam hal ini Anda harus menggunakan metode pembantu seperti yang disebutkan sebelumnya.

public static <E> List<E> nullToEmpty(List<E> list)
{
    if(list == null || list.isEmpty())
    {
        return Collections.emptyList();
    }
    return list;
}
sdc
sumber
7

Jika Anda mendapatkannya Listdari pemanggilan metode yang Anda terapkan, maka jangan kembali null, kembalikan yang kosong List.

Jika Anda tidak dapat mengubah implementasi maka Anda mandek dengan nullcek. Jika tidak null, maka lemparkan pengecualian.

Saya tidak akan menggunakan metode helper yang mengembalikan daftar kosong karena mungkin berguna beberapa kali tetapi kemudian Anda akan terbiasa menyebutnya di setiap loop yang Anda buat mungkin menyembunyikan beberapa bug.

Lombo
sumber
4

Saya telah memodifikasi jawaban di atas, jadi Anda tidak perlu membuang dari Object

public static <T> List<T> safeClient( List<T> other ) {
            return other == null ? Collections.EMPTY_LIST : other;
}

dan kemudian cukup panggil Daftar dengan

for (MyOwnObject ownObject : safeClient(someList)) {
    // do whatever
}

Penjelasan: MyOwnObject: Jika List<Integer>kemudian MyOwnObject akan menjadi Integer dalam hal ini.

Haris Iltifat
sumber
1

Cara lain untuk melindungi secara efektif terhadap null dalam perulangan for adalah dengan membungkus koleksi Anda dengan Google Guava Optional<T>karena ini, satu harapan, membuat kemungkinan koleksi kosong secara efektif menjadi jelas karena klien diharapkan untuk memeriksa apakah koleksi tersebut hadir Optional.isPresent().

Nico de Wet
sumber
1

Bagi siapa pun yang tidak tertarik dalam menulis metode keselamatan nol statis mereka sendiri, Anda dapat menggunakan: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). Sebagai contoh:

    for (final String item : 
    (List<String>)ObjectUtils.defaultIfNull(items, Collections.emptyList())) { ... }

ObjectUtils.defaultIfNull JavaDoc

Jacob Briscoe
sumber
Bagi saya, jawaban ini adalah yang paling elegan
Truong Nguyen
0

Gunakan, CollectionUtils.isEmpty(Collection coll)metode yang aman untuk memeriksa apakah kumpulan yang ditentukan kosong.

untuk ini import org.apache.commons.collections.CollectionUtils.

Ketergantungan maven

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>
Swadeshi
sumber
-4
for (Object object : someList) {

   // do whatever
}  throws the null pointer exception.
pengguna6315386
sumber