关闭不可变变量并在多个迭代中累积值作为lambda表达式 - Java 8

时间:2016-08-30 11:56:56

标签: java lambda java-8 immutability

Jersey客户端中的WebTarget是作为不可变对象实现的,任何更改状态的操作都会返回一个新的WebTarget。要向Map<>添加查询参数,请编写以下代码。

public WebTarget webTarget(String path, Map<String, String> queryMap) {

    WebTarget webTarget = client.target(this.address.getUrl()).path(path);
    if (queryMap != null)
        queryMap.entrySet().forEach(e -> webTarget.queryParam(e.getKey(), e.getValue()));
    return webTarget;
 }

这里的问题是对.queryParam()的每次调用都会返回一个新的WebTarget,而我仍然坚持如何累积,因为lambda表达式中使用的变量必须是final或implicit final,而不需要任何重新分配。

修改: 在这种情况下,Reduce可能不是一个选项,因为WebTarget缺少减少机制,我无法从一个webtarget获取queryParam并将其设置为另一个。如果WebTarget api有更好的支持积累,它可能已被使用。

使用Jool尝试利用本地Java 8 API中缺少的foldLeft,但由于WebTarget api缺乏对它的支持,但仍然触底。

EDIT2 :foldLeft就像下面的答案中建议的那样,在这个上写了一个小的blog

2 个答案:

答案 0 :(得分:2)

如果你想要功能性方法,你需要foldLeft(右)或reduce。

foldLeft已在某些库中实施,例如FunctionaljavastreamEx

Functionaljava:

<B> B foldLeft(final F<B, F<A, B>> bff, final B z)

WebTarget wt = wtCollection.foldLeft(x -> (y -> x.queryParam(...)), new WebTarget());

StreamEx:

<U> U foldLeft(U seed, BiFunction<U, ? super T, U> accumulator) 

<强> UPD 流减少

queryMap.entrySet().stream()
    .reduce(new WebTarget(), (x, y) -> { 
        x.queryParam(y.getKey(), y.getValue()); 
    });

答案 1 :(得分:1)

你可以使用ol&#39;数组技巧,除了概念验证之外的任何东西都不好。

WebTarget[] webTarget = {client.target(this.address.getUrl()).path(path)};
if (queryMap != null){
    queryMap.forEach((k, v)->{
        webTarget[0] =  webTarget[0].queryParam(k, v);
    });
}
return webTarget[0];

您可以使用AtomicReference来改进它。

AtomicReference<WebTarget> webTarget = new AtomicReference<>(client.target(this.address.getUrl()).path(path));
if (queryMap != null){
    queryMap.forEach((k, v)->{
        webTarget.updateAndGet(w->w.queryParam(k, v));
    });
}
return webTarget.get();