DEV Community

Carolina Cunha
Carolina Cunha

Posted on • Edited on

Interfaces Funcionais

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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());
            }
        };
Enter fullscreen mode Exit fullscreen mode

Utilizando lambda, podemos ainda escrever o Comparator de forma mais simples:

Comparator<Livro> porNome =
                (Livro o1, Livro o2)->o1.getNome().compareTo(o2.getNome());
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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()));
    }
Enter fullscreen mode Exit fullscreen mode

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));
    }
}

Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

Runnable:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
Enter fullscreen mode Exit fullscreen mode

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)