Как вы фильтруете вложенные циклы, используя потоки и фильтры Java 8?
Как вы фильтруете вложенные циклы, используя потоки и фильтры java8?
Предположим, у меня есть список автомобилей (List<Car>
), каждая машина имеет список двигателей (List<Engine>
), каждый двигатель, имеющийList<Parts>
, В обычной Java эта структура может быть описана как:
for(Car car : cars) {
for (Engine engine : car.getEngines()) {
for (Part part : engine.getParts()) {
// ...
}
}
}
Предположим, я инициализирую список автомобилей следующим образом:
List<Car> cars = new ArrayList<Car>(Arrays.asList(new Car(), new Car(), new Car()));
cars.get(0).setEngines(null);
cars.get(1).setEngines(new ArrayList<Engine>());
cars.get(2).setEngines(new ArrayList<Engine>() {{
add(new Engine());
add(null);
add(new Engine());
}});
Если я хочу отфильтровать нулиList<Engine>
тогда я бы сделал
cars.stream().filter(p -> p.getEngines() != null).forEach(System.out::println);
Если я хочу отфильтровать пустые массивы List, я бы сделал
cars.stream().filter(p -> !p.getEngines().isEmpty()).forEach(System.out::println);
Но как мне удалить нульEngine
в 3-й машине и все же оставить два других двигателя прикрепленными к первоначальной структуре списка? Другими словами, можем ли мы перейти на 2-й, 3-й, n-й уровень иерархии с фильтрами Java 8 или фильтры работают только на самом верхнем уровне? Я также пытался использовать.anyMatch()
без особой удачи.
просто для дальнейшего уточнения рассмотрим следующий пример: в моем гараже 3 машины. Каждый автомобиль имеет 3 заполнителя для двигателя. Каждый двигатель имеет 3 заполнителя для частей, из которых состоит двигатель:
Car #1:
Engine#1: part1, part2, part3
Engine#2: null, part2, empty
Engine#3: part1, null, part3
Car #2:
Engine#1: part1, part2, part3
empty: null, null, null
null: null, null, null
Car #3:
Engine#1: null, empty, part3
Engine#2: null, part2, empty
Engine#3: part1, null, part3
Вопрос: как мы используем Java 8 .filter, чтобы после фильтрации получалось следующее:
Car #1:
Engine#1: part1, part2, part3
Engine#2: part2,
Engine#3: part1, part3
Car #2:
Engine#1: part1, part2, part3
Car #1:
Engine#1: part3
Engine#2: part2,
Engine#3: part1,part3
=======================
Другой примерРебята, я надеюсь, что этот пример, который я только что составил, более понятен: .. По сути, он такой же, как и выше, только он более многословен, и вместо машин мы можем думать о банках, чтобы минимизировать абстракцию. Для краткости я обнародую все поля, надеюсь, вы не против.
Предположим, что я связан с 4 банками в своем «банковском кошельке»
Bank # 1:
Я физически банк здесь. Я вынужден иметь 3 счета, но только 2 заполнены небольшим количеством денег, а 3 еще не открыт (т. Е. Ноль)
Банк № 2:
Я планирую банк здесь. Создана структура поддержки аккаунта (пустой ArrayList), но аккаунты не добавлены
Банк № 3:
Я заполнил некоторую маркетинговую форму. У меня есть я в их CRM, но никакие счета никогда не будут открыты
Банк № 4:
Этот банк сгорел, в кошельке есть артефакт-заполнитель, который является нулевым.
Следующий код описывает это:
public class Bank_Wallet {
public static void main(String[] args) {
List<Bank> banks = new ArrayList<Bank>(Arrays.asList(new Bank(), new Bank(), new Bank(), null));
// 1st bank with physical accounts, but one of them is null
banks.get(0).accounts = Arrays.asList(new Account(), null, new Account());
// 2nd bank with empty accounts
banks.get(1).accounts = new ArrayList<Account>();
System.out.println("RAW original");
banks.stream().forEach(System.out::println);
System.out.println("\nFiltered result... ");
banks.stream()// get stream
.filter(p -> p != null) // get rid of null banks
.filter(p -> p.accounts != null) // get rid of null accounts
.filter(p -> !p.accounts.isEmpty()) // get rid of empty accounts
// .filter(p->p.accounts. ?????? ??) ?? how do I remove null account from the remaining bank entry?
.forEach(System.out::println);
}// main
}
Классы поддержки здесь:
public class Bank {
public String name;
public static int counter = 0;
public List<Account> accounts;
public Bank() {
this.name = "Bank: #" + Bank.counter++;
}
@Override
public String toString() {
return "Bank [name=" + this.name + ", accounts=" + this.accounts + "]";
}
public class Account {
public String name;
public static int counter;
public Account() {
this.name = "Account: " + Account.counter++;
}
@Override
public String toString() {
return "Account [name=" + this.name + "]";
}
}
когда вы запустите этот код, вы увидите, что после предложенной фильтрации все, что мне осталось, это
Bank [name=Bank: #0, accounts=[Account [name=Account: 0], null, Account [name=Account: 1]]]
Вопрос: Какой еще фильтр мне нужно добавить в код, чтобы приведенный выше результат не показывал ноль в счетах и при этом сохранял общую структуру (Банк-> Счет-> и т. Д.> И т. Д.)
Bank [name=Bank: #0, accounts=[Account [name=Account: 0], Account [name=Account: 1]]]