关闭不可变变量并将值作为lambda表达式在多个迭代中累积-Java 8
Jersey客户端中的WebTarget是作为不可变对象实现的,任何更改状态的操作都会返回一个新的WebTarget。要向其中添加查询参数(作为关闭不可变变量并将值作为lambda表达式在多个迭代中累积-Java 8,java,lambda,java-8,immutability,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 (q
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;
}
publicWebTargetWebTarget(字符串路径,映射查询映射){
WebTarget WebTarget=client.target(this.address.getUrl()).path(path);
if(queryMap!=null)
forEach(e->webTarget.queryParam(e.getKey(),e.getValue());
返回webTarget;
}
这里的问题是每次调用.queryParam()
都会返回一个新的WebTarget,我一直在思考如何累积,因为lambda表达式中使用的变量必须是final或隐式final,而不需要任何重新分配
编辑:
在这种情况下,Reduce可能不是一个选项,因为WebTarget缺少Reduce机制,我无法从一个WebTarget获取queryParam并将其设置到另一个WebTarget。如果WebTargetAPI对累加有更好的支持,就可以使用它
用于尝试和利用原生Java8API中缺少的foldLeft,但由于WebTargetAPI缺乏对它的支持,它仍然处于谷底
EDIT2:foldLeft是下面答案中建议的方法,你可以在上面写一个小的你可以使用ol'数组技巧,这除了概念证明之外,对任何事情都没有好处
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<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();
AtomicReference webTarget=新的AtomicReference(client.target(this.address.getUrl()).path(path));
if(queryMap!=null){
查询映射forEach((k,v)->{
updateAndGet(w->w.queryParam(k,v));
});
}
返回webTarget.get();
如果您想要功能性方法,您需要折叠(右)或缩小
foldLeft
在一些库中实现,例如和
功能Java:
<B> B foldLeft(final F<B, F<A, B>> bff, final B z)
WebTarget wt = wtCollection.foldLeft(x -> (y -> x.queryParam(...)), new WebTarget());
猜一猜像foldLeft这样的带有零值的WebTarget,它携带状态,尽管迭代可能会有所帮助!!!我们是否有一种使用java-8执行foldLeft的机制看看除了
forEach
之外的其他API方法。另一个好的起点是。使用普通循环<代码>for(条目e:queryMap)webTarget=webTarget.queryParam(…)代码>在我看来很好…对不起,我正在寻找一种正确的方法。似乎用对方付费的方式会很好地完成这项工作。对方付费似乎不是最好的。我想说一个普通的循环是最合适的。另外,当后来有人说“嘿,我可以并行运行这个流”时,你的代码会被微妙地破坏,可能会在没有任何警告的情况下给出错误的答案。好把戏!你真的在那个愚蠢的编译器上加了一个。使用reduce
,这就是它的目的。@Holger在任何情况下,一个arg数组的技巧都是不合理的——正如第一位评论员所指出的,有数百万开发人员愿意利用这个“聪明”的技巧来“愚弄”编译器,在这个过程中胜过他们自己和他们的维护人员。(如果你要这样做,至少使用一个AtomicRef。)所以我的评论更像是“永远不要这样做”,而不是对特定代码的评论。@matt:或者,你写queryMap.forEach((k,v)->{webTarget.updateAndGet(w->w.queryParam(k,v));})代码>(注意)代码>结尾),或者您编写queryMap.forEach((k,v)->webTarget.updateAndGet(w->w.queryParam(k,v));
(不带花括号)。您现在编写的方式是无效语法。如果我理解正确,streamx解决方案应该类似于:webTarget=streamx.of(queryMap.entrySet().stream()).foldLeft(webTarget,(w,e)->w.queryParam(e.getKey(),e.getValue());
如果(queryMap!=null){…}
分支,则必须将其放入中。有趣的技术,谢谢!
<U> U foldLeft(U seed, BiFunction<U, ? super T, U> accumulator)
queryMap.entrySet().stream()
.reduce(new WebTarget(), (x, y) -> {
x.queryParam(y.getKey(), y.getValue());
});