Interfaces Funcionais

ccunha

Carolina Cunha

Posted on August 31, 2020

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!

💖 💪 🙅 🚩
ccunha
Carolina Cunha

Posted on August 31, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Interfaces Funcionais
beginners Interfaces Funcionais

August 31, 2020