无法理解 Predicate isEqual 方法

Unable to get my head around Predicate isEqual method

在 Java 文档中给出 -

Modifier and Type                      Method and Description
static <T> Predicate<T>                isEqual(Object targetRef)
                                       Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object).

https://www.geeksforgeeks.org/java-8-predicate-with-examples/

给出-

isEqual(Object targetRef) : Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object).

static Predicate isEqual(Object targetRef) Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object). T : the type of arguments to the predicate Parameters: targetRef : the object reference with which to compare for equality, which may be null Returns: a predicate that tests if two arguments are equal according to Objects.equals(Object, Object)

我无法理解这个 Objects.equals(Object, Object) 可能是什么

我写了下面的代码试试看-

Class 水果 -

Fruits.java-

public class Fruits {
    private String fruit;

    public Fruits(String fruit) {
        this.fruit = fruit;
    }

    public String getFruit() {
        return fruit;
    }
}

到这里,predicate的其他方法好像还挺容易理解的-

Predicate<List<Fruits>> containsApple = list -> {
            boolean myReturn = false;
            Iterator<Fruits> iterator = list.iterator();
            while (iterator.hasNext()) {
                Fruits fruits = iterator.next();
                String fruit = fruits.getFruit();
                if (fruit.equals("Apple")) {
                    myReturn = true;
                    break;
                }
            }
            return myReturn;
        };
Predicate<List<Fruits>> containsOrange = list -> {
            boolean myReturn = false;
            Iterator<Fruits> iterator = list.iterator();
            while (iterator.hasNext()) {
                Fruits fruits = iterator.next();
                String fruit = fruits.getFruit();
                if (fruit.equals("Orange")) {
                    myReturn = true;
                    break;
                }
            }
            return myReturn;
        };
Predicate<List<Fruits>> containsAppleAndOrange = list -> {
            return containsApple.and(containsOrange).test(list);
        };
Predicate<List<Fruits>> containsAppleOrRange = list -> {
            return containsApple.or(containsOrange).test(list);
        };

Predicate<List<Fruits>> notContainsApple = list -> {
            return containsApple.negate().test(list);
        };
Predicate<List<Fruits>> notContainsOrange = list -> {
            return containsOrange.negate().test(list);
        };
Predicate<List<Fruits>> notContainsAppleAndOrange = list -> {
            return containsAppleAndOrange.negate().test(list);
        };
Predicate<List<Fruits>> notContainsAppleOrOrange = list -> {
            return containsAppleOrRange.negate().test(list);
        };

这里我用下面的数据进行测试-

        List<Fruits> list1 = new ArrayList<>(List.of(
                new Fruits("Apple"),
                new Fruits("Orange"),
                new Fruits("Mango"),
                new Fruits("Banana")
        ));

        List<Fruits> list2 = new ArrayList<>(List.of(
                new Fruits("Apple"),
                new Fruits("Mango"),
                new Fruits("Banana"),
                new Fruits("Berry")
        ));

        List<Fruits> list3 = new ArrayList<>(List.of(
                new Fruits("Orange"),
                new Fruits("Mango"),
                new Fruits("Banana"),
                new Fruits("Berry")
        ));

结果符合预期。

但是我完全无法理解如何实现 isEqual() 方法 -

要查看两个参数是否相等,我创建了另一个谓词 -

redicate<List<Fruits>> containsApple2 = list -> {
            boolean myReturn = false;
            Iterator<Fruits> iterator = list.iterator();
            while (iterator.hasNext()) {
                Fruits fruits = iterator.next();
                String fruit = fruits.getFruit();
                if (fruit.equals("Apple")) {
                    myReturn = true;
                    break;
                }
            }
            return myReturn;
        };

我尝试类似(不明白为什么)-

System.out.println(Predicate.isEqual(containsApple).test(list1));

输出 - false

现在这里发生了什么?

System.out.println(Predicate.isEqual(containsApple2).test(containsApple));

输出 - false

现在又发生了什么事?

那么,这个isEqual方法具体怎么用呢?

Predicate.isEqual 是一个工厂方法,它创建谓词来测试给定的事物是否等于传入的参数。

Predicate.isEqual(containsApple) 创建一个 Predicate<Predicate<List<Fruits>>> 来测试给定的事物是否等于 containsApple。但是,由于 containsApple 指的是从 lambda 创建的实例,并且对于从 lambda 表达式创建的实例的相等性并没有太多保证(参见 JLS),所以关于结果没有什么可以说的在上面调用 test。 lambda 实例的 类 可能实现也可能不实现 equals,并且 containsApple 可能与 containsApple2 是同一实例,也可能不同,具体取决于实现。

而不是比较 lambda 实例,使用 Predicate.isEqual 的典型示例是:

Fruits apple = new Fruits("Apple");
Predicate<Fruits> isApple = Predicate.isEqual(apple);
// rather than this slightly longer version:
// Predicate<Fruits> isApple = x -> Objects.equals(x, apple);

然后你可以将 isApple 传递给其他需要 Predicates 的方法,and/or 调用 test 就可以了。 isApple.test(apple) 为真,isApple.test(new Fruits("something else")) 为假。我还建议您在 Fruits.

中覆盖 equalshashCode

请注意,我们通常使用谓词来测试单个对象,而不是事物列表(集合)。我们会将这些谓词传递给其他方法(例如 Stream.filter),并让 它们 进行过滤。例如,要过滤列表以获取所有苹果:

List<Fruits> apples = fruitsList.stream()
    .filter(Predicate.isEqual(apple)).toList();

这里 class 水果应该用单数。

首先你必须建立水果的平等。如果您希望它存储在 HashMap 或 HashSet 中,hashCode 实现也很重要。

public class Fruit {
    private final String fruit; // Or name.

    public Fruit(String fruit) {
        this.fruit = fruit;
    }

    public String getFruit() {
        return fruit;
    }

    @Override
    public boolean equals(Object other) {
        return other instanceOf Fruit && ((Fruit) other).fruit.equals(fruit);
    }

    @Override
    public int hashCode() {
        return fruit.hashCode();
    }
}

迭代器 class 相当陈旧,它的主要优点是您可以遍历并仍然使用 iterator.remove() 删除元素,这在 - statefull - for ( ConcurrentModificationException).

Predicate<List<Fruit>> containsApple = list -> {
    for (Fruit fruit: list) {
        if (fruit.getFruit().equals("Apple")) {
            return true;
        }
    }
    return false;
};

Predicate<List<Fruit>> containsApple = list -> list.contains(new Fruit("Apple"));

建议熟悉 Stream(如 for 遍历集合)及其表达能力。

Predicate<List<Fruit>> containsApple = list ->
    list.stream()
        .anyMatch(fr -> fr.getFruit().equals("Apple"));