Java 符合分配律的谓词
Java Predicates with distributive law
我有一个布尔 Java 语句,其结构如下:
return A AND (B OR C OR D)
在Java中:
return A && (B || C || D);
我想通过使用链式谓词重新表述它,但似乎我必须使用布尔代数的分配律才能使其工作:
(A AND B) OR (A AND C) OR (A AND D) 这迫使我一直重复 A。
这就是我在 java 中得到的结果:
return A.and(B)
.or(A.and(C))
.or(A.and(D))
.test(params)
这似乎不会导致相同的结果,因为当我使用谓词版本时我的测试用例失败了。
在不使用分配律的情况下使用 Java 谓词是不可能的还是我做错了什么?
您可以完全按照自己的意愿编写声明:
A.and(B.or(C).or(D))
编辑:
以下是评论中的问题示例:
// here you tell Java that p1 is of type Predicate
// though you can use "and" and "or"
Predicate<String> p1 = s -> s.equals("foo");
p1.and(s -> !s.equals("bar"));
但您也可以使用相同的签名但不同的默认方法创建您自己的功能接口:
public interface MyCustomPredicate<T> {
boolean test(T value);
default MyCustomPredicate<T> and(MyCustomPredicate<? super T> other) {
return (t) -> true;
}
}
// ...
// here you tell Java that p2 is of type MyCustomPredicate
// though you can't use "or"
// and MyCustomPredicate.and does not behave the same as Predicate.and
MyCustomPredicate p2 = s -> s.equals("bar");
p2.and(s -> !s.equals("bar"));
它与 pre-lambda Java 有点不同。 Predicate.and
的签名表示它接受 Predicate
。但实际上这意味着它接受匹配 T -> boolean
.
的 any lambda
Predicate<String> p1 = s -> s.equals("foo");
MyCustomPredicate p2 = s -> s.equals("bar");
// this works because MyCustomPredicate has the same T -> boolean signature as Predicate
p1.or(p2);
您也可以内联转换 lambda:
Predicate<String> p3 = (s) -> true;
p3.and(((Predicate<String>) x -> true).and(x -> true));
总结:如果你只是写 s -> s.equals("bar")
Java 不知道这个 lambda 是 Predicate
还是任何其他具有相同签名的功能接口 T -> boolean
.
您需要使用括号
A.and(B.or(C).or(D));
这里是验证。
Function<Boolean[], Boolean> pred = ar -> {
Predicate<Boolean[]> A = a -> a[0];
Predicate<Boolean[]> B = b -> b[1];
Predicate<Boolean[]> C = c -> c[2];
Predicate<Boolean[]> D = d -> d[3];
return A.and(B.or(C).or(D)).test(ar);
};
Function<Boolean[], Boolean> java = arr -> {
boolean A = arr[0];
boolean B = arr[1];
boolean C = arr[2];
boolean D = arr[3];
return A && (B || C || D);
};
Random r = new Random();
for (int i = 0; i < 1_000_000; i++) {
Boolean[] b = Stream.generate(() -> r.nextBoolean())
.limit(4).toArray(Boolean[]::new);
if (java.apply(b) != pred.apply(b)) {
System.out.println("Different results");
}
}
由于您在构造谓词后立即对其求值,因此您可以对所有项求值:
return A.test(params)
&& (B.test(params) || C.test(params) || D.test(params));
这避免了创建几乎立即丢弃的对象。
我有一个布尔 Java 语句,其结构如下:
return A AND (B OR C OR D)
在Java中:
return A && (B || C || D);
我想通过使用链式谓词重新表述它,但似乎我必须使用布尔代数的分配律才能使其工作:
(A AND B) OR (A AND C) OR (A AND D) 这迫使我一直重复 A。
这就是我在 java 中得到的结果:
return A.and(B)
.or(A.and(C))
.or(A.and(D))
.test(params)
这似乎不会导致相同的结果,因为当我使用谓词版本时我的测试用例失败了。
在不使用分配律的情况下使用 Java 谓词是不可能的还是我做错了什么?
您可以完全按照自己的意愿编写声明:
A.and(B.or(C).or(D))
编辑:
以下是评论中的问题示例:
// here you tell Java that p1 is of type Predicate
// though you can use "and" and "or"
Predicate<String> p1 = s -> s.equals("foo");
p1.and(s -> !s.equals("bar"));
但您也可以使用相同的签名但不同的默认方法创建您自己的功能接口:
public interface MyCustomPredicate<T> {
boolean test(T value);
default MyCustomPredicate<T> and(MyCustomPredicate<? super T> other) {
return (t) -> true;
}
}
// ...
// here you tell Java that p2 is of type MyCustomPredicate
// though you can't use "or"
// and MyCustomPredicate.and does not behave the same as Predicate.and
MyCustomPredicate p2 = s -> s.equals("bar");
p2.and(s -> !s.equals("bar"));
它与 pre-lambda Java 有点不同。 Predicate.and
的签名表示它接受 Predicate
。但实际上这意味着它接受匹配 T -> boolean
.
Predicate<String> p1 = s -> s.equals("foo");
MyCustomPredicate p2 = s -> s.equals("bar");
// this works because MyCustomPredicate has the same T -> boolean signature as Predicate
p1.or(p2);
您也可以内联转换 lambda:
Predicate<String> p3 = (s) -> true;
p3.and(((Predicate<String>) x -> true).and(x -> true));
总结:如果你只是写 s -> s.equals("bar")
Java 不知道这个 lambda 是 Predicate
还是任何其他具有相同签名的功能接口 T -> boolean
.
您需要使用括号
A.and(B.or(C).or(D));
这里是验证。
Function<Boolean[], Boolean> pred = ar -> {
Predicate<Boolean[]> A = a -> a[0];
Predicate<Boolean[]> B = b -> b[1];
Predicate<Boolean[]> C = c -> c[2];
Predicate<Boolean[]> D = d -> d[3];
return A.and(B.or(C).or(D)).test(ar);
};
Function<Boolean[], Boolean> java = arr -> {
boolean A = arr[0];
boolean B = arr[1];
boolean C = arr[2];
boolean D = arr[3];
return A && (B || C || D);
};
Random r = new Random();
for (int i = 0; i < 1_000_000; i++) {
Boolean[] b = Stream.generate(() -> r.nextBoolean())
.limit(4).toArray(Boolean[]::new);
if (java.apply(b) != pred.apply(b)) {
System.out.println("Different results");
}
}
由于您在构造谓词后立即对其求值,因此您可以对所有项求值:
return A.test(params)
&& (B.test(params) || C.test(params) || D.test(params));
这避免了创建几乎立即丢弃的对象。