如何使用Java 8流和filter过滤嵌套循环?

如何使用java8流和filter过滤嵌套循环?

假设我有一个汽车ListList ),每辆汽车都有一个Engines ListList ),每个引擎都有一个List 。 在常规Java中,这种结构可以描述为:

 for(Car car : cars) { for (Engine engine : car.getEngines()) { for (Part part : engine.getParts()) { // ... } } } 

假设我将汽车列表初始化为:

 List cars = new ArrayList(Arrays.asList(new Car(), new Car(), new Car())); cars.get(0).setEngines(null); cars.get(1).setEngines(new ArrayList()); cars.get(2).setEngines(new ArrayList() {{ add(new Engine()); add(null); add(new Engine()); }}); 

如果我想过滤掉List空值,那么我会这样做

 cars.stream().filter(p -> p.getEngines() != null).forEach(System.out::println); 

如果我想过滤掉List的空arraylists,那么我会这样做

 cars.stream().filter(p -> !p.getEngines().isEmpty()).forEach(System.out::println); 

但是,如何在第3辆车中删除空Engine ,并将其他两个引擎连接到原始列表结构? 换句话说,我们可以使用Java 8filter进入第2级,第3级,第n级层次结构,还是仅在最顶层使用filter? 我也尝试使用.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家银行有关联
银行#1:
我亲自到这里来。 我被迫有3个帐户,但只有2个充满了一些现金而第3个尚未开启(即空)
银行#2:
我打算在这里开银行。 创建帐户支持结构(空ArrayList),但不添加任何帐户
银行#3:
我填写了一些营销表格。 他们让我在他们的CRM中,但没有帐户会被打开
银行#4:
这个银行烧毁了,钱包里有一个神器占位符,它是空的。

以下代码描述了这一点:

 public class Bank_Wallet { public static void main(String[] args) { List banks = new ArrayList(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(); 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 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]]] 

问题:我需要做什么其他filter添加到代码中以获得上述结果在帐户中不显示null并保留整体结构(Bank-> Account-> etc-> etc)

 Bank [name=Bank: #0, accounts=[Account [name=Account: 0], Account [name=Account: 1]]] 

流相当于

 for(Car car : cars) { for (Engine engine : car.getEngines()) { for (Part part : engine.getParts()) { // ... } } } 

 cars.stream() .flatMap(car -> car.getEngines().stream()) .flatMap(engine -> engine.getParts().stream()) .forEach(part -> { /* ... */ }); 

但是...代码无法访问carengine

要检查null,您可以在两个地方办理登机手续:

 cars.stream() .flatMap(car -> car.getEngines().stream()) .filter(engine -> engine != null) .flatMap(engine -> engine.getParts().stream()) .forEach(part -> { /* ... */ }); 

要么

 cars.stream() .flatMap(car -> car.getEngines() .stream() .filter(engine -> engine != null)) .flatMap(engine -> engine.getParts().stream()) .forEach(part -> { /* ... */ }); 

为什么你不简单地写这个?

 cars.stream() .filter(car -> notEmpty(car.getEngines())) .filter(car -> car.getEngines().stream().allMatch(engine -> notEmpty(engine.getParts()))) .forEach(System.out::println); public static  boolean notEmpty(Collection collection) { return collection != null && !collection.isEmpty(); } 

跟着怎么样?

  List cars = new ArrayList(Arrays.asList(new Car("C0"), new Car("C1"), new Car("C2"))); cars.get(0).setEngines(new ArrayList()); cars.get(1).setEngines(new ArrayList()); cars.get(2).setEngines(Arrays.asList(new Engine("C2E1"), new Engine("C2E2"), null)); cars.stream().filter(c -> Objects.nonNull(c.getEngines())).forEach(c -> { System.out.printf("Car %s ", c); c.getEngines().stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getParts())).forEach(e -> { System.out.printf(" Engine %s ", e); e.getParts().stream().filter(p -> Objects.nonNull(p)) .forEach(p -> System.out.printf("Part %s", p)); }); System.out.println(); }); 

产生以下:

车C0

车C1

Car C2 Engine C2E1 Part DefaultPart Engine C2E2 Part DefaultPart

为汽车/发动机/零件类重写了“toString”。

希望这可以帮助。

您可以使用removeIf() ,如下所示:

  cars.removeIf(car -> car.getEngines() == null); cars.forEach(c->System.out.println("Car :"+c);