Java 8函数式接口赋值上下文

10

这个问题涉及到函数接口的赋值语境 -

Predicate<String> p = String::isEmpty;

在String类中,isEmpty方法声明如下:public boolean isEmpty(){}。这个方法可以正常工作。

如果我尝试在自定义类中声明相同的方法,代码如下 -

class Test{
   public boolean isEmpty(){
       ...
   }
}

同时进行相同的赋值操作 -

Predicate<String> p = Test::isEmpty;

这将是编译错误 -

类型Test未定义可用于此处的isEmpty(String)

Predicate<T>表示一个带有一个参数的谓词(布尔值函数),其功能方法为boolean test(T t){}

需要解释吗?我有漏掉什么吗?


很简单:类不是接口,因此它不能成为函数式接口。 - Brian Goetz
4个回答

11

你应该拥有:

Predicate<Test> p = Test::isEmpty;

而不是

Predicate<String> p = Test::isEmpty;

没有字符串在

class Test {
    public boolean isEmpty(){
           ...
    }
}

那么为什么需要 Predicate<String>

请参阅方法引用的教程。这里讨论的是第三种情况,即“特定类型任意对象的实例方法引用”。

有了它,您可以使用更简洁的代码来表示某些逻辑,例如在集合中过滤元素。

Predicate<String> p = String::isEmpty();
String s = "";

调用 p.test(s); 和调用 s.isEmpty(); 相同,所以你不能将一个 String 作为参数传递给从 Test 调用的方法。

如果 StringTest 都实现了一个叫做 Empty 的接口,并有一个方法 boolean isEmpty(),那么就可以拥有一个共用的 Predicate,然后使用 Predicate<Empty>。这样,p.test(string)p.test(test) 都能正常工作;否则就不行,因为 Java 具有强类型,而不支持鸭子类型。


4
方法引用可以有几种用法。它可以捕获要调用的实例。它可以引用应在功能接口提供的参数上调用的方法(您的第一个示例)。它也可用作调用目标,其中将函数接口中的参数作为参数传递给所引用的方法的调用(您的第二个示例)。 Predicate 接受您的通用类型参数的参数。您提供的方法引用必须能够对其执行某些操作。

你能告诉我函数式接口赋值背后的编译逻辑吗? - Subhrajyoti Majumder
@sub 它在JLS中,链接为(http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13.1)。请查看第二点。 - Sotirios Delimanolis

2
我想添加@m3th0dman的回答。
您可以使用Test类的方法引用来定义Predicate。实现方式是将isEmpty方法定义为静态方法,并具有String参数。
public class Test
{

  public static boolean isEmpty (String s)
  {
    return s.length() == 0;
  }

  public static void main (String[] args)
  {
      Predicate<String> p = Test::isEmpty;
      System.out.println(p.test("ff"));
      System.out.println(p.test(""));
  }

}

0

当您使用 Predicate<String> 时,只有 String 的方法引用是可接受的。
要给出 Test 类的方法引用,您需要使用 Predicate<Test>
因此代码应该是:

Predicate<Test> p = Test::isEmpty;

而不是

Predicate<String> p = Test::isEmpty;

为了更清晰地阐述我的观点,请考虑以下代码:-
public static void main(String args[]){
    Predicate<String> p;
    p = String::isEmpty;
    Predicate<Test> q;
    q = Test::isEmpty;
}

interface Predicate<T>{
    public boolean test(T t);
}

class Test{
    public boolean isEmpty(){
        return true;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接