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!
Top comments (0)