Java с использованием enum с оператором switch


106

Я просмотрел различные вопросы и ответы на SO, похожие на этот вопрос, но не нашел решения.

У меня есть перечисление, которое представляет различные способы просмотра телегида ...

В Applicationклассе NDroid

static enum guideView {
    GUIDE_VIEW_SEVEN_DAY,
    GUIDE_VIEW_NOW_SHOWING,
    GUIDE_VIEW_ALL_TIMESLOTS
}

... когда пользователь меняет представление, обработчик событий получает сообщение intот 0 до 2, и я хотел бы сделать что-то вроде этого ...

В Activity onClick(DialogInterface dialog, int which)обработчике событий Android

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

Я привык к перечислениям C # и операторам select / case, которые позволяют делать что-то вроде приведенного выше, и я знаю, что Java работает иначе, но я просто не могу понять, что мне нужно делать.

Придется ли мне прибегать к ifзаявлениям? Скорее всего, когда-либо будет только 3 варианта, чтобы я мог это сделать, но мне было интересно, как это можно сделать с помощью switch-case в Java.

ИЗМЕНИТЬ Извините, я не полностью раскрыл проблему, так как рассматривал ее как общую проблему Java. Я добавил к вопросу, чтобы немного пояснить.

Нет ничего специфичного для Android, поэтому я не пометил его как Android, но перечисление определено в Applicationклассе, а код, в котором я не хочу переключаться, находится в файле Activity. Перечисление статично, так как мне нужно получить к нему доступ из нескольких Activity.


1
Должен быть сразу case GUIDE_VIEW_SEVEN_DAYпосле надлежащего импорта; Какие у вас проблемы?
Дэйв Ньютон

Разве вы не можете просто заставить обработчик событий получать перечисление? Кроме того, возможно, это поможет: stackoverflow.com/questions/5292790/…
Брайан Роуч

@ Дэйв: Ой, извини, я исправил код, чтобы показать, как он есть. Eclipse выдает ошибку несоответствия типов, говоря, что он не может преобразовать из guideView в int.
Squonk

@Brian: Это приложение для Android, и обработчик событий ( OnClickListener ) определяется DialogInterfaceинтерфейсом, который я должен реализовать.
Squonk

@MisterSquonk О, я скучал, что вы получали его от int - извините, см. Ответ Ophidian, хотя я бы поместил функциональность в перечисление.
Дэйв Ньютон

Ответы:


162

Часть, которую вам не хватает, - это преобразование целого числа в типобезопасное перечисление. Java не сделает этого автоматически. Есть несколько способов сделать это:

  1. Используйте список статических конечных целых чисел, а не типобезопасное перечисление, и включите полученное значение int (это подход до Java 5)
  2. Включите либо указанное значение id (как описано heneryville ), либо порядковое значение значений перечисления; т.е.guideView.GUIDE_VIEW_SEVEN_DAY.ordinal()
  3. Определите значение перечисления, представленное значением int, а затем включите значение перечисления.

    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;
        }
    }

    Вы можете найти более полезным / менее подверженным ошибкам написать собственную valueOfреализацию, которая принимает ваши целочисленные значения в качестве аргумента для разрешения соответствующего значения перечисления и позволяет централизовать проверку границ.


Большое спасибо. Мне потребовалось время, чтобы проработать это в моем коде, но теперь он отлично работает с примером кода, который вы опубликовали. 6 лет с C # и 1 год с Java - не часто я сталкиваюсь с чем-то, что меня ставит в тупик. Так много сходств, но такие редкие, как это, очень разные. Я не забуду это в спешке. :-)
Squonk

2
Вам нужны неквалифицированные имена перечислений в операторе case, поэтому case GuideView.SEVEN_DAY:выдает ошибку компиляции, она должна быть case SEVEN_DAY:.
haridsv 08

Это превосходно, братан !!
Нео

42

Если whichViewэто объект GuideView Enum, следующее работает хорошо. Обратите внимание, что для константы после нет квалификатора case.

switch (whichView) {
    case SEVEN_DAY:
        ...
        break;
    case NOW_SHOWING:
        ...
        break;
}

4
Как это вообще возможно?!
Jes Chergui

12

Перечисления не должны быть квалифицированы внутри метки case, как у вас NDroid.guideView.GUIDE_VIEW_SEVEN_DAY, вместо этого вам следует удалить квалификацию и использоватьGUIDE_VIEW_SEVEN_DAY


Предпочитает этот. Просто!
Lazy Ninja

5

Мне нравится несколько вариантов использования Java enum:

  1. .name () позволяет вам получить имя перечисления в String.
  2. .ordinal () позволяет получить целочисленное значение, отсчитываемое от 0.
  3. Вы можете присоединить другие параметры значения к каждому перечислению.
  4. и, конечно же, переключатель включен.

перечисление со значениями параметров:

    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); 
        ...
    }

пример переключателя:

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

3

Это должно работать так, как вы описываете. Какую ошибку вы получаете? Если бы вы могли вставить свой код, это помогло бы.

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

EDIT: вы уверены, что хотите определить статическое перечисление? Мне это не кажется правильным. Перечисление очень похоже на любой другой объект. Если ваш код компилируется и запускается, но дает неверные результаты, вероятно, причина в этом.


«Вложенные перечисляемые типы неявно статичны. Допускается явное объявление вложенного перечислимого типа как статического» - JLS §8.9 .
trashgod

@trashgod, действительно, но я всегда буду использовать неявное объявление, чтобы избежать путаницы, поскольку это на самом деле более очевидное ИМО. Глобальное статическое перечисление (как я полагаю) в большинстве случаев, вероятно, неверно.
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

Это работает, только если вы не получаете данные извне. Поскольку OP сказал, что возвращает значение 1, 2, 3, а не TYPE, ваш метод не будет работать без случая обратного переключения, который принимает 1, 2, 3 и возвращает TYPE перед тем, как перейти к случаю переключения, который он перечислил.
WORMSS

2

Краткий пример ассоциативной функции:

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 "";
    }
}

Как сказал @Dhanushka, опустить квалификатор внутри "switch" - это ключ.


1

Я делаю это как

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;   
}

И использовать в заявлении Switch

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

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

case Preparing:
case Playing:

    playPause.setBackgroundResource(R.drawable.selpause);
    break;    
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.