02 maio 2016

Java8: Modificador de acesso DEFAULT

A maioria dos desenvolvedores perceberam grandes mudanças em diversas APIs do Java 8, como adições de métodos em interfaces como sort(), foreach() e outros na interface List ou Stream, essa modificação só foi possível com a modificação do bytecode rodado na JVM, possibilitando a criação de um novo tipo modicador de acesso chamado default.

Um dos grandes problemas sempre foi a adição de novos métodos em interfaces antigas que necessitam de atualização como por exemplo a API de Collections, um novo método em uma interface torna a implementação necessária em todas as classes que implementam, assim quebrando a compatibilidade com versões anteriores da linguagem, dado a restrição a API de Collections foi criada na versão 1.2 em 1998 e ficou 20 anos sem nenhuma modificação.

Esse modificador chamado de default foi criado com a finalidade de criar métodos em interfaces sem quebrar o contrato com classes existentes, uma peculiaridade é que esses métodos necessitam a criação de um de um comportamento padrão, e por isso são chamados de métodos padrão (default methods).

Vemos o método adicionado ao código na interface List, chamado .sort(), a necessidade veio de não ser mais necessário ter que chamar uma classe utilitária externa.

 @SuppressWarnings({"unchecked", "rawtypes"})
  default void sort(Comparator c) {
      Object[] a = this.toArray();
      Arrays.sort(a, (Comparator) c);
      ListIterator i = this.listIterator();
      for (Object e : a) {
          i.next();
          i.set((E) e);
      }
  }

Vamos implementar uma classe de teste para entender os conceitos e comportamentos a feature.

package io.redspark.java8.modifierdefault;

import org.junit.Assert;
import org.junit.Test;

public class DefaultModifierTest {

  public interface Fighter {  
    default String fight() {
      return "Fight with knife";
    }
  }
 
  public interface BasicFighter {
    default String fight(){
      return "Fight with hand";
    }
  }
 
  public class HumanFighter implements Fighter {}
  public class GlobinFighter implements Fighter {
    @Override
    public String fight() {
      return "Fight with axe";
    }
  }

  /**
   * default access enable implement methods without obligatoriness and must have a default behavior.
   */

  @Test
  public void testDefaultMethodWithBehavior() throws Exception {
     
    HumanFighter humanFighter = new HumanFighter();
    Assert.assertEquals("Fight with knife", humanFighter.fight());
   
    GlobinFighter globinFighter = new GlobinFighter();
    Assert.assertEquals("Fight with axe", globinFighter.fight());
  }

}

A criação de métodos com comportamento padrão evita outro problema na modelagem de objetos, uso indiscriminado de herança, esse novo tipo de contrato garante que humanos e globins lutem com um comportamento padrão, sem a necessidade de estender uma classe abstrata por exemplo.

Suporte a multiplas intefaces

Todo o comportamento padrão de interfaces é mantido, como vimos GlobinFighter simplesmente sobrescreve o método com o comportamento de um globin, assim como podemos usar múltiplas interfaces, mas nesse caso é necessário na classe concreta.

package io.redspark.java8.modifierdefault;

import org.junit.Assert;
import org.junit.Test;

public class DefaultModifierTest {

  public interface Fighter {  
    default String fight() {
      return "Fight with knife";
    }
  }
 
  public interface BasicFighter {
    default String fight(){
      return "Fight with hand";
    }
  }
 
  public class HumanFighter implements Fighter {}

  public class PoorFighter implements BasicFighter, Fighter {
    @Override
    public String fight() {
      return BasicFighter.super.fight();
    }
  }

  @Test
  public void testCreateClassWithMultipleInterfaceAndUsingSameNameOfDefaultMethod() throws Exception {
   
    PoorFighter poorFighter = new PoorFighter();
    Assert.assertEquals("Fight with hand", poorFighter.fight());
  }
}

Os exemplos completos podem ser conferidos nesse repositório no Github.

About Lucas Martins

Software Engineer at Holmes, to know me better @lucasgmmartins at Twitter and my technical blog https://medium.com/@lucasflice/

Leave a Comment