Novo no Java 12: O Teeing Collector

Neste artigo, veremos um novo coletor introduzido no Java 12. Esse novo recurso não foi anunciado no JEP oficial, pois era uma solicitação de alteração secundária com o título " Criar Coletor, que mescla os resultados de outros dois coletores ". Ele foi projetado para combinar resultados de dois coletores.


Tudo interessante - sob o corte


Se você ainda não sabe o que são colecionadores
Coletores são classes especiais usadas para converter um fluxo em outra estrutura de dados. Por exemplo, na list :
 list = Stream.of(1,2,3).collect(Collectors.toList()); //     1, 2  3 

Este é um exemplo inútil, porque cria um novo fluxo e o transforma imediatamente. Pensa-se mostrar o uso de colecionadores

A documentação


Clique aqui para ver os Collectors#teeing . De acordo com a documentação oficial:
“... retorna um coletor composto por dois coletores subordinados. Cada elemento transferido para o coletor resultante é processado pelos dois coletores subordinados e, em seguida, seus resultados são combinados usando uma função especial que os conecta ao resultado final. ”
O original
"... retorna um coletor que é composto de dois coletores a jusante. Cada elemento passado ao coletor resultante é processado pelos dois coletores a jusante, e seus resultados são mesclados usando a função de mesclagem especificada no resultado final."
Cabeçalho do método:

 static <T, R1, R2, R> Collector<T, ?, R> teeing( Collector<? super T, ?, R1> downstream1, Collector<? super T, ?, R2> downstream2, BiFunction<? super R1, ? super R2, R> merger) 

Fato interessante


Este é um tee (tee do inglês):



Teeing veio de um tee. De acordo com a Wikipedia, "um tee é o acessório mais comum (conectando parte de um oleoduto, aprox. Translator) usado para combinar [ou dividir] um fluxo de fluido (neste caso, queremos dizer fluxos, fluxo - fluxo / fluxo / fluxo, tradutor de comentários)".
Outros nomes foram sugeridos: dividir (dividir em 2 partes), duplexar, bifurcar (dividir), replicador, fanout (dividir), tocar, descompactar, collectionToBothAndThen, biCollecting, expandindo (extension), bifurcação, etc.
Todas as alternativas classificadas pelos desenvolvedores do Core podem ser encontradas aqui .

Exemplos de uso


Eu compilei três exemplos de uso de código com diferentes níveis de complexidade.

Lista de convidados


Extraímos dois tipos diferentes de informações da lista de objetos no fluxo. Cada hóspede deve aceitar o convite e pode liderar a família. Queremos saber quem confirmou a reserva e o número total de participantes (incluindo convidados e familiares).

 var result = Stream.of( // Guest(String name, boolean participating, Integer participantsNumber) new Guest("Marco", true, 3), new Guest("David", false, 2), new Guest("Roger",true, 6)) .collect(Collectors.teeing( //  ,    ,    Collectors.filtering(Guest::isParticipating, //        Collectors.mapping(o -> o.name, Collectors.toList())), //  ,       Collectors.summingInt(Guest::getParticipantsNumber), //      , //    EventParticipation::new )); System.out.println(result); //  // EventParticipation { guests = [Marco, Roger], // total number of participants = 11 } 


Convidado
 class Guest { private String name; private boolean participating; private Integer participantsNumber; public Guest(String name, boolean participating, Integer participantsNumber) { this.name = name; this.participating = participating; this.participantsNumber = participantsNumber; } public boolean isParticipating() { return participating; } public Integer getParticipantsNumber() { return participantsNumber; } } 


Participação em eventos
 class EventParticipation { private List<String> guestNameList; private Integer totalNumberOfParticipants; public EventParticipation(List<String> guestNameList, Integer totalNumberOfParticipants) { this.guestNameList = guestNameList; this.totalNumberOfParticipants = totalNumberOfParticipants; } @Override public String toString() { return "EventParticipation { " + "guests = " + guestNameList + ", total number of participants = " + totalNumberOfParticipants + " }"; }} 


Filtrar nomes em duas listas diferentes


Neste exemplo, dividimos o fluxo de nomes em duas listas de acordo com o filtro.

 var result = Stream.of("Devoxx", "Voxxed Days", "Code One", "Basel One", "Angular Connect") .collect(Collectors.teeing( //   Collectors.filtering(n -> n.contains("xx"), Collectors.toList()), //   Collectors.filtering(n -> n.endsWith("One"), Collectors.toList()), //  -       (List<String> list1, List<String> list2) -> List.of(list1, list2) )); System.out.println(result); // -> [[Devoxx, Voxxed Days], [Code One, Basel One]] 

Contar e adicionar um fluxo de números


Você pode ter visto um exemplo semelhante aparecendo em blogs que combinam soma e contagem para obter a média. Este exemplo não requer Teeing e você pode simplesmente usar o AverageInt e um coletor simples.

O exemplo a seguir usa funções de Teeing para retornar dois valores:

 var result = Stream.of(5, 12, 19, 21) .collect(Collectors.teeing( //   Collectors.counting(), //   Collectors.summingInt(n -> Integer.valueOf(n.toString())), // : (count, sum) -> new Result(count, sum); Result::new )); System.out.println(result); // -> {count=4, sum=57} 

Resultado
 class Result { private Long count; private Integer sum; public Result(Long count, Integer sum) { this.count = count; this.sum = sum; } @Override public String toString() { return "{" + "count=" + count + ", sum=" + sum + '}'; }} 


Possível armadilha


Map.Entry

Muitos exemplos usam o Map.Entry para armazenar o resultado de uma BiFunction . Por favor, não faça isso porque você não pode armazenar o último argumento no Map . Não há nenhum objeto padrão no Java Core para armazenar dois valores - você precisará criá-lo.

Tudo sobre os novos recursos do Java 12


Você pode encontrar mais informações e fatos interessantes sobre o Java 12 nesta apresentação .

Colecionáveis ​​de sucesso!

Source: https://habr.com/ru/post/pt445622/


All Articles