主题 - lambda 表达式,在模式的上下文中,责任链。我在网上遇到了这段代码:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@FunctionalInterface
interface RequestHandler {
public abstract Request handle(Request r);
default RequestHandler setSuccessor(RequestHandler other) {
return (req) -> { //req - it's request
System.out.println("req instance of: " +req.getClass().getName());
return other.handle(this.handle(req));
};
}
}
public class Request {
String data;
public String getData() {
return data;
}
public Request(String data) {
this.data = data;
}
}
更详细地说——有一个类Request
——它只包含一行,带有一个构造函数和一个 getter。有一个接口RequestHandler
——它是一个请求处理程序。它有一个抽象方法handle
——用于 lambda 表达式。还有一种方法setSuccessor
——进行更深层次的操作。这是setSuccessor
我想知道的方法。为什么它会编译?通过签名,它应该返回 RequestHandler,但在第一个返回 (req) 中 - 我发现 req 只是请求。(这行代码 System.out.println("req instance of: " +req.getClass().getName());
说的是 Request 的 req 实例) 第二个return other.handle(this.handle(req));
,不管怎么说,返回值也是 Request,而不是 RequestHandler!例如,表达式 RequestHandler r = other.handle(this.handle(req));
- 表示类型不兼容。
摘要问题:该方法在哪里和哪一行setSuccessor
设法返回了一个接口对象RequestHandler
?
了解什么是功能接口。要成为
RequestHandler
,您需要提供一个带有类型参数Request
和类型返回值的方法Request
。这来自签名handle
。一个 lambda 表达式(req) -> {...}
,粗略地说,用这种方法定义了一个匿名对象。正如您正确指出的那样,参数req
是 typeRequest
,花括号内的返回值也是 typeRequest
。事实证明,这个对象满足要求RequestHandler
。是的,确实java可以返回一个“接口对象”,即使这样的“对象”没有在返回方法的任何地方显式创建。“接口对象”——我用引号括起来,因为我们仍然指的是由接口引用控制的特定(通常是匿名)类的对象。
在 java 8 之前,方法可以返回接口的“对象”,如下所示:
在 java 8 发布之后,为了创建一个“接口对象”,我们仍然需要声明某种方法实现。但如果接口中只有一个抽象,则可以使用 lambda 表达式来完成:
发生了什么魔法
x-> 25
?就 lambda 表达式而言,我们给出了 f(x) = 25;f(x) 是抽象方法的具体实现doSomething(int x)
;编程语言将其理解为“从方法m()
返回一个具体的实现Marker
,这样它的唯一抽象方法doSomething(int x)
将返回一个常量{return 25;};
。也就是说,事实上,要创建一个“功能接口对象”,只需实现它的抽象 lambda 方法就足够了用表达式:回到方法:
这里有人说“抽象句柄方法的实现(取决于请求参数)是这样的”:
此外,该方法安全地返回了一个带有该方法特定实现的“接口对象”RequestHandler。