การจัดการกับแอตทริบิวต์ว่างโดยใช้สตรีม Java 8 และการเรียงลำดับโดยใช้นิพจน์แลมบ์ดา

ลองพิจารณาคลาส Parent ซึ่งมีแอตทริบิวต์ Integer เพียงอันเดียว ฉันสร้างวัตถุ 6 รายการของคลาสพาเรนต์และค่าของแอตทริบิวต์คือ 100, 20, 300, 400, 500, null

ตอนนี้ฉันได้เพิ่มวัตถุทั้งหมดลงในรายการ (ชื่อของรายการคือรายการ) ฉันต้องการรับวัตถุที่มีค่าแอตทริบิวต์มากกว่า 100 ฉันใช้สตรีม Java 8 เพื่อจุดประสงค์นี้

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

ฉันยังต้องการเรียงลำดับรายการจากมากไปน้อย ฉันใช้รหัสต่อไปนี้เพื่อจุดประสงค์นี้

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

ในทั้งสองกรณี ฉันได้รับ NullPointerException

จะจัดการเรื่องนี้อย่างไร?


person Manu Joy    schedule 08.07.2015    source แหล่งที่มา


คำตอบ (6)


คำตอบทั้งหมดที่นี่เกี่ยวข้องกับ "กำจัดองค์ประกอบที่ไม่ดีออกไป ซึ่งมี getParentId() เป็นโมฆะ" นั่นอาจเป็นคำตอบหากพวกเขาแย่จริงๆ แต่มีอีกทางเลือกหนึ่ง: Comparators.nullsFirst (หรือสุดท้าย) ซึ่งช่วยให้คุณสามารถเปรียบเทียบสิ่งต่าง ๆ ที่ใช้ค่าว่างว่าน้อยกว่า (หรือมากกว่า) ค่าที่ไม่ใช่ค่าว่างทั้งหมด ดังนั้นคุณจึงไม่จำเป็นต้องโยนองค์ประกอบด้วย parentId เป็นโมฆะ ห่างออกไป.

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

คุณสามารถทำสิ่งที่คล้ายกันในการกรอง กำหนดภาคแสดงของคุณเป็น:

Predicate<Entity> predicate = e -> e.getParentId() != null 
                                       && e.getParentId() < 100;
person Brian Goetz    schedule 08.07.2015
comment
ฉันเดาว่าคุณหมายถึง Comparator.nullsFirst เพราะ Comparators มาจากฝรั่ง - person Eugene Kortov; 10.09.2019

ดูเหมือนว่าคุณกำลังมองหาบางสิ่งเช่น:

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

องค์ประกอบทั้งหมดที่มีพาเรนต์ null จะถูกใส่ไว้ตอนท้าย และส่วนที่เหลือจะถูกจัดเรียงตามพาเรนต์

person joetde    schedule 02.06.2016
comment
วิธีนี้ใช้ได้ผลสำหรับฉัน เพราะฉันไม่ต้องการกรองค่าว่าง - person omerhakanbilici; 14.11.2016
comment
ขอขอบคุณที่แสดงวิธีใช้ Comparator.nullsLast - person Noumenon; 01.12.2018

ลองกรองล่วงหน้าสำหรับค่า parentId ที่ไม่ใช่ค่าว่างเท่านั้น:

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

[แก้ไข] เพิ่งเห็นว่าแอตทริบิวต์ (e.parentId) ดูเหมือนเป็น null ในกรณีนั้น อย่างที่สอง การคัดแยกก็แตกหัก คุณกำลังเรียงลำดับรายการดั้งเดิม ไม่ใช่รายการที่ถูกกรอง ลอง result.sort(comp) แล้วคุณควรหลีกเลี่ยง NPE

person Dominik Sandjaja    schedule 08.07.2015
comment
สิ่งนี้ควรจะได้ผล คุณยังสามารถทำ .filter(Objects::nonNull) - person Nir Alfasi; 08.07.2015
comment
ปัญหาคือวัตถุไม่เป็นโมฆะ แต่แอตทริบิวต์เป็นโมฆะ หากฉันมีแอตทริบิวต์ 100 รายการ และฉันสร้างรายการของวัตถุนั้น ซึ่งแอตทริบิวต์จำนวนมากอาจมีค่าว่างในบางวัตถุในรายการ ฉันจะจัดการอย่างไร นี้. - person Manu Joy; 08.07.2015

คุณสามารถทำได้ทั้งหมดใน 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 ตามข้อความคำถามของคุณ ภาคแสดงดั้งเดิมควรเป็น:

Predicate<Entity> predicate = e -> e.getParentId() > 100; // not < 100
person Eran    schedule 08.07.2015
comment
สิ่งนี้จะไม่กรอง e.getParentId() == null องค์ประกอบใช่ไหม เขากำลังพูดถึง e การเป็นโมฆะ - person Codebender; 08.07.2015
comment
@Codebender ฉันอาจอ่านคำถามผิด แต่ดูเหมือนว่า OP จะสร้างวัตถุที่มีรหัสพาเรนต์เป็น 100,20,300,400,500,null ดังนั้นฉันจึงถือว่าเป็นค่าว่างที่อ้างถึง ParentId ฉันอาจจะผิด. - person Eran; 08.07.2015
comment
@Codebender ที่ไม่ชัดเจน ฉันคิดว่าเขากำลังพูดถึง parentId ที่เป็นโมฆะ ซึ่งเป็นไปได้หากเป็น Integer - person ajb; 08.07.2015

ควบคุมพลังของการอ้างอิงวิธีการเพื่อทำให้โค้ดมีขนาดกะทัดรัดยิ่งขึ้น:

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

คุณทำได้:

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

แน่นอน คุณสามารถรวมภาคแสดงให้เป็นภาคแสดงเดียวได้ แต่ฉันแนะนำภาคแสดงที่สองเพื่อให้อ่านง่ายขึ้น นอกจากนี้ คุณยังเปลี่ยนภาคแสดง nonNull เพื่อตรวจสอบเอนทิตีทั้งหมดหรือเฉพาะแอตทริบิวต์ id ได้อย่างอิสระ (หรือทั้งสองอย่าง) แค่เล่นกับมันสักหน่อย :)

person Konstantin Yovkov    schedule 08.07.2015