Streams

Aula
Estado
💡
São um fluxo de elementos imutáveis que podem ser processados apenas uma vez
  • Pode ser sequencial ou paralela; finita ou infinita
    • uma stream pode ser infinita, mas deve ter um processamento finito
  • Se uma Stream tiver chamadas para parallel e outra, em qualquer ordem, para sequential toda a Stream será processada de acordo com o último método chamado, seja ele sequential ou parallel
  • As operações de uma stream utilizam functional interfaces
  • São definidas através das interfaces:
    • BaseStream: define os comportamentos essenciais
    • Stream: pode ser utilizada para qualquer tipo de stream
    • DoubleStream, IntStream e LongStream: fornecem métodos que ajudam no processamento desses tipos em suas versões primitivas
  • É possível criar uma stream a partir de qualquer coleção, array ou com métodos estáticos da classe Stream
notion image

Operações

Short-circuit

São algumas operações de Streams que produzem resultado finito mesmo em Streams infinitas. Existem operações short-circuit que são intermediárias ou terminais.
notion image

Intermediárias

São operações que executam uma ação e retornam outra Stream. Elas são: filter, map, flatMap, peek, distinct, sorted, dropWhile e skip. limit, takeWhile. As operações short-circuit são: limit e takeWhile.
  • flatMap permite transformar uma lista de listas em uma lista única, ou seja, mesclar múltiplas Streams em uma única

Terminais

São operações que percorrem toda a Stream e retornam algo diferente de uma Stream. Elas são: forEach, ForEachOrdered, count, min, max, sum, average, collect e reduce. As operações short-circuit são: allMatch, anyMatch, noneMatch, findAny e findFirst.
  • collect executa uma redução mutável nos elementos da Stream. Ele utiliza classes que implementam a interface Collector; existem muitos métodos auxiliares na classe Collectors

Collectors

💡
Classe com métodos Collector auxiliares
  • Existem métodos para executar cálculos matemáticos comuns
  • Métodos para mapear e unir elementos de uma Stream
  • Métodos de união de elementos de uma coleção
  • O método collectingAndThen une os elementos resultantes de outros métodos coletores
  • O método partitioningBy divide o conteúdo em um Map com colunas de valores verdadeiros e falsos; um valor é testado usando um Predicate
  • O método groupingBy divide o conteúdo em um Map com colunas criadas a partir de uma Function
notion image

Parallel Stream Processing

Os elementos da Stream são divididos em subconjuntos. Subconjuntos podem ser divididos em mais subconjuntos, e assim por diante. Esses subconjunto são enviados para diferentes cores do processador e processados em uma ordem impossível de determinar. Quando todos elementos da Stream forem processados ela se torna uma novamente.
Processamento paralelo só é benéfico se:
  • A Stream tem um grande número de elementos (+10.000)
  • O hardware executando o programa possuí um CPU multi-core
  • O processamento feito nos elementos da Stream consome muitos recursos do CPU
Existem alguns critérios para definir se uma Stream deve ser processadas de forma paralela ou não:
  • Stateless: o estado de um elemento não pode afetar outro
  • Non-interfering: a coleção-fonte não deve sofrer modificações
  • Associative: o resultado não pode ser afetado pela ordem de processamento dos elementos
notion image
Lidar com Streams paralelas de forma incorreta pode corromper a memória e/ou deixar o processamento lento:
  • Não executar operações que precisem de acesso sequencial a um recurso compartilhado (e.g. imprimir as Strings de uma coleção)
  • Não executar operações que modifiquem um recurso compartilhado (e.g. como fazer um map dos elementos da Stream)
  • Não Usar Collectors inapropriados (e.g. toMap deve ser usado em modo sequencial; toConcurrentMap em paralelo)
Â