Wie filtert man verschachtelte Schleifen mit Java 8-Streams und -Filtern?

Wie filtert man verschachtelte Schleifen mit Java8-Streams und -Filtern?

Angenommen, ich habe eine Liste von Autos List<Car>), jedes Auto hat eine Liste von Motoren List<Engine>), jeder Motor hat einList<Parts>. In regulärem Java kann diese Struktur wie folgt beschrieben werden:

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

Angenommen, ich initialisiere die Liste der Autos als:

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());  
}});

Wenn ich Nullen von @ herausfiltern möchList<Engine>, dann würde ich @ t

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

Wenn ich leere Arraylisten von List herausfiltern möchte, würde ich

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

Aber wie entferne ich die NullEngine in einem 3. Auto und trotzdem zwei weitere Motoren an der ursprünglichen Listenstruktur hängen lassen? Mit anderen Worten, können wir mit Java 8-Filtern in die 2., 3. und n-te Hierarchieebene gehen oder funktionieren Filter nur auf der obersten Ebene? Ich habe auch versucht, @ zu verwend.anyMatch(), ohne viel Glück.

eachten Sie zur weiteren Verdeutlichung das folgende Beispiel: Ich habe 3 Autos in meiner Garage. Jedes Auto hat 3 Platzhalter für den Motor. Jeder Motor hat 3 Platzhalter für Teile, aus denen der Motor besteht:

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

Frage: Wie verwenden wir Java 8 .filter, sodass ich nach dem Filtern Folgendes erhalte:

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

=======================

Ein anderes Beispie

Guys Ich hoffe, dieses Beispiel, das ich gerade erfunden habe, ist klarer: .. Im Wesentlichen ist es das gleiche wie oben, nur ist es ausführlicher und anstelle von Autos können wir an Banken denken, um die Abstraktion zu minimieren. Aus Gründen der Übersichtlichkeit mache ich alle Felder öffentlich, ich hoffe es macht Ihnen nichts aus.

Angenommen, ich bin mit 4 Banken in meiner 'Bank-Brieftasche' verbunden.
Bank # 1:
ch habe hier eine physische Bank. Ich muss 3 Konten haben, aber nur 2 sind mit etwas Bargeld gefüllt und der 3. ist noch nicht eröffnet (dh null)
Bank # 2:
Ich habe vor, hier zu bankieren. Kontounterstützungsstruktur wird erstellt (leere ArrayList), aber es werden keine Konten hinzugefügt
Bank # 3:
Ich habe ein Marketingformular ausgefüllt. Sie haben mich in ihrem CRM, aber es werden niemals Konten eröffnet.
Bank # 4:
Diese Bank ist abgebrannt, in der Brieftasche befindet sich ein Artefakt-Platzhalter, der null ist.

Der folgende Code beschreibt dies:

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
}


Die Supportklassen sind hier:

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 + "]";
    }

}

wenn Sie diesen Code ausführen, werden Sie feststellen, dass nach dem vorgeschlagenen Filtern nur noch @ übrig is

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

Frage: Welchen anderen Filter muss ich zum Code hinzufügen, damit das obige Ergebnis nicht null in den Konten anzeigt und trotzdem die Gesamtstruktur beibehält (Bank-> Konto-> etc-> etc)

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

Antworten auf die Frage(8)

Ihre Antwort auf die Frage