Default Methods e Métodos Estáticos em Interfaces
Tags: java, beginners, oop, design
Published: 2020-11-04 18:46:26

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()_:

```java
default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
```
```java
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()));
    }
```
Saída:
![Saída do console após execução do método acima](https://dev-to-uploads.s3.amazonaws.com/i/80w5ha41k23wsgt3xx6i.png)

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:

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

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()_:

```java
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        return Collections.reverseOrder();
    }
```
```java
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    }
```
```java
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 + " "));
    }
```
Saída:
![Saída do console após execução do método acima](https://dev-to-uploads.s3.amazonaws.com/i/irltxtoq1pzyolfij12a.png)

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!