Java 8! Ordenando dados com Stream
Neste tutorial vou apresentar um novo recursos do Java 8, o qual tem o objetivo de ordenação de dados a partir de uma lista. A algum tempo, postei o tutorial Java 8! Filtrando dados com Stream, neste veremos então como ordenar dados com o uso de Stream e expressões Lambdas. Para isto, vou criar uma classe chamada Person
e gerar uma lista de dados a partir dela e esta lista será ordenada com o uso do recursos Stream do Java 8.
No exemplo a seguir temos a classe Person
, a qual será formada por três atributos, name
, age
e salary
, conforme a Listagem 1.
- Listagem 1 – Classe Person
public class Person {
private String name;
private Integer age;
private Double salary;
public Person(String name, int age, Double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Double getSalary() {
return salary;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
Na classe Main – Listagem 2 – vamos criar uma lista do tipo Person
e atribuir a cada posição desta lista valores nos atributos via método construtor. No método testSortOne()
, recebemos a lista como parâmetro e usamos o método sort()
da classe java.util.Collections
para criar o sistema de ordenação pelo atributo name
de forma ascendente [a – z]. Para este recursos utilizo uma classe anônima.
- Listagem 2 – Classe Main
package com.mballem.tutorial;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("Ana Maria", 25, 3200.50));
persons.add(new Person("Bianca", 35, 3440.50));
persons.add(new Person("Marta", 28, 5500.00));
persons.add(new Person("Breno", 22, 3330.70));
persons.add(new Person("Mario", 34, 2200.50));
persons.add(new Person("Ricardo", 55, 3200.00));
persons.add(new Person("Pietra", 26, 3400.50));
persons.add(new Person("Fabiana", 44, 4200.60));
persons.add(new Person("Airton", 29, 1500.50));
testSortOne(persons);
}
private static void testSortOne(List<Person> persons) {
//Usando classe anonima
Collections.sort(persons, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
});
for (Person person : persons) {
System.out.println(person.toString());
}
}
}
Em seguida, o próximo passo é realizar um loop na lista e imprimir o resultado no console por meio de um System.out.println()
. Então, como resultado, teremos no console a seguinte saída:
Person{name='Airton', age=29, salary=1500.5}
Person{name='Ana Maria', age=25, salary=3200.5}
Person{name='Bianca', age=35, salary=3440.5}
Person{name='Breno', age=22, salary=3330.7}
Person{name='Fabiana', age=44, salary=4200.6}
Person{name='Mario', age=34, salary=2200.5}
Person{name='Marta', age=28, salary=5500.0}
Person{name='Pietra', age=26, salary=3400.5}
Person{name='Ricardo', age=55, salary=3200.0}
Analisando a saída no console do método testSortOne()
, veja que os objetos foram ordenados pelo nome, bem como a instrução passada na classe anônima. Porém, o Java 8 fornece um recurso que torna mais simples esta operação, onde você não precisa criar uma classe anônima para adicionar a regra de ordenação e nem executar o loop em uma instrução separada. Vejo como fazer isto usando o recurso de Stream com Lambda no método testSortTwo()
da Listagem 3.
- Listagem 3 – Método testSortTwo
private static void testSortTwo(List<Person> persons) {
persons.stream()
.sorted((p1, p2) -> p1.getName().compareTo(p2.getName()))
.forEach(p -> System.out.println(p));
}
O método testSortTwo()
, assim como o método testSortOne()
, recebe como parâmetro uma lista contendo os objetos do tipo Person
. No entanto, desta vez, usamos o próprio objeto da lista para realizar todas as operações necessárias: ordenação e impressão no console.
A interface java.util.Collection
, que é a superclasse de java.util.List
, fornece o método stream()
, e este, provê o método sorted()
que a partir de uma expressão lambda recebe a instrução referente a ordenação pelo atributo name
.
Em seguida, o método usado é o foreach()
, que por meio de outras expressão lambda vai exibir o resultado no console. Enfim, a operação está encerrada, agora compare as instruções usadas nos métodos testSortOne()
e testSortTwo()
para ver as diferenças e como no segundo método o processo se tornou mais simples e menor.
Caso você queira mudar a ordem de ordenação, basta mudar a ordem dos parâmetros na expressão lambda do método sorted()
:
.sorted((p1, p2) -> p2.getName().compareTo(p1.getName()))
E a saída no console para esta operação seria a seguinte:
Person{name='Airton', age=29, salary=1500.5}
Person{name='Ana Maria', age=25, salary=3200.5}
Person{name='Bianca', age=35, salary=3440.5}
Person{name='Breno', age=22, salary=3330.7}
Person{name='Fabiana', age=44, salary=4200.6}
Person{name='Mario', age=34, salary=2200.5}
Person{name='Marta', age=28, salary=5500.0}
Person{name='Pietra', age=26, salary=3400.5}
Person{name='Ricardo', age=55, salary=3200.0}
Suponha que você deseja realizar a ordenação da lista pelo atributo age
de forma ascendente [0 – 9]. Veja na Listagem 4 como proceder:
- Listagem 4 – Método testSortThree
private static void testSortThree(List<Person> persons) {
persons.stream()
.sorted((p1, p2) -> p1.getAge().compareTo(p2.getAge()))
.forEach(p -> System.out.println(p));
}
Saída no console:
Person{name='Breno', age=22, salary=3330.7}
Person{name='Ana Maria', age=25, salary=3200.5}
Person{name='Pietra', age=26, salary=3400.5}
Person{name='Marta', age=28, salary=5500.0}
Person{name='Airton', age=29, salary=1500.5}
Person{name='Mario', age=34, salary=2200.5}
Person{name='Bianca', age=35, salary=3440.5}
Person{name='Fabiana', age=44, salary=4200.6}
Person{name='Ricardo', age=55, salary=3200.0}
Agora, caso você queira o retorno apenas com as idades e de forma ordenada, construa uma operação como a da Listagem 5.
- Listagem 5 – Método testSortFour
private static void testSortFour(List<Person> persons) {
persons.stream()
.mapToInt((p) -> p.getAge())
.sorted()
.forEach((p) -> System.out.printf("[%s]", p));
}
E o resultado seria o seguinte:
[22][25][26][28][29][34][35][44][55]
No método testSortFour()
foi incluído na operação o método mapToInt()
. Este método recebe como parâmetro uma expressão lambda que retorna para o processo o atributo que você deseja obter como resultado, substituindo assim, todo o objeto Person
pelo atributo age
. Então, age
é ordenado por sorted()
de forma natural, que seria o mesmo que de [0 – 9]. Por fim, usamos o foreach()
para imprimir no console o resultado obtido.
Referencia – https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html