Lambda表示法 - 尝试重构但遇到问题

时间:2015-03-18 14:05:02

标签: java playframework lambda java-8

我有许多映射到服务器请求的方法。请求使用promises(来自Play Framework)在将来的某个时间返回响应。以下是我的一个行动示例:

public static Promise<Result> someAction() {
    MyBean data = new MyBean(getData(request().body()));
    Promise<MyReq> promise = Promise.promise(() -> new MyReq(data));
    return promise.map((MyReq req) -> ok(req.getResponse()));
}

请注意,MyReq扩展了MyAbstractReq<T>

我希望能够从所有操作方法中获取所有常用代码,并将其捆绑到单个通用handleRequest方法中。但是我很难理解Lambda Notation并且无法修改代码以适合我的目的。

我理解() -> new MyReq(data)基本上意味着(arg1, arg2, ...) -> { body },可以写成(我认为):

MyBean data = new MyBean(getData(request().body()));

// Anonymous Functional Interface
MyFunction f = new MyFunction() {      
    @Override
    public void getReq(){
        return new MyReq(data);
    }
};

或类似的东西。

但是我想要实现的是这样的事情(不编译,但我希望它足以让我知道我想要实现的目标):

public static Promise<Result> handleRequest(MyAbstractReq<?> req) {
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req);
    return promise.map(() -> ok(req.getResponse()));
}

每个动作都是这样的:

public static Promise<Result> someAction() {
    MyBean data = new MyBean(getData(request().body()));
    return handleRequest(new MyReq(data));
}

有人可以指出我对Lambda表示法缺少什么,并解释我如何能够实现我想要做的事情。

更新

我得到的错误是

  

Lambda expression's signature does not match the signature of the functional interface method apply(? super MyAbstractReq<?>)

我猜这是因为语法错误,这只是我第一次尝试重构它。

req.getResponse()方法并不真正相关,因为它只生成一个Json对象(ObjectNode - Jackson更快的xml),ok()方法可以使用它来创建Result

更新2

关于使用handleRequest(MyAbstractReq<T> req)我最初实际上有这个,但错误基本相同。

  

Lambda expression's signature does not match the signature of the functional interface method apply(? super MyAbstractReq<T>)

更新3

请原谅。错误在return promise.map(() -> ok(req.getResponse()));

更新4

我可能应该提到我知道如何通过将handleRequest()方法更改为:

来解决问题
public static Promise<Result> handleRequest(MyAbstractReq<?> req) {
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req);
    return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse()));
}

但感觉不对,因为第return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse()));行采用了从未使用的MyAbstractReq<?>参数。

我对Lambda表达式的符号知之甚少,不知道这是不是达到我想要的最佳方式(我没有提及它,因为我想看看如果没有我引导他们,人们的建议是什么回答)。

2 个答案:

答案 0 :(得分:2)

在您的初始代码中

public static Promise<Result> someAction() {
    MyBean data = new MyBean(getData(request().body()));
    Promise<MyReq> promise = Promise.promise(() -> new MyReq(data));
    return promise.map((MyReq req) -> ok(req.getResponse()));
}

一切都按预期工作,map获取一个函数,指定如何处理参数req。但是在重构的代码中,您突然尝试从外部作用域访问变量,而不是保留逻辑:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) {
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req);
    // the following function refers to handleRequest’s parameter instead of its argument
    return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse()));
}

这适用于这种特殊情况,但确实和你的感觉一样错误。

请坚持原始逻辑:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) {
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req);
    // arg is unrelated to req here though both variables happen to have to same contents
    return promise.map(arg -> ok(arg.getResponse()));
}

但它仍然有点奇怪,因为promise是围绕一个已经存在的对象构建的,而不是构造它。也许你想要

public static Promise<Result> handleRequest(Function0<MyAbstractReq<?>> supplier) {
    Promise<MyAbstractReq<?>> promise = Promise.promise(supplier);
    return promise.map(arg -> ok(arg.getResponse()));
}

所以你可以像

一样调用它
handleRequest( ()-> new MyReq(new MyBean(getData(request().body()))) );

然后Promise将真正涵盖整个操作。

答案 1 :(得分:2)

现在,在您的更新2之后,您已经提出了以下方法:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) {=
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req);
    return promise.map((MyAbstractReq<?> notUsed) -> ok(req.getResponse()));
}

在继续讨论之前,让我解释一下map()的作用。在给定的Iterable上,map()将简单地将每个元素转换为其他元素(可能是从元素中提取的内容)。为此,我们将Function传递给map()方法,该方法接受输入并返回输出。

在这种情况下,(MyAbstractReq<?> notUsed) -> ok(req.getResponse())就是那个功能。您将notUsed作为参数(这是promise中的一个元素,并在响应该对象时调用ok()方法。

但是你看,你没有使用你传递的参数,而是使用另一个对象(你作为handleRequest()方法的参数传递的那个。这是错误的。你应该使用notUsed.getResponse()那里。

此外,您不需要在那里提供notUsed类型。 Java可以推断出类型。因此,将您的方法更改为:

public static Promise<Result> handleRequest(MyAbstractReq<?> req) {=
    Promise<MyAbstractReq<?>> promise = Promise.promise(() -> req);
    return promise.map(promReq -> ok(promReq.getResponse()));
}