是如何决定谓词“和”方法在java中拥有消费者而不是生产者的?
我正在浏览 java 8 中引入的 Predicate 类,它是函数式接口。Predicate 类中有一个方法和方法,用于将多个谓词组合成一个。
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
我已经阅读了 Java 中 PECS 的概念,但仍然无法理解为什么在 Predicate 的情况下我们使用? super T. Java 程序员如何决定它将成为消费者而不是生产者。
我的意思是为什么不允许出现编译错误的行:
public class PredicateExample {
public static void main(String[] args) {
Predicate<Number> pred = n -> n.intValue() > 2;
Predicate<Integer> predInt = n -> n > 3;
//Compile error
//pred.and(predInt);
Predicate<Object> predObj = o -> Integer.parseInt(o.toString()) > 4;
pred.and(predObj); //Valid statement
Number n = new Integer(100);
System.out.println(pred.and(predObj).test(10));
System.out.println(predInt.and(pred).test(10));
//Compile error
//System.out.println(pred.and(predInt).test(10));
}
}
回答
Predicate<T>s 接受一个T并给你一个boolean。是的,它是booleans的生产者,但这在这里并不重要。在对类型参数应用 PECS 时,您应该考虑该类型是该类型参数的生产者还是消费者。
由于Predicate<T>接受 a T,它是 的使用者T,因此它应该? super用于T参数。
另一个例子:BiFunction<T, U, V>接受 aT和 a U,并产生 a V,所以它是 的消费者T、 的消费者U和 的生产者V。因此,? super对于T和U,? extends对于V。如您所见,只有类型参数很重要。该类型可能会做的任何其他事情,不会。
如果您翻转两侧 - predInt.and(pred),则将允许这些行,这会创建一个Predicate<Integer>.
这是因为and被声明为产生与它被调用的谓词类型相同的谓词,所以pred.and(...)只能产生 a Predicate<Number>,但 aPredicate<Number>在这里没有意义 - 另一个连接词只能接受整数!
你可以完全让它在两个订单中工作。如果您声明and为静态方法:
public static <T> Predicate<T> and(Predicate<? super T> a, Predicate<? super T> b)
然后你可以做这两个:
and(predInt, pred)
and(pred, predInt)
但这样可读性较差:(