我有以下代码,它使用了很好的旧java:
List<Bar> repo = ArrayList<>();
public Bar foo(int id) {
for(Bar c: repo){
if(c.getId() == id)
return c;
}
Bar target = new Bar();
target.setFooo("");
target.setId(0);
return target;
}
然而,我试图让它变得更好一点,(即只是想学习lambdas)
public Bar foo(int id) {
Bar target = repo.stream().filter(c -> c.getId() == id)
.findFirst().orElse(null);
if(target == null){
target = new Bar();
target.setFooo("");
target.setId(0);
}
return target;
}
但上面的代码返回ArrayOutOfBounds
异常,我不确定如何(因为它是一个列表)或为什么。
答案 0 :(得分:6)
如果要使用函数式编程技术,最好重构代码,以便能够使用构造函数,构建器或工厂方法完全构造对象。塞特斯是坏朋友,因为他们暗示可变性和功能编程喜欢不可改变的东西。
所以添加新的Bar
构造函数:
public Bar(String fooo, int id) {
this.fooo = fooo;
this.id = id;
}
在此之后您可能会意识到所有Bar
对象都可以在没有setter的情况下使用。如果是这样,您只需删除setter并将Bar
字段设为final,这样Bar
将变为不可变。即使你无法摆脱其他地方的setter,拥有新的构造函数,你的foo
方法也可以用更清晰的方式重写:
public Bar foo(int id) {
return repo.stream()
.filter(c -> c.getId() == id)
.findFirst()
.orElseGet(() -> new Bar("", 0));
}
答案 1 :(得分:1)
你的解决方案非常接近我的建议:
public Bar foo(int id) {
return repo.stream()
// find by id
.filter(c -> c.getId() == id)
// choose any
.findAny()
.orElseGet(() -> {
target = new Bar();
target.setFooo("");
target.setId(0);
return target;
});
}
不要创建更复杂的构造函数。它们甚至经常被称为反模式。坚持你的二传手!
如果要优化,请让您的setter返回更新的对象。这种方法将来允许添加任意数量的setter。那看起来像那样:
public Bar setFooo(String fooo) {
this.fooo = fooo;
return this; // return modified instance
}
// do the same for setId()
稍后在代码中:
.orElseGet(() -> new Bar()
.setFooo("")
.setId(0)
// add any number of future setters here
);