Transformar una lista plana de objetos de dominio con los objetos secundarios que utilizan corrientes de Java

Adam:

Tengo objetos entrantes con una estructura normalizada de-plano que me crea una instancia de un conjunto de resultados JDBC. Los objetos de entrada reflejan el conjunto de resultados, hay un montón de datos repetidos, así que quiero convertir los datos en una lista de objetos padres con colecciones hijas anidados, es decir, un gráfico de objetos, o una lista normalizada.

la clase del objeto entrante se ve así:

class IncomingFlatItem {
    String clientCode;
    String clientName;
    String emailAddress;
    boolean emailHtml;
    String reportCode;
    String reportLanguage;
}

Lo que los datos de entrada contiene varios objetos para cada cliente, lo que me gustaría a agregarse en un objeto de cliente, que contiene una lista de objetos de dirección de correo electrónico para el cliente, y una lista de objetos de informe.

Por lo tanto el objeto de cliente se vería así:

class Client {
    String clientCode;
    String clientName;
    Set<EmailAddress> emailAddresses;
    Set<Report> reports;
}

Por extraño que no puedo encontrar una respuesta existente para esto. Estoy buscando en la anidación corrientes o flujos de encadenamiento pero me gustaría encontrar el enfoque más elegante y definitivamente quiero evitar un bucle para.

Adam:

Gracias a todos los que responden que han mencionado Collectors.groupingBy(). Esto fue clave para la creación de un flujo en el que podía utilizar reduce(). Yo había creído erróneamente que debería ser capaz de utilizar reducepor sí solo para resolver el problema, sin groupingBy.

Gracias también a la sugerencia de crear una API fluida. He añadido IncomingFlatItem.getEmailAddress()y IncomingFlatItem.getReport()de fluidez agarrar los objetos de dominio de IncomingFlatItem- y también un método para convertir todo el elemento plano a un objeto de dominio adecuado con su correo electrónico y el informe ya anidado:

public Client getClient() {
    Client client = new Client();
    client.setClientCode(clientCode);
    client.setClientName(clientName);
    client.setEmailAddresses(new ArrayList());
    client.getEmailAddresses().add(this.getEmailAddress());
    client.setReports(new ArrayList<>());
    client.getReports().add(this.getReport());
    return client;
}

También basado en el ID de empresa creada .equals()y .hashCode()métodos sobre Client, EmailAddressy Reportsegún lo recomendado por @SamuelPhilip

Por último para los objetos de dominio, creé .addReport(Report r)y .addEmail(EmailAddress e)en mi Clientclase, lo que añadiría el objeto secundario que Clientsi no está ya presente. Dejé el Settipo de colección para Listdebido a que el modelo estándar es de dominio Listy Setshabría significado una gran cantidad de conversiones a Lists.

Así que con eso, el código de secuencia y lambdas ven sucinta.

Hay 3 pasos:

  1. asignar IncomingFlatItemsaClients
  2. grupo de la Clientsen un mapa por el cliente (depender en gran medida Client.equals())
  3. reducir cada grupo a una Client

Así que este es el algoritmo funcional:

List<Client> unflatten(List<IncomingFlatItem> flatItems) {
    return flatItems.parallelStream()
            .map(IncomingFlatItem::getClient)
            .collect(Collectors.groupingByConcurrent(client -> client))
            .entrySet().parallelStream()
            .map(kvp -> kvp.getValue()
                    .stream()
                    .reduce(new Client(), 
                            (client1, client2) -> {
                                    client1.getReports()
                                            .forEach(client2::addReport);
                                    client1.getEmailAddresses()
                                            .forEach(client2::addEmail);
                                    return client2;
                    }))
            .collect(Collectors.toList());
}

Me tomó mucho tiempo debido a salirse por la tangente antes de que realmente entendí reduce- he encontrado una solución que pasaba mis pruebas durante el uso .stream(), pero fracasó totalmente con .parallelStream()por lo tanto, su uso aquí. Tuve que usar CopyOnWriteArrayListademás de lo contrario sería caer al azar conConcurrentModificationExceptions

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=226558&siteId=1
Recomendado
Clasificación