我正在阅读playframework中的一些http webservice api,链接如下。
我无法理解这种嵌套如何使用flatmap。
有人可以给我一些提示,如何打击这一大块函数调用。
来自http://www.playframework.com/documentation/2.2.x/JavaWS
撰写结果
如果您想按顺序拨打多个电话,
这可以使用flatMap来实现:
public static Promise<Result> index() {
final Promise<Result> resultPromise = WS.url(feedUrl).get().flatMap(
new Function<WS.Response, Promise<Result>>() {
public Promise<Result> apply(WS.Response response) {
return WS.url(response.asJson().findPath("commentsUrl").asText()).get().map(
new Function<WS.Response, Result>() {
public Result apply(WS.Response response) {
return ok("Number of comments: " + response.asJson().findPath("count").asInt());
}
}
);
}
}
);
return resultPromise;
}
答案 0 :(得分:1)
flatMap
和map
是常见的Scala(或更常见的函数式编程)函数。它们都接受函数作为参数。为了将Play WS API转换为Java(以及其他所有内容),需要在Java中重新实现Scala的函数类型,以便您可以充分利用WS库。它在这里以与Scala编译器类似的方式完成。 Function<A,B>
是一种需要apply
方法的抽象类型。 apply
的参数是函数的参数,apply
的返回类型是函数的参数。
如果你在Java中有这个功能:
public String int2String(Integer integer) {
return integer.toString();
}
这相当于:
new Function<Integer, String>() {
public String apply(Integer integer) {
return integer.toString();
}
}
在一次WS调用的情况下,让我们开始更简单。 WS.url(...).get()
会返回Promise<WS.Response>
。 Promise
是承诺的值的容器类。为了处理它包含的值(或最终包含的值),我们需要使用map
函数。对于Promise<WS.Response>
,map
会接受Function<WS.Response, T>
作为参数,其中T
是您要将响应映射到的类型。
例如,让我们定义一个Function
,它只返回Play HTTP WS.Response
中Result
的正文:
Function<WS.Response, Result> echo = new Function<WS.Response, Result>() {
public Result apply(WS.Response response) {
return ok(response.asText());
}
}
现在让我们在控制器的WS调用中使用这个Function
:
public static Promise<Result> index() {
final Promise<Result> resultPromise = WS.url("http://google.com").get().map(echo);
return resultPromise;
}
完成Promise
后,之前定义的echo
函数将在map
内执行,并返回Promise<Result>
。前面两个代码块也可以这样编写(与匿名函数合并为一个):
public static Promise<Result> index() {
final Promise<Result> resultPromise = WS.url("http://google.com").get().map(
new Function<WS.Response, Result>() {
public Result apply(WS.Response response) {
return ok(response.asText());
}
}
);
return resultPromise;
}
作为一个粗略的例子,让我们说我们需要进行两次WS调用。第二个WS调用将取决于第一个。也许第一次调用会给我们一些URL,我们将使用它来进行第二次WS调用。
这是flatMap
出现的地方。我们需要两个函数来完成这个任务。第一个函数是传递给flatMap
的函数,它将在收到第一个WS.Response
时执行。第一个函数将使用第一个响应来进行第二个WS调用,该调用返回另一个必须映射的Promise<WS.Response>
以获得我们的最终结果。因此,我们map
第二个结果,第二个函数将WS.Response
转换为我们的Result
。
那发生了什么?如果我们在两个实例中都使用了map
而不是flatMap
,那么事件链将会是这样的:
第一个get()
返回Promise<WS.Response>
,然后我们map
包含WS.Response
到Promise<Result>
。但是,这会给我们留下Promise<Promise<WS.Response>>
,这不是很理想。在外部函数中使用flatMap
会将Promise
展平为单个Promise<Result>
。 Simiarly,如果你正在做3个或更多嵌套调用,你会map
每个结果都是一个内部函数,并且在外层只有一个flatMap
来压扁所有内容。
这一切当然在斯卡拉看起来更加美丽。