Java usando enum com instrução switch

106

Eu olhei várias perguntas e respostas sobre SO semelhantes a esta questão, mas não encontrei uma solução.

O que eu tenho é um enum que representa diferentes maneiras de ver um Guia de TV ...

Na Applicationclasse NDroid

static enum guideView {
    GUIDE_VIEW_SEVEN_DAY,
    GUIDE_VIEW_NOW_SHOWING,
    GUIDE_VIEW_ALL_TIMESLOTS
}

... quando o usuário altera a visualização, um manipulador de eventos recebe um intde 0-2 e eu gostaria de fazer algo assim ...

Em um Activity onClick(DialogInterface dialog, int which)manipulador de eventos Android

// 'which' is an int from 0-2
switch (which) {
    case NDroid.guideView.GUIDE_VIEW_SEVEN_DAY:
    ...
    break;
}

Estou acostumado com enums C # e instruções select / case que permitiriam algo como o acima e sei que o Java faz as coisas de maneira diferente, mas simplesmente não consigo entender o que preciso fazer.

Terei de recorrer a ifafirmações? Provavelmente haverá apenas 3 opções, então eu poderia fazer isso, mas me perguntei como isso poderia ser feito com switch-case em Java.

EDITAR Desculpe, não expandi completamente o problema, pois estava olhando para ele como um problema Java genérico. Eu acrescentei à pergunta para explicar um pouco mais.

Não há nada que seja específico do Android, e é por isso que não o marquei como Android, mas o enum é definido na Applicationclasse e o código em que desejo a troca está em um Activity. O enum é estático, pois preciso acessá-lo de várias atividades.

Squonk
fonte
1
Deve ser apenas case GUIDE_VIEW_SEVEN_DAYapós as importações adequadas; que problema (s) você está tendo?
Dave Newton
Você não pode simplesmente fazer seu manipulador de eventos receber um enum? Além disso, talvez isso ajude: stackoverflow.com/questions/5292790/…
Brian Roach
@Dave: Opa, desculpe, eu corrigi o código para mostrar como ele está. O Eclipse está me dando um erro de incompatibilidade de tipo, dizendo que não pode converter de guideView para int.
Squonk
@Brian: Este é um aplicativo Android e o manipulador de eventos ( OnClickListener ) é definido pela DialogInterfaceinterface que devo implementar.
Squonk
@MisterSquonk Oh, senti falta de que você estava recebendo de um int - desculpe, veja a resposta de Ophidian, embora eu tenha colocado a funcionalidade no enum.
Dave Newton

Respostas:

162

A parte que está faltando é a conversão do número inteiro para o enum de tipo seguro. Java não fará isso automaticamente. Existem algumas maneiras de fazer isso:

  1. Use uma lista de ints finais estáticos em vez de um enum de tipo seguro e ative o valor int que você recebe (esta é a abordagem pré-Java 5)
  2. Ative um valor de id especificado (conforme descrito por heneryville ) ou o valor ordinal dos valores de enum; ieguideView.GUIDE_VIEW_SEVEN_DAY.ordinal()
  3. Determine o valor enum representado pelo valor int e, a seguir, ative o valor enum.

    enum GuideView {
        SEVEN_DAY,
        NOW_SHOWING,
        ALL_TIMESLOTS
    }
    
    // Working on the assumption that your int value is 
    // the ordinal value of the items in your enum
    public void onClick(DialogInterface dialog, int which) {
        // do your own bounds checking
        GuideView whichView = GuideView.values()[which];
        switch (whichView) {
            case SEVEN_DAY:
                ...
                break;
            case NOW_SHOWING:
                ...
                break;
        }
    }
    

    Você pode achar mais útil / menos sujeito a erros escrever uma valueOfimplementação customizada que leva seus valores inteiros como um argumento para resolver o valor enum apropriado e permite centralizar sua verificação de limites.

Ofidiano
fonte
Muito Obrigado. Levei um tempo para trabalhar com meu código, mas agora está funcionando bem com o código de exemplo que você postou. 6 anos com C # e 1 ano com Java - não é sempre que encontro algo que me confunda. Tantas semelhanças, mas uma ocasional como esta que é muito diferente. Eu não esquecerei este tão rápido. :-)
Squonk
2
Você precisa dos nomes de enum não qualificados na instrução case, então case GuideView.SEVEN_DAY:dá um erro de compilação, deveria ser case SEVEN_DAY:.
haridsv
É excelente mano !!
Neo
41

Se whichViewfor um objeto do GuideView Enum, o seguinte funciona bem. Observe que não há qualificador para a constante depois case.

switch (whichView) {
    case SEVEN_DAY:
        ...
        break;
    case NOW_SHOWING:
        ...
        break;
}
Dhanushka
fonte
4
Como isso é possível?!
Jes Chergui
12

Os enums não devem ser qualificados no rótulo do caso, como o que você tem NDroid.guideView.GUIDE_VIEW_SEVEN_DAY, em vez disso, você deve remover a qualificação e usarGUIDE_VIEW_SEVEN_DAY

Piyush Mattoo
fonte
Prefere este. Simples!
Lazy Ninja de
5

Eu gosto de alguns usos do enum Java:

  1. .name () permite que você busque o nome enum em String.
  2. .ordinal () permite que você obtenha o valor inteiro, baseado em 0.
  3. Você pode anexar outros parâmetros de valor a cada enum.
  4. e, é claro, switch habilitado.

enum com parâmetros de valor:

    enum StateEnum {
        UNDEFINED_POLL  ( 1 * 1000L,       4 * 1000L),
        SUPPORT_POLL    ( 1 * 1000L,       5 * 1000L),
        FAST_POLL       ( 2 * 1000L,  4 * 60 * 1000L),
        NO_POLL         ( 1 * 1000L,       6 * 1000L); 
        ...
    }

exemplo de troca:

private void queuePoll(StateEnum se) {
    // debug print se.name() if needed
    switch (se) {
        case UNDEFINED_POLL:
            ...
            break;
        case SUPPORT_POLL:
            ...
            break;
david m lee
fonte
3

Isso deve funcionar da maneira que você descreve. que erro você está tendo? Se você pudesse colar seu código, isso ajudaria.

http://download.oracle.com/javase/tutorial/java/javaOO/enum.html

EDIT: Tem certeza de que deseja definir um enum estático? Isso não parece certo para mim. Um enum é muito parecido com qualquer outro objeto. Se o seu código compila e executa, mas fornece resultados incorretos, provavelmente é esse o motivo.

SystemParadox
fonte
"Tipos de enum aninhados são implicitamente estáticos. É permitido declarar explicitamente um tipo de enum aninhado como estático." - JLS §8.9 .
trashgod
@trashgod, de fato- mas eu sempre usaria a declaração implícita para evitar confusão, já que isso é realmente mais óbvio, IMO. Um enum estático global (que presumo que seja) provavelmente está errado na maioria dos casos.
SystemParadox
2
enumerations accessing is very simple in switch case

private TYPE currentView;

//declaration of enum 
public enum TYPE {
        FIRST, SECOND, THIRD
    };

//handling in switch case
switch (getCurrentView())
        {
        case FIRST:
            break;
        case SECOND:
            break;
        case THIRD:
            break;
        }

//getter and setter of the enum
public void setCurrentView(TYPE currentView) {
        this.currentView = currentView;
    }

    public TYPE getCurrentView() {
        return currentView;
    }

//usage of setting the enum 
setCurrentView(TYPE.FIRST);

avoid the accessing of TYPE.FIRST.ordinal() it is not recommended always
Jaya
fonte
Isso só funciona se você não estiver recebendo seus dados externamente. Uma vez que OP disse que retorna o valor 1, 2, 3 não é um TIPO, seu método não funcionaria sem um caso de switch reverso que leva 1, 2, 3 e retorna um TIPO antes de ir para o caso de switch que ele listou ..
WORMSS
2

Exemplo de função associativa curta:

public String getIcon(TipoNotificacao tipo)
{
    switch (tipo){
        case Comentou : return "fa fa-comments";
        case ConviteEnviou : return "icon-envelope";
        case ConviteAceitou : return "fa fa-bolt";
        default: return "";
    }
}

Como @Dhanushka disse, omitir o qualificador dentro de "switch" é a chave.

Auston
fonte
1

Eu estou fazendo como

public enum State
{
    // Retrieving, // the MediaRetriever is retrieving music //
    Stopped, // media player is stopped and not prepared to play
    Preparing, // media player is preparing...
    Playing, // playback active (media player ready!). (but the media player
                // may actually be
                // paused in this state if we don't have audio focus. But we
                // stay in this state
                // so that we know we have to resume playback once we get
                // focus back)
    Paused; // playback paused (media player ready!)

    //public final static State[] vals = State.values();//copy the values(), calling values() clones the array

};

public State getState()
{
        return mState;   
}

E usar na instrução Switch

switch (mService.getState())
{
case Stopped:
case Paused:

    playPause.setBackgroundResource(R.drawable.selplay);
    break;

case Preparing:
case Playing:

    playPause.setBackgroundResource(R.drawable.selpause);
    break;    
}
Zar E Ahmer
fonte