Forem

FUNDAMENTOS JAVA
FUNDAMENTOS JAVA

Posted on

Java 8 e Lambda

Estudos do livro Java 8 Prático - Casa do Código

Evolução do Java

Java 5 (2004)

  • Introdução de generics, enums e anotações

Java 8 (2014)

  • Introdução de lambda e method references

  • Atualizações na API de Collections

  • Streams

  • Métodos default

Lambda

Exemplo:
Classe Usuario com os atributos:
pontos (pontuação do usuário)
nome (nome do usuário)
moderador (booleano indicando se é moderador)

class Usuario {
private String nome;
private int pontos;
private boolean moderador;
public Usuario(String nome, int pontos) {
this.pontos = pontos;
this.nome = nome;
this.moderador = false;
}
public String getNome() {
return nome;
}
public int getPontos() {
return pontos;
}
public void tornaModerador() {
this.moderador = true;
}
public boolean isModerador() {
return moderador;
}
}

O primeiro exemplo usará a abordagem clássica, sem recursos novos do Java 8.

public class Capitulo2 {
public static void main(String ... args) {
Usuario user1 = new Usuario("Paulo Silveira", 150);
Usuario user2 = new Usuario("Rodrigo Turini", 120);
Usuario user3 = new Usuario("Guilherme Silveira", 190);
List<Usuario> usuarios = Arrays.asList(user1, user2, user3);
for(Usuario u : usuarios) {
System.out.println(u.getNome());
}
}
}

  • Arrays.asList cria uma lista imutável rapidamente.

  • Alternativamente, poderia ser usada uma ArrayList e adicionar elementos manualmente.

  • Desde o Java 5, é possível usar o for-each para percorrer: Arrays, coleções e objetos que implementam Iterable.

Novo Método forEach em Coleções

  • Introduzido no Java 8 para facilitar iteração sobre coleções.

  • Recebe um argumento do tipo Consumer, uma interface funcional do java.util.function.

usuarios.forEach(...);

Arquivo: Capitulo2Exemplo2.java

Implementação do Consumer

class Mostrador implements Consumer<Usuario> {
public void accept(Usuario u) {
System.out.println(u.getNome());
}
}

Arquivo: Mostrador.java

  • O método accept executa uma ação sobre cada elemento (imprimir nome do usuário).

Passando a classe para o forEach:

Mostrador mostrador = new Mostrador();
usuarios.forEach(mostrador);

Arquivo: Capitulo2Exemplo3.java

Uso de Classe Anônima

usuarios.forEach(new Consumer<Usuario>() {
public void accept(Usuario u) {
System.out.println(u.getNome());
}
});

Arquivo: Capitulo2Exemplo4.java

  • Gera um arquivo .class com nome interno estranho (ex.: Capitulo2$1.class).

Que entre o Lambda!

Em vez de escrever:

Consumer<Usuario> mostrador = new Consumer<Usuario>() {
public void accept(Usuario u) {
System.out.println(u.getNome());
}
};

Podemos escrever:

Consumer<Usuario> mostrador =
(Usuario u) -> {System.out.println(u.getNome());};

Arquivo: Capitulo2Exemplo5.java

Uso de Lambda no forEach

(Usuario u) -> { System.out.println(u.getNome()); }

  • O compilador infere que se trata de um Consumer e o mapeia para o método accept automaticamente.

Simplificação do Lambda

1 O compilador pode inferir o tipo, removendo Usuario e os parênteses:

Consumer<Usuario> mostrador = u -> { System.out.println(u.getNome()); };

2 Se houver apenas uma instrução, {} e ; podem ser omitidos:

Consumer<Usuario> mostrador = u -> System.out.println(u.getNome());

3 Pode ser passado diretamente para forEach, sem variável temporária:

usuarios.forEach(u -> System.out.println(u.getNome()));

Arquivo: Capitulo2Exemplo6.java

Lambda vs. Classe Anônima

  • Diferente das classes anônimas (Capitulo2$N.class), lambdas são tratados de forma mais otimizada pelo compilador.

Alterando Objetos

usuarios.forEach(u -> u.tornaModerador());

  • A variável u não pode ter sido declarada no mesmo escopo, pois lambdas podem capturar variáveis externas (será explorado depois).

Top comments (0)