Java 8谓词

时间:2018-07-08 07:39:16

标签: java generics lambda java-8

这是一个以谓词为参数的示例方法:

CloseWindow

我将上述函数称为:

void processFields(List<WebDataField> fields, Predicate<WebDataField> predicate) {
    for (WebDataField webDataField : fields) {
        boolean expectedCondition = predicate.test(webDataField);
    }
}

另一个功能:

processFields(fields, w -> w.getFieldName().length() > 5);

在调用方,将这样调用doSomething()方法–

public void doSomething(Object someObject,Predicate<T> predicateInstance){
    //doSomething method's code goes here
}

我检查了Java 8文档中的String / Integer / Object等,但没有发现实现doSomething(someObjectInstance, Integer i-> i>10) 接口的这些类中的任何一个。我不知道我在Java 8教程系列中错过了什么,但是我无法得到这种现象:

  1. 如果目标类型与Predicate类没有直接关系,编译器如何允许lambda表达式?

  2. 以上两种情况的答案都一样吗?

2 个答案:

答案 0 :(得分:1)

lambda表达式(Integer i) -> i>1的值不是Integer,因此Integer不必实现Predicate就可以传递该lambda表达您的方法。

Integer是lambda表达式的参数i的类型。 (Integer i) -> i>1可以表示具有单个方法的任何功能接口,该方法采用Integer自变量并返回boolean。因此,它适合Predicate<Integer>功能界面。

您的其他lambda表达式-w -> w.getFieldName().length() > 5-接受未指定类型的参数,并返回boolean。为了使其能够通过编译,编译器必须将w的类型推断为具有getFieldName()方法的某个类或接口,该类或接口将返回具有length()方法的某种类型的实例。当您将lambda表达式传递给需要processFields的{​​{1}}方法时,编译器可以推断出lambda表达式的参数Predicate<WebDataField>的类型为w

答案 1 :(得分:1)

回答第一个问题:
上面的lambda表达式i-> i>10是表达以下内容的较短方法:

Predicate<Integer> predicate = new Predicate<Integer>() {

  @Override
  public boolean test(Integer i) {
    return i > 10;
  }
};

随后将如下使用:

Integer someObjectInstance = 1;
doSomething(someObjectInstance, predicate);

因此目标类型(Integer)具有“ 与谓词直接连接”。

继续第二个问题:
Predicate<T>上,Tgeneric类型的参数。泛型类型参数仅接受引用类型,而不接受原始类型。因此,Predicate<T> p始终必须具有类型为T的对象实例作为参数(您称其为 someObjectInstance )。如果您想测试Integer,请按照以下方式进行操作:

Integer someObjectInstance = 1;
doSomething(someObjectInstance, i-> i>10);

但是,如果您尝试使用原始类型整数(int)调用该方法,则会出现语法错误:

int integer = 0;
worker.doSomething(integer, i -> i > 10); // The operator > is undefined for the argument type(s) Object, int

但是您可以通过显式提供泛型类型参数来帮助编译器。在这种情况下,它是Integer,即int的相应包装类型。这将因为autoboxing而起作用。

int integer = 0;
worker.<Integer> doSomething(integer, i -> i > 10);

但是您说的是“ 字符串/整数/对象等...没有找到实现谓词的所有此类”。对于原始类型,有专用的谓词接口。例如:IntPredicate
但是他们没有扩展接口Predicate<T>。这是不可能的,因为IntPredicate extends Predicate<int>之类的定义无效。如上所述,int作为通用类型参数是不可接受的。

要使用IntPredicate,可以声明一个方法

  public <T> void doSomething(int i, IntPredicate intPredicate) {
    // doSomething method's code goes here
  }

并这样称呼它:

doSomething(integer, i -> i > 10);

要获得不同谓词接口的概述,请查看软件包java.util.function reference