¿Cómo se filtran los bucles anidados utilizando flujos y filtros de Java 8?

¿Cómo se filtran los bucles anidados utilizando flujos y filtros java8?

Supongamos que tengo una lista de autos (List<Car>), cada automóvil tiene una lista de motores (List<Engine>), cada motor tiene unList<Parts>. En Java normal, esta estructura se puede describir como:

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

Supongamos que inicializo la lista de autos como:

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

Si quiero filtrar nulos deList<Engine>entonces haría

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

Si quiero filtrar las listas de matrices vacías de List, entonces lo haría

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

¿Pero cómo elimino el nuloEngine en un tercer automóvil y aún así mantener otros dos motores unidos a la estructura de la lista original? En otras palabras, ¿podemos pasar al segundo, tercer y noveno nivel de jerarquía con los filtros Java 8 o los filtros solo funcionan en la capa superior? También intenté usar.anyMatch()Sin mucha suerte.

solo para aclarar más, considere el siguiente ejemplo: tengo 3 autos en mi garaje. Cada automóvil tiene 3 marcadores de posición para el motor. Cada motor tiene 3 marcadores de posición para las partes que componen el motor:

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

Pregunta: ¿cómo usamos Java 8 .filter, de modo que cuando después de filtrar obtengo lo siguiente:

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

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

Otro ejemplo

Chicos, espero que este ejemplo que acabo de inventar sea más claro: .. Esencialmente, es el mismo que el anterior, pero es más detallado y en lugar de autos podemos pensar en los bancos para minimizar la abstracción. Para ser concisos, hago públicos todos los campos, espero que no te importe.

Supongamos que estoy afiliado a 4 bancos en mi 'billetera bancaria'
Banco # 1:
Físicamente banco aquí. Me veo obligado a tener 3 cuentas, pero solo 2 están llenas de efectivo y la tercera aún no se ha abierto (es decir, nula)
Banco # 2:
Planeo depositar aquí. Se crea la estructura de soporte de la cuenta (ArrayList vacía), pero no se agregan cuentas
Banco # 3:
Completé un formulario de marketing. Me tienen en su CRM pero nunca se abrirán cuentas
Banco # 4:
Este banco se quemó, hay un marcador de posición de artefacto en la billetera, que es nulo.

El siguiente código describe esto:

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
}


Las clases de soporte están aquí:

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

}

cuando ejecute este código, verá que después de sugerir el filtrado, todo lo que me queda es

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

Pregunta: ¿Qué otro filtro necesito agregar al código para que el resultado anterior no se muestre nulo en las cuentas y aún así conserve la estructura general (Banco-> Cuenta-> etc-> etc.)

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

Respuestas a la pregunta(4)

Su respuesta a la pregunta