从列表中遍历和查找对象字段的最佳方法

Best way to traverse and find an object field from a list

我有一个自定义对象列表,我想通过给定的 Id(自定义对象中的一个字段)找到一个对象。我正在为此编码,所以我在比较字段时找到了两个解决方案。

1

private Product getProduct(String productId,List<Product> productList){
        for (int i = 0; i < productList.size(); i++) {
            if (productId.equals(productList.get(i).getId())) {
                return productList.get(i);
            }


        }
        return null;
    }

2.

 private Product getProduct(String productId,List<Product> productList){
        for (int i = 0; i < productList.size(); i++) {
            if (productList.get(i).getId().equals(productId)) {
                return productList.get(i);
            }
        }
        return null;
    }

区别在于 if 条件,我想知道哪个比另一个更好,为什么,什么时候使用第一种方法,什么时候使用第二种方法?

第一个在参数 productId 上调用 equals,而第二个在 productList 中的当前列表元素上调用 equals。结果是一样的,因为 equals 对称的 :

for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.

您也可以为此使用流,因此您不必关心实现细节(此外,Objects#equals(Object, Object) 是空安全的):

String p = productList.stream().filter(e -> Objects.equals(e, productId))
                               .findFirst()
                               .orElse(null);

查看 this 问题以获取更多信息。

由于 equals() 被 Java required 对称,所以这两个片段之间没有区别。

这两个片段都不是最佳的,因为它们按数字索引迭代,并在返回之前检索 productList.get(i) 两次。按索引迭代特别危险,因为传递 LinkedList<Product> 会大大减慢您的搜索速度。

更好的方法是使用 for-each 形式的循环:

for (Product p : productList) {
    if (p.getId().equals(productId)) {
        return p;
    }
}
return null;

当您确定产品 ID 永远不会为空时,这并不重要。

但总的来说,以防御方式编程总是好的,所以例如更喜欢使用

"SomeString".equals(aString)

而不是

aString.equals("SomeString")

因为你知道 "SomeString" 永远不会是 null

或使用

Objects.equals(object1, object2)

当两个对象都可能是 null

您的两个实现中的问题是对空值调用 .equals 的可能性。

如果你能保证它们都不为空那么它们是等价的。

如果您使用的是 Java 8,stream 可能是更好的选择。

private Product getProduct(String productId,List<Product> productList){
    return products.stream()
        .filter(p-> productId.equals(p.getId())
        .findFirst()
        .orElse(null);