如何决定 Predicate "and" 方法在 java 中有消费者而不是生产者?
How was it decided that Predicate "and" method would have a consumer and not producer in java?
我正在研究 java 8 中引入的 Predicate class,它是函数式接口。
Predicateclass里面有一个方法,就是把多个谓词组合成一个
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
我已经在 java 中阅读了 PECS 的概念,但仍然无法理解为什么在谓词的情况下我们使用 ? 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));
}
}
Producer - 通过返回给你一个对象:T get()
该对象必须是 T
或其子类,因此它 extends
.
Consumer - 从您那里获取一个对象作为方法参数:void accept(T)
该方法可以采用更通用的类型,但不能要求更具体的类型,因此参数可以是 super
.
由于 Predicate boolean test(T)
方法将对象作为参数,因此它是一个消费者。
参考:What is PECS (Producer Extends Consumer Super)?
Predicate<T>
s 接受一个 T
并给你一个 boolean
。是的,它是 boolean
s 的生产者,但这与这里无关。 在类型参数上应用 PECS 时,您应该考虑该类型是该类型参数的生产者还是消费者.
由于Predicate<T>
接受T
,它是T
的消费者,所以T
参数应该是? super
。
另一个例子:BiFunction<T, U, V>
接受一个 T
和一个 U
,并产生一个 V
,所以它是 T
的消费者,T
的消费者U
,以及 V
的制作人。因此,T
对应 ? super
,V
对应 U
,? extends
。如您所见,只有类型参数很重要。该类型可能做的任何其他事情都不会。
如果翻转两侧 - predInt.and(pred)
,将允许使用这些线,这会创建一个 Predicate<Integer>
。
这是因为 and
被声明为产生与调用它的谓词相同类型的谓词,所以 pred.and(...)
只能产生一个 Predicate<Number>
,但是一个 Predicate<Number>
在这里没有意义 - 另一个合取只能接受整数!
你完全可以让它在两个订单中工作。如果将 and
声明为静态方法:
public static <T> Predicate<T> and(Predicate<? super T> a, Predicate<? super T> b)
那么你可以做这两个:
and(predInt, pred)
and(pred, predInt)
但这样可读性较差:(
的问题
Predicate<Number> pred = n -> n.intValue() > 2;
Predicate<Integer> predInt = n -> n > 3;
//Compile error
//pred.and(predInt);
是pred
接受Number
的所有子类(例如也Double
)但是predInt
只接受一个特定的子类(Integer
) .
因此下面的代码很好:
Number n = Double.valueOf(100);
System.out.println(pred.test(n));
但是下面的代码(如果能编译的话)会在运行时失败:
Number n = Double.valueOf(100);
System.out.println(pred.and(predInt).test(n));
由于引入泛型正是为了防止此类运行时故障,因此它必须防止代码编译(即产生编译错误)。
我正在研究 java 8 中引入的 Predicate class,它是函数式接口。 Predicateclass里面有一个方法,就是把多个谓词组合成一个
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
我已经在 java 中阅读了 PECS 的概念,但仍然无法理解为什么在谓词的情况下我们使用 ? 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));
}
}
Producer - 通过返回给你一个对象:T get()
该对象必须是 T
或其子类,因此它 extends
.
Consumer - 从您那里获取一个对象作为方法参数:void accept(T)
该方法可以采用更通用的类型,但不能要求更具体的类型,因此参数可以是 super
.
由于 Predicate boolean test(T)
方法将对象作为参数,因此它是一个消费者。
参考:What is PECS (Producer Extends Consumer Super)?
Predicate<T>
s 接受一个 T
并给你一个 boolean
。是的,它是 boolean
s 的生产者,但这与这里无关。 在类型参数上应用 PECS 时,您应该考虑该类型是该类型参数的生产者还是消费者.
由于Predicate<T>
接受T
,它是T
的消费者,所以T
参数应该是? super
。
另一个例子:BiFunction<T, U, V>
接受一个 T
和一个 U
,并产生一个 V
,所以它是 T
的消费者,T
的消费者U
,以及 V
的制作人。因此,T
对应 ? super
,V
对应 U
,? extends
。如您所见,只有类型参数很重要。该类型可能做的任何其他事情都不会。
如果翻转两侧 - predInt.and(pred)
,将允许使用这些线,这会创建一个 Predicate<Integer>
。
这是因为 and
被声明为产生与调用它的谓词相同类型的谓词,所以 pred.and(...)
只能产生一个 Predicate<Number>
,但是一个 Predicate<Number>
在这里没有意义 - 另一个合取只能接受整数!
你完全可以让它在两个订单中工作。如果将 and
声明为静态方法:
public static <T> Predicate<T> and(Predicate<? super T> a, Predicate<? super T> b)
那么你可以做这两个:
and(predInt, pred)
and(pred, predInt)
但这样可读性较差:(
Predicate<Number> pred = n -> n.intValue() > 2;
Predicate<Integer> predInt = n -> n > 3;
//Compile error
//pred.and(predInt);
是pred
接受Number
的所有子类(例如也Double
)但是predInt
只接受一个特定的子类(Integer
) .
因此下面的代码很好:
Number n = Double.valueOf(100);
System.out.println(pred.test(n));
但是下面的代码(如果能编译的话)会在运行时失败:
Number n = Double.valueOf(100);
System.out.println(pred.and(predInt).test(n));
由于引入泛型正是为了防止此类运行时故障,因此它必须防止代码编译(即产生编译错误)。