Parte 1 - Introdução às expressões Lambdas
Parte 2 - As interfaces funcionais e as novidades da API Collections
Parte 3 - A classe Stream e conclusão
Introdução às expressões Lambdas
As
mudanças presentes no Java 8 são as mais profundas das últimas
versões. Junto com essas mudanças temos a adição das expressões
lambdas. O objetivo maior é facilitar a criação de implementações
de interfaces, evitando assim a grande de quantidade de código
quando usamos classes anônimas. Essa funcionalidade, no entanto, vai
muito além disso, ela traz características funcionais à plataforma
Java e a API Collections foi redefinida para uso mais intensivo das
expressões Lambdas.
A
necessidade de uso de expressões de código que devem ser executadas
após determinada ação é possível no Java através do uso de
interfaces cuja implementação deveriam ser informadas por quem usa
a API. Um exemplo comum é quando queremos informar qual tarefa uma
thread deve executar, fornecemos a implementação da interface
Runnable e nela escrevemos o corpo do código run.
Vejam que essa abordagem é uma forma orientada a objetos de
conseguirmos um comportamento comum em linguagens ditas funcionais.
A
introdução de expressões lambdas trouxe também algumas alterações
na API básica do Java SE. Foi introduzido um novo pacote
java.util.function que traz
diversas interfaces com um só método a ser implementado, cujo nome
passa a ser interface funcional no Java 8. A das Collections foi
também modificada para possibilitar a manipulação de listas
através do uso de Lambdas.
O conceito, a sintaxe e as mudanças na API Java para se adequar às
expressões Lambdas serão discutidas nesse artigo.
Uso
de classes anônimas e as interfaces funcionais
Constantemente
vemos na API do Java o uso de interfaces que contém somente um
método abstrato, que deve ser implementado pelo usuário de
determinada funcionalidade. Um exemplo clássico é com relação às
threads, onde temos que implementar a interface Runnable e o
método run para informar qual tarefa será executada. Na
Listagem 1 você pode ver uma implementação usando a
convencional classe anônima do Java. Note que temos que definir toda
a assinatura do método e também escrever bastante código só para
definirmos nossa classe anônima. Somente o corpo do método run é
onde está o código que nos interessa.
Listagem
1. Definindo um Runnable usando uma classe anônima
Runnable
r = new Runnable(){
public
void run(){
System.out.println("Task
rodando...");
}
};
new
Thread(r).start();
Outro
ótimo exemplo é relacionando a definição de um código que deve
ser ativado quando determinado evento acontece. Por exemplo,
normalmente temos um método que é executado quando um botão da
interface gráfica é clicado. Com o JavaFX tratamos o evento usando
uma implementação da interface EventHandler como
mostra a Listagem 2,
onde temos o registro de um código para execução quando o ponteiro
do mouse move sobre o Label.
O
Java 8 traz o JavaFX como uma API padrão. As classes da nova
biblioteca gráfica da plataforma Java podem ser usadas sem nenhuma
biblioteca adicional
Listagem
2. Um ouvinte para o evento MouseMoved de um Label
Label
lbl = new Label("Passe o Mouse!");
lbl.setOnMouseMoved(new
EventHandler<MouseEvent>(){
public
void handle(MouseEvent e){
System.out.println("Mouse
movendo sob o Label");
}
});
Por fim,
quando queremos ordenar uma lista, temos que criar uma implementação
da interface Comparator, onde definimos o nosso critério de
comparação para que a ordenação seja feita. Na Listagem 3
temos um exemplo de uma implementação de Comparator para
realizar a ordenação de uma lista de Pessoas. O método compare
deve ser escrito para determinamos a comparação.
Listagem
3. Criando um Comparator para ordenação de uma lista
Collections.sort(pessoas,
new Comparator() {
public
int compare(Pessoa p1, Pessoa p2) {
return
p1.compareTo(p2);
}
}
O que
vemos nas listagens 1, 2 e 3 é o uso de interfaces que contém
somente um método abstrato. Na interface Runnable temos o
método run, que não recebe nenhum parâmetro e não
retornada nada, na interface EventHandler implementamos o
método handle que recebe um
parâmetro dependendo do tipo genérico da implementação e na
implementação do Comparator
temos dois parâmetros recebidos e um retorno. No Java 8
chamamos interfaces desse tipo de interfaces funcionais.
Uma
outra novidade do Java 8 são as modificações na definição de
interfaces, sendo que estas começam a ter suporte a métodos com uma
implementação padrão(que podem
ser redefinidos pela classe implementadora), métodos
estáticos(semelhantes a métodos estáticos em classes) e métodos
finais(que não podem
ser redefinidos pela classe implementadora) e os clássicos métodos
abstratos(que devem ser
redefinidos)
Substituindo
interfaces funcionais por expressões Lambdas
A expressão Lambda deve ser definida através de uma interface
funcional. Veja respectivamente nas listagens 4, 5, 6 como fica a
implementação das interfaces Runnable, EventHandler e
Comparator usando expressões Lambdas.
Listagem
4. Definindo um Runnable usando uma expressão Lambda
Runnable
r = () -> System.out.println("Task rodando...");
new
Thread(r).start();
Listagem
5. Definindo um Eventhandler com Lambdas
Label
lbl = new Label("Passe o Mouse!");
lbl.setOnMouseMoved(e
-> System.out.println("Mouse movendo sob o Label"));
Listagem
6. Um Comparator usando Lambda
Collections.sort(pessoas,
(p1,p2)-> p1.compareTo(p2));
Muito mais
simples, não? Note que uma expressão Lambda segue o seguinte
padrão: Lista de parâmetros -> bloco de
código, onde:
- lista de parâmetros: pode incluir o tipo dos parâmetros, não é obrigatório. O compilador fará inferência de tipo de acordo com a declaração da interface funcional. Quando não temos parâmetros, podemos simplesmente utilizar parênteses () como você pode ver na Listagem 4. Quando há um parâmetro único, não precisamos de parentêses, veja a Listagem 5. Quando há mais de um parâmetro, eles devem ser separados por vírgula, como mostrado na Listagem 6.
- ->: Esse é o indicar que procede o corpo da expressão Lambda;
- bloco de código: É onde vai nosso código em sí. Entre chaves você pode escrever o código como se fosse o corpo de um método comum entre chaves {}, veja a Listagem 6. Quando há uma só expressão, podemos omitir as chaves, veja as Listagens 4 e 5.
Na API padrão do Java já há diversos exemplos onde podemos aplicar
o que acabamos de aprender, no entanto, algumas adições foram
feitas ao Java 8 para maior uso dos Lambdas.
Continuamos na parte 2...
Nenhum comentário:
Postar um comentário