繁体   English   中英

有没有更好的方法来处理 Java 中的多个空检查?

[英]Is there a better way of handling multiple null checks in Java?

我有以下代码

Set<Product> getallProducts(){

    Product p = getProduct(brand, price);
    Product p1 = getProduct(brand, price, location);
    Product p2 = getProduct(brand, price, qty);

   Set<SuperProducts> superProducts = new HashSet<>;


   if(p!=null){
      SuperProduct sp  = getSuperProduct(p)
      superProducts.add(sp)
   }

   if(p1!=null){
      SuperProduct sp1  = getSuperProduct(p1)
      superProducts.add(sp)

   }

   if(p2!=null){
      SuperProduct sp2  = getSuperProduct(p2)
      superProducts.add(sp2)

    }
}

有没有明确的方法来处理 p!=null, p2!=null, p1 !=null。 我可以将 p,p1,p2 添加到列表中并按如下方式遍历它,但我正在寻找一种比将产品添加到列表然后遍历它们更便宜的方法。? 另外,我想知道每次检查 null 是否比添加到列表并遍历它更昂贵?

List<Product> products = new ArrayList<>():
products.add(p);
products.add(p1);
products.add(p2);

and 
for(Product p:products){
// and adding to superProducts
}

您可以使用Stream.of然后filter为:

return Stream.of(p1, p2, p3).filter(Objects::nonNull)
                            .map(this::getSuperProduct)
                            .collect(Collectors.toSet());

这是一种使用 Optional 的方法,不会比其他答案长多少,因为无论如何都需要创建每个 Product 对象。

Set<Product> getallProducts() {
    Set<SuperProducts> superProducts = new HashSet<>;

    Optional.ofNullable(getProduct(brand, price))
        .ifPresent(prod -> superProducts.add(new SuperProduct(prod)));
    Optional.ofNullable(getProduct(brand, price, location))
        .ifPresent(prod -> superProducts.add(new SuperProduct(prod)));
    Optional.ofNullable(getProduct(brand, price, qty))
        .ifPresent(prod -> superProducts.add(new SuperProduct(prod)));

    return superProducts;
}

如果您正在寻找执行此操作的最佳方式,请坚持使用您当前的方式。 您的解决方案很冗长,但可能尽可能有效。 毫无疑问,您的代码比其他替代方案更容易理解。

如果您正在寻找使用更少代码行的解决方案,您可以使用流和过滤器来实现这一点,或者通过创建Product引用和迭代的数组或列表来实现。 然而,这些解决方案都需要创建临时数据结构并且效率大大降低。


请注意,如果getSuperProduct(p)调用是由 JIT 编译器内联的,那么它可能能够优化掉调用中发生的null隐式测试。


另外,我想知道每次检查 null 是否比添加到列表并遍历它更昂贵?

我想你会发现情况正好相反。 在任何一种情况下,您都需要进行空检查(或不...见上文)。 当你尝试使用一个列表、数组或流时,你有创建数据结构的开销(一个或多个新的堆对象来创建和初始化),当你到达列表的末尾时你有测试的开销/阵列/流。


最后要注意的一件事是,像这样的代码的效率通常是无关紧要的。 我们可能在谈论不到 100 条指令的差异; 即小于 1 微秒的差异。 与应用程序正在执行的其他操作相比,这可能是微不足道的。

鉴于相同的代码序列重复 3 次,我将编写一个实用方法:

 private void addSuper(Product p, Set<SuperProduct> s) {
   if (p != null)
      s.add(getSuperProduct(p));
 }

进而

Set<SuperProduct> superProducts = new HashSet<>();
addSuper(getProduct(brand, price), superProducts);
addSuper(getProduct(brand, price, location), superProducts);
addSuper(getProduct(brand, price, qty), superProducts);

我在进行这种重构时主要关注的不是“非空测试”,而是原始内容的重复性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM