DEV Community

Carolina Cunha
Carolina Cunha

Posted on

Default Methods e Métodos Estáticos em Interfaces

Continuando na saga de rever as funcionalidades e conceitos que foram introduzidos na versão 8 do Java, hoje vou falar um pouquinho de default methods e métodos estáticos em interfaces.

Antes da versão 8 do Java, caso fosse necessário adicionar métodos em uma interface, obrigatoriamente esses métodos teriam que ser implementados em todas as implementações daquela interface. Se estivermos falando de uma interface muito usada, como a interface Comparator, a adição de métodos acarretaria a quebra de todos os sistemas construídos nas versões anteriores do Java que utilizam essa interface. Para permitir a evolução de interfaces sem causa a quebra de código, foram inseridos na versão 8 do Java os default methods.

Os default methods são métodos contendo código que são declarados em interfaces e, diferente dos demais métodos da interface, eles não precisam ser implementados em todas as implementações da interface. Outra vantagem é que uma vez adicionados, todas as implementações da interface passam a ter acesso a eles.

Como disse antes, para exemplificar vou utilizar a interface Comparator. A interface Comparator nos acompanha desde os primórdios do Java (mais especificamente desde a versão 1.2), porém a partir da versão 1.8 ela ganhou diversos métodos, como o reversed():

default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
Enter fullscreen mode Exit fullscreen mode
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));

        Comparator<Livro> comparator = new Comparator<Livro>() {
            @Override
            public int compare(Livro o1, Livro o2) {
                return o1.getNome().compareTo(o2.getNome());
            }
        };
        System.out.println("Ordem Natural:");
        livros.sort(comparator);
        livros.forEach(l -> System.out.println(l.getNome()));

        System.out.println("---------------------");

        System.out.println("Ordem Contrária:");
        livros.sort(comparator.reversed());
        livros.forEach(l -> System.out.println(l.getNome()));
    }
Enter fullscreen mode Exit fullscreen mode

Saída:
Saída do console após execução do método acima

A adição desse método não comprometeu o funcionamento dos sistemas que já utilizavam essa interface. Esse é o principal objetivo dos default methods: preservar a estabilidade dos sistemas de versões anteriores quando for necessário alterar interfaces.

No exemplo acima, eu utilizei o método sort() da interface List, que também foi um default method adicionado na versão 8 do Java! Ele foi adicionado para facilitar a ordenação das listas. A sintaxe dele é a seguinte:

default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }
Enter fullscreen mode Exit fullscreen mode

Já pensou como poderíamos inserir novas funcionalidades em uma interface tão usada como a List sem causar um caos nos sistemas já existentes? Daí a importância desse novo recurso.

Outro recurso interessante adicionado no Java 8 foi a possibilidade de se implementar métodos estáticos nas interfaces, que podem trazer funcionalidades úteis às interfaces sem comprometer o funcionamento de códigos legados.

Voltando à interface Comparator, vamos observar os métodos reverseOrder() e naturalOrder():

public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        return Collections.reverseOrder();
    }
Enter fullscreen mode Exit fullscreen mode
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    }
Enter fullscreen mode Exit fullscreen mode
public static void main(String[] args){
        List<Integer> numeros = Arrays.asList(300,19,32,10,69);
        System.out.println("Ordem Natural:");
        numeros.sort(Comparator.naturalOrder());
        numeros.forEach(n-> System.out.print(n + " "));
        System.out.println();
        System.out.println("Ordem Contrária:");
        numeros.sort(Comparator.reverseOrder());
        numeros.forEach(n-> System.out.print(n + " "));
    }
Enter fullscreen mode Exit fullscreen mode

Saída:
Saída do console após execução do método acima

Esse são recursos muito úteis, mas é importante salientar que não devem ser usados para herança. Já existem vários outros recursos de herança no Java, como a Composição, por exemplo. Use com moderçã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)