Berurusan dengan atribut null menggunakan aliran Java 8 dan mengurutkan menggunakan ekspresi lambda

Mari kita pertimbangkan kelas Parent yang hanya berisi satu atribut Integer. Saya membuat 6 objek kelas induk dan nilai atributnya adalah 100, 20, 300, 400, 500, null.

Sekarang saya menambahkan semua objek ke daftar (Nama daftar adalah daftar). Lalu saya ingin mendapatkan objek yang nilai atributnya lebih besar dari 100. Saya menggunakan aliran Java 8 untuk tujuan ini.

Predicate<Entity> predicate = e -> e.getParentId() < 100;
result = list.stream().filter(predicate).collect(Collectors.toList());

Saya juga ingin mengurutkan daftar dalam urutan menurun. Saya menggunakan kode berikut untuk tujuan ini.

Comparator<Entity> comp = (d1,d2) -> d2.getId().compareTo(d1.getId());
list.sort(comp);

Dalam kedua kasus saya mendapatkan NullPointerException.

Bagaimana cara menangani ini?


person Manu Joy    schedule 08.07.2015    source sumber


Jawaban (6)


Semua jawaban di sini berkisar pada "buang elemen buruk, elemen yang memiliki getParentId() nol." Itu mungkin jawabannya, jika memang buruk. Namun ada alternatif lain: Comparators.nullsFirst (atau terakhir.) Ini memungkinkan Anda membandingkan hal-hal yang menganggap nilai nol kurang dari (atau lebih besar dari) semua nilai bukan nol, jadi Anda tidak perlu membuang elemen dengan parentId nol jauh.

Comparator<Entity> cmp = nullsLast(comparing(Entity::getParentId));
List<Entity> list = list.stream().sorted(cmp).collect(toList());

Anda dapat melakukan hal serupa untuk memfilter; tentukan predikat Anda sebagai:

Predicate<Entity> predicate = e -> e.getParentId() != null 
                                       && e.getParentId() < 100;
person Brian Goetz    schedule 08.07.2015
comment
Saya rasa maksud Anda Comparator.nullsFirst karena Comparators berasal dari Jambu Biji - person Eugene Kortov; 10.09.2019

Sepertinya Anda mencari sesuatu seperti:

list.sort(Comparator.comparing(Entity::getParent, 
                               Comparator.nullsLast(Integer::compareTo)));

Semua elemen dengan induk null akan diletakkan di akhir dan sisanya akan diurutkan berdasarkan induknya.

person joetde    schedule 02.06.2016
comment
solusi ini berhasil untuk saya. Karena saya tidak ingin memfilter nilai nol. - person omerhakanbilici; 14.11.2016
comment
Terima kasih telah menunjukkan cara menggunakan Comparator.nullsLast. - person Noumenon; 01.12.2018

Coba lakukan pra-pemfilteran hanya untuk nilai parentId yang bukan nol:

result = list.stream().filter(e -> e.getParentId() != null).filter(predicate).collect(Collectors.toList());

[sunting] Baru saja melihat, atribut (e.parentId) sepertinya null. Dalam hal ini, hal kedua, penyortiran, rusak. Anda mengurutkan daftar asli, bukan daftar yang difilter. Coba result.sort(comp), maka sebaiknya hindari NPE.

person Dominik Sandjaja    schedule 08.07.2015
comment
Ini seharusnya berhasil. Anda juga dapat melakukan .filter(Objects::nonNull) - person Nir Alfasi; 08.07.2015
comment
Masalahnya adalah objek bukan nol, tetapi atributnya nol, jika saya berisi 100 atribut, dan saya membuat daftar objek itu, di mana banyak atribut mungkin memiliki nilai nol di beberapa objek dalam daftar, bagaimana saya harus menanganinya? ini. - person Manu Joy; 08.07.2015

Anda dapat melakukan semuanya dalam satu pipa Stream :

List<Entity> result =  
    list.stream()
        .filter(e -> e.getParentId()!=null) // it's not clear if the null
                                            // is the Entity object itself
                                            // (in which case it should be e!=null)
                                            // or just the ParentId member
        .filter(predicate)
        .sorted(comp)
        .collect(Collectors.toList());

BTW, menurut teks pertanyaan Anda, predikat aslinya adalah:

Predicate<Entity> predicate = e -> e.getParentId() > 100; // not < 100
person Eran    schedule 08.07.2015
comment
Bukankah ini akan memfilter e.getParentId() == null elemen? Dia berbicara tentang e menjadi nol. - person Codebender; 08.07.2015
comment
@Codebender Saya mungkin salah membaca pertanyaannya, tetapi sepertinya OP membuat objek dengan ID induk 100,20,300,400,500,null, jadi saya berasumsi nol merujuk ke ParentId. Saya mungkin salah. - person Eran; 08.07.2015
comment
@Codebender itu tidak jelas. Saya pikir dia berbicara tentang parentId menjadi nol, yang mungkin terjadi jika itu adalah Integer. - person ajb; 08.07.2015

Manfaatkan kekuatan referensi metode untuk membuat kode menjadi lebih ringkas:

   List<Entity> result =
            list.stream()
                    .filter(Objects::nonNull) 
                    .filter(predicate)
                    .sorted(comp)
                    .collect(Collectors.toList());
person Fritz Duchardt    schedule 08.07.2015

Anda dapat melakukan:

Predicate<Entity> predicate = e -> e.getParentId() < 100;
Predicate<Entity> nonNull = e -> e != null;
result = list.stream().filter(nonNull)
                      .filter(predicate)
                      .collect(Collectors.toList());

Tentu saja, Anda dapat menggabungkan predikat menjadi satu, namun saya memperkenalkan predikat kedua agar lebih mudah dibaca. Selain itu, Anda bebas mengubah predikat nonNull untuk memeriksa keseluruhan entitas, atau hanya atribut id (atau bahkan keduanya). Mainkan saja sedikit dengannya. :)

person Konstantin Yovkov    schedule 08.07.2015