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?


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;
}

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.


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.


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
}

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;
}

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.


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.


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().


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


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>

-4
for (Object object : someList) {

   // do whatever
}  throws the null pointer exception.
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.