如何忽略比较器中的空值?

时间:2018-07-05 08:03:05

标签: java comparator

我有一个比较器,用于比较对象的嵌套字段。这里是price的{​​{1}}。

问题:如果该字段为null,则显示NullPointerException。

问题:如何让比较器忽略比较字段为null的对象,而无需(!)事先过滤列表? “忽略”是指将它们放在列表的末尾。

product

结果:

public class SorterTest {
    private static final Comparator<Product> PRODUCT_COMPARATOR = 
           Comparator.comparing(p -> p.details.price);

    static class Product {
        String name;
        Details details;

        static class Details {
            BigDecimal price;
        }
    }

    @Test
    public void test() {
        List<Product> products = Arrays.asList(
                createProduct("A", new BigDecimal(30.00)),
                createProduct("B", new BigDecimal(55.00)),
                createProduct("C", new BigDecimal(20.00)),
                createProduct("D", null),
                createProduct("E", null),
                createProduct("F", null)
        );

        Collections.sort(products, PRODUCT_COMPARATOR);
        assertEquals("C", products.get(0).name);
        assertEquals("A", products.get(1).name);
        assertEquals("B", products.get(2).name);
        assertEquals("D", products.get(3).name);
        assertEquals("E", products.get(4).name);
        assertEquals("F", products.get(5).name);
    }

    private Product createProduct(String name, BigDecimal price) {
        Product p = new Product();
        p.details = new Product.Details();
        p.name = name;
        p.details.price = price;
        return p;
    }
}

3 个答案:

答案 0 :(得分:3)

您可以使用Comparator的nullsLast方法:

   private static final Comparator PRODUCT_COMPARATOR = 
           Comparator
           .nullsLast(Comparator.comparing(p -> p.details.price, Comparator.nullsLast(Comparator.naturalOrder())));

Product的第一个null持续时间为null,价格的第二个null为空。

答案 1 :(得分:0)

由于价格为null,因此您将收到NullPointerException。因此,使用if语句检查价格值,如果为null,则使用其他值(如0)替换价格。代码可能像:

public class SorterTest {
    private static final Comparator<Product> PRODUCT_COMPARATOR =
            Comparator.comparing(p->
                    {
                        if (p.details != null && p.details.price != null) {
                            return p.details.price;
                        } else {
                            return new BigDecimal(0);
                        }
                    }
            );

    static class Product {
        String name;
        Details details;

        static class Details {
            BigDecimal price;
        }
    }

    @Test
    public void test() {
        List<Product> products = Arrays.asList(
                createProduct("A", new BigDecimal(30.00)),
                createProduct("B", new BigDecimal(55.00)),
                createProduct("C", new BigDecimal(20.00)),
                createProduct("D", null),
                createProduct("E", null),
                createProduct("F", null)
        );

        Collections.sort(products, PRODUCT_COMPARATOR);
        assertEquals("D", products.get(0).name);
        assertEquals("E", products.get(1).name);
        assertEquals("F", products.get(2).name);
        assertEquals("C", products.get(3).name);
        assertEquals("A", products.get(4).name);
        assertEquals("B", products.get(5).name);
    }

    private Product createProduct(String name, BigDecimal price) {
        Product p = new Product();
        p.details = new Product.Details();
        p.name = name;
        p.details.price = price;
        return p;
    }
}

答案 2 :(得分:0)

您可以使用Optional <>来查看getter的结果是否为null或有效值。对于空值,可以通过始终将其comparer()结果设为-1或1来将它们放在尾部或头部。

private static final Comparator<Product> PRODUCT_COMPARATOR = 
           Comparator.comparing(p -> {
               Optional<BigDecimal> res = Optional.ofNullable(p.getPrice);
               if(res.isPresent())
                   return p.getPrice();
               else
                   return -1;
           });
           ...
static class Product {
        String name;
        BigDecimal price;

        BigDecimal getPrice(){
            return this.price;
        }
        ...
}