Executando verificação de segurança...
15

Java Streams

Como motivação para meu primeiro post aqui no TabNews decidi mostrar um pouco sobre a manipulação de listas utilizando a API Java Streams.

Sempre senti dificuldade em entender essa api e passei anos como dev java sem utilizar esse recurso, mas nos últimos anos venho me aperfeiçoando em JavaScript e nele tem funções como .map, .find, .reduce entre outras, e senti um ganho de produtividade imensa, foi daí que decidi ter o mesmo ganho em java.

Java Streams é uma API inicialmente introduzida no Java 8 e vem tendo atualizações interessantes para melhorar seu uso.

Java Streams tem como princípio fazer a manipulação de Collections de forma mais simples juntamente alinhada com uma programação mais funcional
utilizando as functions lambda.

Lembrete: Se você não sabe como fazer com for normal talvez streams não seja para você, então cuidado
ao utilizar essa API poderosa;

Com grandes poderes vem grandes responsabilidade ~ Ben Parker

Mais sobre: https://www.devmedia.com.br/java-streams-api-manipulando-colecoes-de-forma-eficiente/37630

Documentação oficial:

Vou mostrar alguns exemplos lidando com listas no modo tradicional e com streams

Para os exemplos a seguir vamos assumir que temos a seguinte lista

	private static List<Person> personList = new ArrayList<Person>();
        personList.add(new Person(1, "Bob", 'M', 25));
	personList.add(new Person(2, "Alice", 'F', 18));
	personList.add(new Person(3, "John", 'M', 20));
	personList.add(new Person(4, "Michael", 'M', 32));

Foreach

Como você pode ver a baixo não há muita diferença, (Eu particularmente prefiro no modo normal ainda) mas prometo que nos próximos exemplos terá maior impacto.

  • Normal
for(Person p: personList) {
    System.out.println(p.getName());
}
  • Lambda
personList.stream().forEach(p -> {
    System.out.println(p.getName());
});

Map

Para o map temos como objetivo criar uma lista com apenas os nomes

  • Normal
List<String> names = new ArrayList<String>(); 
for (Person p : personList) {
    names.add(p.getName());
}
  • Lambda
 List<String> names = personList.stream()
                                .map(Person::getName)
				.collect(Collectors.toList());

Filter

Objetivo e obter uma lista com todas as person do sexo masculino

  • Normal
List<Person> personTempList = new ArrayList<Person>();
for (Person p : personList) {
    char sex = p.getSex();
    if('M' == sex) {
        personTempList.add(p);
    }
}
  • Lambda
List<Person> personTempList = personList.stream()
                                        .filter(p -> 'M' == p.getSex())
                                        .collect(Collectors.toList());

Bem esses são apenas alguns exemplos para o post, mais exemplos de código você encontra no meu Git.

Todo código-fonte está no meu Git

Carregando publicação patrocinada...
3
Antes
List<Person> personTempList = personList.stream()
                                        .filter(p -> 'M' == p.getSex())
                                        .collect(Collectors.toList());
Depois
public static boolean hasSexMasculine(Person person) {
	return person.getSex() == 'M';
}
        
List<Person> personTempList = personList.stream()
                                        .filter(Person::hasSexMasculine)
                                        .collect(Collectors.toList())

Esta mudança pode até parecer entranha ou que esta deixando o código mais sujo, mas bem pelo contrário com uma função como essa pode ocasionar, mesmo erros de escritas aumentando a desempenho de sua equipe.

2

Lembrando que desde a versão 16, é possível coletar os valores à list mais fácilmente:

List<Person> personTempList = personList.stream()
                                        .filter(Person::hasSexMasculine)
                                        .toList() // <--  
1
2
2

Muito bom man, parabéns. No começo eu achava streams um verdadeiro bixo de 777 cabeças. Mas conhecendo melhor a API percebi que é a coisa mais simples e mais agradavel de trabalhar que existe kkk.

Deixando minha humilde contribuição, além dos métodos que vc destacou, eu também uso muito no dia a dia como dev os métodos anyMatch, noneMatch e allMatch, eles são bem legais, ajudam a encontrar determinadas ocorrências numa lista de forma bem simples, por exemplo:

1. anyMatch:

  • Retorna verdadeiro se pelo menos um item da lista satisfizer a condição, no caso abaixo, retornará verdadeiro se pelo menos uma das pessoas for maior de idade.
 personList.stream().anyMatch(p -> p.age >= 18);

2. noneMatch:

  • Retorna verdadeiro se ninguém da lista satisfizer a condição, no caso abaixo, retornará verdadeiro se nenhuma das pessoas for maior de idade.
 personList.stream().noneMatch(p -> p.age >= 18);

3. allMatch:

  • Retorna verdadeiro se todos os itens da lista satisfizerem a condição, no caso abaixo, retornará verdadeiro se todas as pessoas forem maiores de idade.
 personList.stream().allMatch(p -> p.age >= 18);

O mais massa é que a JVM já otimiza esses métodos, todos eles param assim que é possível definir o resultado, por exemplo, o método anyMatch para de executar no momento em que ele encontra o primeiro caso que da match (retorna verdadeiro). O método noneMatch para de executar no momento em que ele encontra o primeiro caso que dê match (e retorna falso). E o método allMatch para de executar no momento em que ele encontra o primeiro caso que não dê match (e retorna falso). O código fica mais legível (e por consequência, agradável de ler e entender) do que se isso fosse feito na mão com for e if.

1
1
1

Oi Deivid! :D

Me perdoe por fugir um pouco do escopo do post, mas sou iniciante em Java e como você trabalha com isso, você poderia me dar conselhos do que estudar?

1

Olá joel, oque realmente virou a chave no modo que programava foi entender como funciona a orientação a objeto e o java no meu caso foi muito util, então eu recomendo em estudar bem esse conceito e aplicar na pratica (fazer sistemas basicos em terminal msm) e tentar utilizar ao máximo interação entre classes para aperfeiçoar a decisão de quais metodos fica em cada classe e como elas se conversam entre si para atender um objetivo.

1

Olá joel,

Sem saber o quê você já sabe é difícil recomendar. Eu diria que polimorfismo é um bom começo, as diferenças entre os tipos de classe e quando usar-las (class, interface, enum, record), a diferença entre os modificadores de acesso (public, private, protected), etc.

Um curso básico, fácil de seguir e bem didático (em inglês) é esse aqui: https://www.w3schools.com/java/java_getstarted.asp

Um bom objetivo a médio prazo eu diria que pode ser o desenvolvimento em algum framework como Spring boot, por exemplo.

1

Excelente artigo cara, parabéns!!

Stream facilita demais a nossa vida e você soube explicar de forma muito clara. A facilidade que fica para trabalhar com manipulação de dados é incrivel, além de deixar o código bem mais limpo e intuitivo.

Também achei muito bacana o desafio que você propôs no seu Git, para que nós possamos colocar em prática o que você nos ensinou.

Além disso, os comentários aqui do pessoal agregaram ainda mais o seu artigo! Show de bola!!