DEV Community

Alex Reis
Alex Reis

Posted on

Streams do Java

Lançada na versão 8 do Java, Stream API é um recurso que traz métodos e classes e tem por finalidade facilitar a manipulação das Collections no estilo da programação funcional (não sabe o que é? dê uma olhada no meu artigo O que é um Paradigma de Programação).

A seguir temos um trecho de código, na forma imperativa, cujo propósito é somar os inteiros pares de uma lista.

private static int somaIterator(ListList<Integer> list) {
   int soma = 0;
   for (int num : list) {
       if (num % 2 == 0) {
           soma += num;
       }
   }
   return soma;
}
Enter fullscreen mode Exit fullscreen mode

Esse tipo de abordagem acaba sendo tediosa, você já deve ter implementado diversos for como esse. Para solucionar este problema, a programação funcional nos permite com encadeamento de métodos e passagem de parâmetros via Expressões Lambda.

Os beneficios dessa abordagem é a imutabilidade de variavéis, a variavél não vai mudar dentro do fluxo, além de um código preciso e claro.

private static int soma(List<Integer> list) {
    int soma = list.stream()
         .filter(n -> n % 2 == 0)
         .reduce(0, Integer::sum);
    return soma;
}
Enter fullscreen mode Exit fullscreen mode

Aqui obtemos uma stream da lista por meio do método stream() da interface Collection. O método filter() retorna apenas os elementos pares. Tais elementos são processados pelo método reduce() que aplica a operação de soma com todos os elementos. O resultado é armazenado no inteiro soma;

Caracteristicas de uma Stream

Uma Stream pode ser definida como uma sequência de elementos de uma fonte de dados que oferece suporte a diferentes tipos de operações de agregação. Vamos entender essa definição:

  • Uma stream provê uma interface para um conjunto sequencial de valores de um determinado tipo. Contudo, streams não armazenam elementos;
  • Streams consomem dados de uma fonte, como coleções, arrays ou até recursos de entrada e saída;
  • Streams suportam operações comuns a linguagens de programação funcionais, como filtrar, modificar, transformar o elemento em outro e assim por diante. Essas operações podem ser realizadas em série ou em paralelo.

Streams são projetadas de tal maneira que a maior parte de suas operações retornam novas streams. Dessa forma, é possível criar uma cadeia de operações que formam um fluxo de processamento. A isso damos o nome de pipeline.

As operações sobre streams são classificadas em intermediárias ou terminais e quando combinadas formam uma estrutura de processo chamada pipeline. As operações intermediárias servem como entrada para outras operações intermediárias ou terminais, elas sempre retornam uma nova stream. As operações terminais são usadas no final da cadeia (de operações) para fechar o processo e retornam um valor ou um objeto, não é possível utilizar intermediárias depois de uma terminal.

Em suma, a Stream API funciona convertendo uma fonte de dados em stream, realizando as operações intermediárias e por fim retorna algo com a chamada da operação terminal. No exemplo do trecho de código acima, temos filter() uma operação terminal e reduce() uma operação terminal.

Como criar uma stream

List<String> nomes = new ArrayLIst<>();
nomes.add("Chicó");
nomes.add("Vicentao");
nomes.add("Cabo Setenta");
Stream<String> stream = nomes.stream();
Enter fullscreen mode Exit fullscreen mode

Operações intermediárias

Filter: O método filter() é usado para filtrar elementos de uma stream de acordo com uma condição (predicado). Para isso, ele recebe como parâmetro um objeto que implementa a interface Predicate (interface funcional que define uma função com valor de retorno igual a um boolean) e retorna uma nova stream contendo apenas os elementos que satisfazem à condição.

Map: O método map() permite realizar transformações em uma lista de dados sem a necessidade de variáveis intermediárias, apenas utilizando como argumento uma função do tipo java.util.function.Function, que, assim como Predicate, também é uma interface funcional. Essa função toma cada elemento de uma stream como parâmetro e retorna o elemento processado como resposta.

Sorted: O método sorted() retorna uma nova stream contendo os elementos da stream original ordenados de acordo com algum critério.

Distinct: A operação distinct() retorna uma stream contendo apenas elementos que não se repetem, de acordo com a implementação do método equals().

Limit: limit() é utilizado para limitar o número de elementos em uma stream.

Operações terminais

ForEach: O método forEach() é usado para sobre uma stream e executar algum processamento como um loop for.

Average: average() permite calcular a média dos valores dos elementos (usado nas implementações de Stream par tipos primitivos como LongStream ou DoubleStream).

Reduce: O método reduce() é uma operação de redução que pode ser usada para transformar todos os elementos de uma stream em um único valor, com base em um predicado. Usado para somar, multiplicar ou encontrar o máximo e o mínimo de uma coleção.

Collect: Com o método collect() é possível coletar os elementos de uma stream em coleções, convertendo a stream para uma List, Set ou Map.

Count: O método count() retorna a quantidade de elementos em uma stream.

AllMatch: O método allMatch() verifica se todos os elementos de uma stream atendem a um critério passado como parâmetro, através de um Predicate, e retorna um valor booleano.

Referência

Java 8: Iniciando o desenvolvimento com a Streams API | Oracle Brasil

Top comments (0)