BT

A evolução das Enums no Java

| por Abraham Marín Pérez , traduzido por Diogo Carleto em 17 Fev 2017. Tempo estimado de leitura: 3 minutos |

As Enums do Java ganharão suporte ao generics com a possibilidade de adicionar métodos para itens individuais. Uma vez que ambas funcionalidades podem ser entregues com a mesma mudança de código, foram empacotadas na mesma JEP. A mudança afeta somente o compilador do Java, portanto não é necessário alterar o runtime. Embora não tenha sido definida uma versão, provavelmente chegará no Java 10.

A mudança inicialmente não teve uma reação positiva, com Java Champions de renome como Joshua Bloch questionando sua utilidade. Entretanto, alguns debates mais aprofundados e a apresentação de novos casos de uso ajudaram a obter apoio.

Veremos o que o desenvolvedor pode fazer resumindo alguns dos casos de usos apresentados no JEP e outras discussões. O Lukas Eder, Java Champion, postou uma pergunta no StackOverflow sobre um caso para recuperar e definir propriedades a partir de um arquivo de configuração, sessão web ou similar de uma maneira segura. Um enum com suporte à generics permitiria indicar os conjuntos de chaves disponíveis junto com o seu tipo associado:

public enum Key {
    HOST,
    PORT,
    SCORE
}

public interface PropertiesStore {
    public  void put(Key key, T value);
    public  T get(Key key);
}

Agora estas chaves podem ser recuperadas e salvas com segurança, uma vez que expressões como a seguir falharão em tempo de compilação:

put(PORT, “not a number”); // Erro, tipo incompatível: PORT é Key<Integer>
                           // "not a number" é String

Em contrapartida, permitir que itens possam ter seus próprios métodos pode ajudar a definir operações que são aplicadas somente para certas propriedades. Sob a JEP 301, a definição anterior pode ser expandida da seguinte maneira:

public enum Key {
    HOST,
    PORT,
    SCORE {
        double normalise(double x) {
            // lógica de normalização de score
            return result;
        }
    }
}

Atualmente todos os itens do enum teriam o tipo genérico Key, significando que o método normalise não seria visível. Entretanto, após a conclusão da alteração, o compilador preservaria este tipo de informação, desta forma o seguinte seria verdade:

SCORE.normalise(5.37); // compila
HOST.normalise(5.37); // erro: ambos HOST e Key nâo tem o normalise

A maneira para conseguir isso será alterando a forma como são expostos os tipos estáticos dos itens individuais do enum. As enums foram adicionadas apenas para facilitar a vida: a JVM não tem nenhum tratamento especial para enums, o compilador traduz o código de uma enum para uma classe normal com objetos estáticos, e então a compila em bytecode. Deixando de lado alguns aspectos técnicos, segue uma enum:

public enum Colour {
     RED, GREEN, BLUE
}

O compilador traduz para algo similar a representação a seguir:

public class Colour extends Enum {
    public static final Colour RED = new Colour();
    public static final Colour GREEN = new Colour();
    public static final Colour BLUE = new Colour();

    private Colour() {}
}

Dado que todos os itens são do tipo Colour, qualquer método específico ou informação de tipo é perdida. O que a JEP 301 propõe é identificar os casos no qual o uso de um enum de tipo genérico não é o bastante para representar os itens individualmente, e neste caso gerar um tipo mais específico como Colour$RED, Colour$GREEN e Colour$BLUE.

As enums melhoradas podem se beneficiar ainda mais de outros esforços que estão sendo realizados atualmente em outras partes do JDK. Por um lado, a inferência de tipos em variáveis locais pode permitir que os desenvolvedores aproveitem dos tipos criados, mesmo que seja desconhecido no momento da codificação, isso significa que, considerando o código anterior, o seguinte seria possível:

var s = Key.SCORE; // tipo de s derivado como Key$SCORE
s.normalise(8.29); // // o método normalise pode ser acessado

Entretanto, analisando as evidências e casos de uso, os exemplos sugerem que generics em enums podem ser usados extensivamente com tipos primitivos, o que é bastante ineficiente (já que a JVM tem que usar o autoboxing para cada primitivo). Isso pode ser aperfeiçoado com parte do projeto Valhalla que lida com Generics sobre tipos primitivos, removendo essa barreira e disponibilizando para o uso em massa.

Avalie esse artigo

Relevância
Estilo/Redação

Olá visitante

Você precisa cadastrar-se no InfoQ Brasil ou para enviar comentários. Há muitas vantagens em se cadastrar.

Obtenha o máximo da experiência do InfoQ Brasil.

Dê sua opinião

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão
Comentários da comunidade

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

Dê sua opinião
BT