[英]Java 8 list processing - add elements conditionally
我有以下代码:
List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;
是否有一种很好的方式有条件地添加元素,可能使用流操作? 我想只在列表为空时添加来自method2的元素,否则返回等等。
编辑:值得一提的是,这些方法包含大量逻辑,因此需要防止执行。
您可以尝试检查addAll
的返回值。 每当修改列表时它都会返回true
,所以试试这个:
List<Object> list = new ArrayList<>();
// ret unused, otherwise it doesn't compile
boolean ret = list.addAll(method1())
|| list.addAll(method2())
|| list.addAll(method3())
|| list.addAll(method4())
|| list.addAll(method5())
|| list.addAll(method6());
return list;
由于延迟评估,添加至少一个元素的第一个addAll
操作将阻止其余的被调用。 我喜欢“||”的事实 很好地表达了意图。
我只是使用供应商流并过滤List.isEmpty
:
Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.ifPresent(list::addAll);
return list;
当其中一个方法返回第一个非空列表时, findFirst()
将阻止对methodN()
不必要调用。
编辑:
正如下面的评论所述,如果你的list
对象没有用其他任何东西初始化,那么直接返回流的结果是有意义的:
return Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.orElseGet(ArrayList::new);
一种不重复自己的方法就是提取一个为你做的方法:
private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}
然后
List<Object> list = new ArrayList<>();
addIfEmpty(list, this::method1);
addIfEmpty(list, this::method2);
addIfEmpty(list, this::method3);
addIfEmpty(list, this::method4);
addIfEmpty(list, this::method5);
addIfEmpty(list, this::method6);
return list;
甚至使用for循环:
List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));
现在DRY不是最重要的方面。 如果您认为原始代码更易于阅读和理解,那么请保持原样。
您可以通过创建方法使您的代码更好
public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
if(list.isEmpty()){
list.addAll(method.get());
}
}
然后你可以像这样使用它(我假设你的方法不是静态方法,如果你需要使用ClassName::method1
引用它们)
List<Object> list = new ArrayList<>();
list.addAll(method1());
addAllIfEmpty(list, this::method2);
addAllIfEmpty(list, this::method3);
addAllIfEmpty(list, this::method4);
addAllIfEmpty(list, this::method5);
addAllIfEmpty(list, this::method6);
return list;
如果你真的想使用Stream,你可以这样做
Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
.collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);
IMO使它变得更复杂,取决于你的方法被引用的方式,使用循环可能更好
你可以这样创建一个方法:
public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
.findFirst()
.orElseGet(Collections::emptyList);
}
然后按如下方式调用它:
lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());
方法名称仅用于说明目的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.