una - lista jframe java
Procesamiento de listas de Java 8-agregar elementos condicionalmente (5)
Tengo el siguiente código:
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;
¿Hay una buena manera de agregar elementos condicionalmente, tal vez utilizando operaciones de transmisión? Me gustaría agregar elementos del método 2 solo si la lista está vacía, de lo contrario, vuelva, y así sucesivamente.
Edición: vale la pena mencionar que los métodos contienen una lógica pesada, por lo que debe evitarse su ejecución.
Podría intentar verificar el valor de retorno de
addAll
.
Devolverá
true
cuando la lista haya sido modificada, así que intente esto:
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;
Debido a la evaluación perezosa, la primera operación
addAll
que agregó al menos un elemento evitará que se llame al resto.
Me gusta el hecho de que "||"
Expresa la intención bastante bien.
Podrías crear un método como tal:
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);
}
y luego llámalo como sigue:
lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());
Nombre del método con fines ilustrativos únicamente.
Podrías mejorar tu código creando el método.
public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
if(list.isEmpty()){
list.addAll(method.get());
}
}
Luego puede usarlo así (asumí que sus métodos no son métodos estáticos, si es que necesitan hacer referencia a ellos usando
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;
Si realmente quieres usar un Stream, puedes hacer esto
Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
.collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);
OMI lo hace más complicado, dependiendo de cómo se hace referencia a sus métodos, podría ser mejor usar un bucle
Simplemente usaría un flujo de proveedores y filtraría en
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()
evitará llamadas innecesarias al
methodN()
cuando uno de los métodos
methodN()
la primera lista que no esté vacía.
EDITAR:
Como se comentó en los comentarios a continuación, si su objeto de
list
no se inicializa con nada más, entonces tiene sentido simplemente devolver el resultado de la secuencia directamente:
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);
Una forma de hacerlo sin repetirte es extraer un método que lo haga por ti:
private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}
Y entonces
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;
O incluso usar un bucle for:
List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));
Ahora DRY no es el aspecto más importante. Si cree que su código original es más fácil de leer y entender, entonces manténgalo así.