我有以下代码:
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添加元素,否则返回等等。
编辑:值得一提的是,这些方法包含沉重的逻辑,因此需要阻止其执行。
答案 0 :(得分:67)
您可以尝试检查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
操作添加了至少一个元素将阻止其余的调用。我喜欢“ ||”的事实表达意图很好。
答案 1 :(得分:45)
我只使用供应商流并在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);
答案 2 :(得分:17)
一种无需重复自己的方法是提取一种为您执行的方法:
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));
现在,干燥不是最重要的方面。如果您认为您的原始代码更易于阅读和理解,请保持原样。
答案 3 :(得分:11)
您可以通过创建方法使代码更好
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使它变得更加复杂,具体取决于如何引用您的方法,使用循环可能会更好。
答案 4 :(得分:6)
您可以这样创建一个方法:
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());
方法名称仅用于说明目的。