Carolina Cunha
Posted on August 31, 2020
As interfaces funcionais não surgiram no Java 8: nas versões mais antigas, já era possível encontrar esse tipo de interface. Mas foi no Java 8 que elas adquiriram maior importância, uma vez que elas são peças fundamentais para a implementação das expressões lambdas. Mas o que é uma interface funcional?
Uma interface funcional é uma interface que possui apenas um método abstrato. Ela pode ter mais de um método, mas se apenas um deles for abstrato, ela será considerada uma interface funcional. Vamos utilizar a interface Comparator para exemplificar:
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
Essa interface contém mais métodos do que apenas o transcrito acima, e ela é interessante por alguns motivos que vou explicando ao longo do artigo. Para criar as comparações criei uma classe Livro:
public class Livro{
private String nome;
private int qtdPaginas;
public Livro(String nome, int qtdPaginas){
this.nome = nome;
this.qtdPaginas = qtdPaginas;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getQtdPaginas() {
return qtdPaginas;
}
public void setQtdPaginas(int qtdPaginas) {
this.qtdPaginas = qtdPaginas;
}
}
A criação de um Comparator utilizando a classe Livro seria:
Comparator<Livro> comparator = new Comparator<Livro>() {
@Override
public int compare(Livro o1, Livro o2) {
return o1.getNome().compareTo(o2.getNome());
}
};
Utilizando lambda, podemos ainda escrever o Comparator de forma mais simples:
Comparator<Livro> porNome =
(Livro o1, Livro o2)->o1.getNome().compareTo(o2.getNome());
Utilizando a classe anônima, vemos que o código fica um pouco confuso, porém o método que está sendo sobrescrito fica claro. Já quando utilizamos lambda, não fica explícito qual é o método da interface a ser sobrescrito, e é por isso que ela deve ser uma interface funcional: haverá apenas um método abstrato, que será sobrescrito.
Uma utilização desse
Comparator:
public static void main(String[] args){
Comparator<Livro> porNome =
(Livro o1, Livro o2)->o1.getNome().compareTo(o2.getNome());
List<Livro> livros = new ArrayList<>();
livros.add(new Livro("Morte e vida Severina", 240));
livros.add(new Livro("Vidas Secas", 190));
livros.add(new Livro("O Alienista", 150));
livros.add(new Livro("Alice no País das Maravilhas", 300));
livros.sort(porNome);
}
Ou ainda de forma mais direta:
public static void main(String[] args){
List<Livro> livros = new ArrayList<>();
livros.add(new Livro("Morte e vida Severina", 240));
livros.add(new Livro("Vidas Secas", 190));
livros.add(new Livro("O Alienista", 150));
livros.add(new Livro("Alice no País das Maravilhas", 300));
livros.sort((Livro o1, Livro o2)->o1.getNome().compareTo(o2.getNome()));
}
Todos os métodos de interfaces no Java são por padrão públicos e abstratos. Porém, em uma interface funcional também podem ser encontrados métodos default. A interface Comparator possui diversos métodos default, como:
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
default java.util.Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
default <U> java.util.Comparator<T> thenComparing(
Function<? super T, ? extends U> keyExtractor,
java.util.Comparator<? super U> keyComparator)
{
return thenComparing(comparing(keyExtractor, keyComparator));
}
}
Como anteriormente dito, não transcrevi todos os métodos presentes na interface, apenas alguns para mostrar que a ela pode possuir mais métodos, desde que sejam default methods.
O método boolean equals(Object obj); não descaracteriza a interface Comparator como funcional porque ele é uma sobrescrita do método equals da classe Object.
Para evitar que uma interface funcional fosse descaracterizada acidentalmente causando prejuízo na utilização de expressões lambda, no Java 8 foi introduzida a anotação FunctionalInterface. É uma anotação opcional para manter as demais interfaces funcionais que já existiam antes da versão 8 do Java funcionando normalmente. Se não for colocada mas ainda assim a interface tiver apenas um método abstrato, ela será considerada funcional.
Outros exemplos de interfaces funcionais no Java:
Comparable:
public interface Comparable<T> {
public int compareTo(T o);
}
Runnable:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
As interfaces Comparator e Runnable conceitualmente já eram consideradas interfaces funcionais antes de receberem a notação @FunctionalInterface no Java 8. A interface Comparable permanece sem a anotação.
Esse artigo faz parte de uma série que estou escrevendo enquanto revejo as funcionalidades do Java 8. Se gostou ou tem melhorias para sugerir, vou adorar saber!
Posted on August 31, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.