【问题标题】:operators in predicate as argument in lambda expression谓词中的运算符作为 lambda 表达式中的参数
【发布时间】:2023-03-04 12:07:01
【问题描述】:

我需要在 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 有什么问题?如果您在其中找到答案,请提供规范页面的任何链接。

【问题讨论】:

  • Predicate&lt;Integer&gt;怎么样?
  • @user3320018 你什么意思? n -&gt; truen -&gt; falsePredicate&lt;Integer&gt; 一起工作对我来说很好。
  • @user3320018:看看kocko的回答,他告诉你如何使用Predicate&lt;Integer&gt;
  • @user3320018 "n -&gt; truen -&gt; false 的情况下没有编译器错误" 你想在这些情况下得到编译器错误吗?如果是,为什么?如果不是,那是什么问题(它工作正常)?
  • “为什么对我的问题投了反对票”我猜有人不喜欢你的问题是由原始类型引起的这一事实,在每个关于泛型的教程中都有解释。跨度>

标签: java lambda type-conversion java-8 predicate


【解决方案1】:

发生的情况是您正在使用 raw java.util.function.Predicatetest() 方法看起来像这样:

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

这就是您收到编译时错误的原因:参数类型为Object,而数字运算符(&lt;&gt;)不适用于Object 类型。

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

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

在这种情况下,数字运算符(&gt;&lt;)对提供的参数类型(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));  

【讨论】:

  • 我用你的方法替换了我的方法,但看到编译器错误:The method sum() is undefined for the type Stream&lt;Integer&gt;
  • 作为替代 IntPredicate 可以用于原始 int 类型。
  • @user3320018,您在提供的代码 sn-p 中没有任何流 API,因此我们不太可能帮助您解决这个问题的编译器错误。
【解决方案2】:

您忽略了 add 方法中的泛型参数。如果从普通的Predicate切换到Predicate&lt;Integer&gt;,那么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 操作而不是方法中的原因。

祝你好运!

【讨论】:

  • 如果我使用&lt; 运算符并给出double 进行比较,它会起作用吗?或任何其他类型。 Predicate 似乎有限制不是吗?
  • 绝对可以。查找“自动装箱”。 DoubleInteger 都扩展了 Number,所以你被覆盖了;此外,您不能将泛型定义为像int 这样的原始类型,因为它们在Java 中完全是它们自己的类。这样您就不会受到任何限制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多