Подтвердить что ты не робот

Записи Java и состояния коммутатора - случай по умолчанию?

Для людей, предлагающих бросать исключение:
Выбрасывание исключения не дает мне ошибки времени компиляции, это дает мне ошибку времени выполнения. Я знаю, что могу исключить исключение, лучше умереть во время компиляции, чем во время выполнения.

Вначале я использую eclipse 3.4.

У меня есть модель данных, которая имеет свойство mode, которое является Enum.

enum Mode {on(...), off(...), standby(...); ...}

В настоящее время я пишу представление этой модели, и у меня есть код

...
switch(model.getMode()) {
case on:
   return getOnColor();
case off:
   return getOffColor();
case standby:
   return getStandbyColor();
}
...

Я получаю сообщение об ошибке "Этот метод должен возвращать результат типа java.awt.Color", потому что у меня нет случая по умолчанию и нет возврата xxx в конце функции. Я хочу ошибку компиляции в случае, когда кто-то добавляет другой тип в перечисление (например, shuttingdown), поэтому я не хочу ставить случай по умолчанию, который генерирует AssertionError, поскольку он будет компилироваться с измененным режимом и не будет как ошибка до выполнения.

Мой вопрос таков:
Почему EclipseBuilder (и javac) не признает, что этот переключатель охватывает все возможности (или охватывает их?) И перестает предупреждать меня о необходимости возврата типа. Есть ли способ сделать то, что я хочу, не добавляя методы в режим?

Если это не так, существует ли опция предупреждения/ошибки в операторах switch, которые не охватывают все возможные значения Enum?

Изменить: Роб: Это ошибка компиляции. Я просто попытался скомпилировать его с помощью javac, и я получаю сообщение об ошибке "missing return statement", нацеленное на последний метод. Eclispe просто помещает ошибку в начало метода.

4b9b3361

Ответ 1

Вы всегда можете использовать шаблон Enum with Visitor:

enum Mode {
  on {
      public <E> E accept( ModeVisitor<E> visitor ) {
         return visitor.visitOn();
      }
  },
  off {
      public <E> E accept( ModeVisitor<E> visitor ) {
         return visitor.visitOff();
      }
  },
  standby {
      public <E> E accept( ModeVisitor<E> visitor ) {
         return visitor.visitStandby();
      }
  }

  public abstract <E> E accept( ModeVisitor<E> visitor );

  public interface ModeVisitor<E> {
      E visitOn();
      E visitOff();
      E visitStandby();
  }
}

Затем вы реализуете что-то вроде следующего:

public final class ModeColorVisitor implements ModeVisitor<Color> {
    public Color visitOn() {
       return getOnColor();
    }

    public Color visitOff() {
       return getOffColor();
    }

    public Color visitStandby() {
       return getStandbyColor();
    }

}

Вы использовали бы его следующим образом:

return model.getMode().accept( new ModeColorVisitor() );

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

Ответ 2

Вам нужно включить в настройках Eclipse (окно → настройки) "Константа типа Enum, не включенная в коммутатор" с уровнем ошибки.

Выбросить исключение в конце метода, но не использовать случай по умолчанию.

public String method(Foo foo)
  switch(foo) {
  case x: return "x";
  case y: return "y";
  }

  throw new IllegalArgumentException();
}

Теперь, если кто-то добавит новый случай позже, Eclipse заставит его узнать, что он пропустил случай. Поэтому никогда не используйте умолчания, если у вас нет оснований для этого.

Ответ 3

Я не знаю, почему вы получили эту ошибку, но вот предложение: почему бы вам не определить цвет в самом enum? Тогда вы не можете случайно забыть определить новый цвет.

Например:

import java.awt.Color;

public class Test {

    enum Mode 
    {
        on (Color.BLACK), 
        off (Color.RED),
        standby (Color.GREEN);

        private final Color color; 
        Mode (Color aColor) { color = aColor; }
        Color getColor() { return color; }
    }

    class Model
    {
        private Mode mode;
        public Mode getMode () { return mode; }
    }

    private Model model;

    public Color getColor()
    {
        return model.getMode().getColor();
    }   
}

btw, для сравнения здесь исходный случай, с ошибкой компилятора.

import java.awt.Color;
public class Test {

    enum Mode {on, off, standby;}

    class Model
    {
        private Mode mode;
        public Mode getMode () { return mode; }
    }

    private Model model;

    public Color getColor()
    {
        switch(model.getMode()) {
        case on:
           return Color.BLACK;
        case off:
           return Color.RED;
        case standby:
           return Color.GREEN;
        }
    }   
}

Ответ 4

Я бы сказал, вероятно, потому, что model.GetMode() мог возвращать null.

Ответ 5

Создайте случай по умолчанию, который выдает исключение:

throw new RuntimeExeption("this code should never be hit unless someone updated the enum") 

... и это в значительной степени описывает, почему Eclipse жалуется: пока ваш коммутатор может охватывать все случаи перечисления сегодня, кто-то может добавить случай и не перекомпилировать завтра.

Ответ 6

Почему EclipseBuilder не распознает, что этот переключатель охватывает все возможности (или закрывает их?) и перестает предупреждать меня о необходимости возврата типа. Есть ли способ сделать то, что я хочу, не добавляя методы в режим?

Это не проблема в Eclipse, а скорее компилятор, javac. Все javac видит, что у вас нет возвращаемого значения в случае, когда ничего не сопоставляется (факт, что вы знаете, что вы соответствуете всем случаям, не имеет значения). Вы должны что-то вернуть в случае по умолчанию (или выбросить исключение).

Лично я просто выброшу какое-то исключение.

Ответ 7

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

Дело в том, что оператор switch и компилятор java не могут распознать, что вы не хотите разрешать другие параметры в вашем перечислении. Тот факт, что вы хотите только три варианта в перечислении, полностью отделен от вашего дизайна оператора switch, который, как отмечают другие, должен ВСЕГДА иметь инструкцию по умолчанию. (В вашем случае это должно вызвать исключение, потому что это необработанный сценарий.)

Вы должны свободно посыпать свой enum комментариями, чтобы каждый знал, что не прикасаться к нему, и вы должны исправить оператор switch, чтобы вызывать ошибки для непризнанных случаев. Таким образом, вы охватили все базы.

ИЗМЕНИТЬ

По вопросу об ошибке компилятора. Это не имеет особого смысла. У вас есть перечисление с тремя параметрами и переключатель с тремя параметрами. Вы хотите, чтобы он выдал ошибку компилятора, если кто-то добавляет значение в перечисление. За исключением того, что перечисления могут быть любого размера, поэтому не имеет смысла бросать ошибку компилятора, если кто-то ее изменяет. Кроме того, вы определяете размер вашего перечисления на основе оператора switch, который может быть расположен в совершенно другом классе.

Внутренние работы Enum и Switch полностью разделены и должны оставаться несвязанными.

Ответ 8

Хорошим способом для этого было бы добавить случай по умолчанию для возврата некоторого значения ошибки или исключения исключения и использования автоматических тестов с помощью jUnit, например:

@Test
public void testEnum() {
  for(Mode m : Mode.values() {
    m.foobar(); // The switch is separated to a method
    // If you want to check the return value, do it (or if there an exception in the 
    // default part, that enough)
  }
}

Когда вы получите автоматические тесты, это позаботится о том, что foobar определен для всех перечислений.

Ответ 9

Так как я не могу просто прокомментировать...

  • Всегда, всегда, всегда есть случай по умолчанию. Вы будете удивлены, как "часто" это будет удалено (Less in Java, чем C, но все же).

  • Сказав это, что, если я только хочу обрабатывать только вкл/выкл в моем случае. Ваша семантическая обработка javac будет отмечать это как проблему.

Ответ 10

В настоящее время (этот ответ написан спустя несколько лет после исходного вопроса), eclipse разрешает следующую конфигурацию в окне → Настройки → Java → Компилятор → Ошибка/предупреждения → Потенциальные проблемы программирования:

Неполные случаи переключения

Сигнал, даже если используется случай по умолчанию