谓词中的运算符作为 lambda 表达式中的参数

operators in predicate as argument in lambda expression

我需要在 lambda 表达式中使用 Predicate 作为参数。我尝试了一个示例代码,但看到编译器错误。 我看到编译器针对不同的参数以不同的方式处理相同的谓词。所以谓词参数 n -> true and n -> false 有效,但 n -> n%4 == 0 无效。

编译错误为:

The operator % is undefined for the argument type(s) Object, int

我修复了它(请参阅下面的替换代码)但我想问我是否必须修复它,为什么?我不确定我是否遗漏了一些基本的东西。

完整代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class PredicateAsArgumentInLambdaExpression {

        public static int add(List<Integer> numList, Predicate predicate) {
            int sum = 0;
            for (int number : numList) {
                if (predicate.test(number)) {
                    sum += number;
                }
            }
            return sum;
        }

        public static void main(String args[]){
            List<Integer> numList = new ArrayList<Integer>();
            numList.add(new Integer(10));
            numList.add(new Integer(20));
            numList.add(new Integer(30));       
            numList.add(new Integer(40));       
            numList.add(new Integer(50));

            System.out.println("Add Everything: "+add(numList, n -> true));
            System.out.println("Add Nothing: "+add(numList, n -> false));
//          System.out.println("Add Less Than 25: "+add(numList, n -> n < 25)); Compiler says: The operator < is undefined for the argument type(s) Object, int
            System.out.println("Add Less Than 25: "+add(numList, n -> Integer.valueOf((int)n) < Integer.valueOf("25")));
//          System.out.println("Add 4 Multiples: "+add(numList, n -> n % 4 == 0)); //Compiler says: The operator % is undefined for the argument type(s) Object, int
            System.out.println("Add 4 Multiples: "+add(numList, n -> Integer.valueOf((int)n) % Integer.valueOf("4")==0));
        }
}

注释掉的代码是无效的,每行下面的行是替换代码。该代码按原样和预期工作,但我希望注释掉的代码应该工作!这里的 java.util.function.Predicate 中的 Predicate 有什么问题?如果您在

中找到答案,请为规格页面提供任何 link

发生的事情是您正在使用 raw java.util.function.Predicatetest() 方法如下所示:

public void test(Object o) { ... }

这就是您得到编译时错误的原因:参数类型为 Object 并且数字运算符(<>)不适用于类型 Object

但是,如果您使用类型参数为 Integer 的泛型 java.util.function.Predicatetest() 方法将如下所示:

public void test(Integer i) { ... }

在这种情况下,数字运算符 (><) 对于提供的参数类型 (Integer) 是有效的,不需要强制转换。

此外,我利用 Java8 中的 Stream API 来缩短您的方法实现:

public static int add(List<Integer> numList, Predicate<Integer> predicate) {
     return numList.stream().filter(predicate).mapToInt(i -> i).sum();
}

有了这样的方法实现,现在所有这些陈述将完全有效:

System.out.println("Add Everything: "+add(numList, n -> true));
System.out.println("Add Nothing: "+add(numList, n -> false));
System.out.println("Add Less Than 25: "+add(numList, n -> n < 25));
System.out.println("Add 4 Multiples: "+add(numList, n -> n % 4 == 0));  

您忽略了 add 方法中的通用参数。如果您从一般 Predicate 切换到 Predicate<Integer>,则 n 将在操作前自动转换为 Integer

简而言之,而不是:

public static int add(List<Integer> numList, Predicate predicate) {

你应该试试:

public static int add(List<Integer> numList, Predicate<Integer> predicate) {

之后,您之前的代码:

n -> Integer.valueOf((int)n) < Integer.valueOf("25")
n -> Integer.valueOf((int)n) % Integer.valueOf("4")==0

可以简单地

n -> n < 25
n -> n % 4 == 0

效率更高。

这只是将方法期望的内容与您提供的内容相匹配的问题。由于没有通用术语,Java 期望 Predicate 默认接收类型 Object,并且由于 Integer 扩展了 Object,它假定这是您的类型正在过去。有了它,它期望 Integer,并且与 Integer 关联的所有方法和运算符都被公开。

这是一个有点不可见的操作,它发生在您的方法被调用之前,这就是为什么您的警告出现在 lambda 操作而不是方法中。

祝你好运!