当交换机用于枚举时,默认值的用法是什么?

时间:2015-10-08 15:06:06

标签: java enums

假设我有一个包含2个可能值的枚举ColorREDBLUE

public enum Color {
    RED,
    BLUE
}

现在假设我有一个这个枚举的switch语句,其中我有两个可能值的代码:

Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
   ...
   break;

case BLUE:
   ...
   break;

default:
   break;
}

由于我对枚举的两个可能值都有代码块,上面代码中default的用法是什么?

如果代码以某种方式到达default块,我应该抛出异常吗?

Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
case RED:
   ...
   break;

case BLUE:
   ...
   break;

default:
   throw new IllegalArgumentException("This should not have happened");
}

11 个答案:

答案 0 :(得分:84)

如您在第二个示例中所示,抛出异常是一个好习惯。您可以通过快速失败来提高代码的可维护性。

在这种情况下,如果您稍后(可能在几年后)添加枚举值并且它到达switch语句,您将立即发现错误。

如果未设置默认值,即使使用新的枚举值,代码也可能会运行,并且可能会产生不良行为。

答案 1 :(得分:53)

其他答案是正确的,说您应该实现一个抛出异常的default分支,以防将来在您的枚举中添加新值。但是,我会更进一步,质疑你为什么甚至首先使用switch语句。

与C ++和C#等语言不同,Java将Enum值表示为实际对象,这意味着您可以利用面向对象的编程。让我们说你的方法的目的是为每种颜色提供一个RGB值:

switch (color)
    case RED:
       return "#ff0000";
    ...

嗯,可以说,如果你想让每种颜色都有RGB值,你应该把它作为描述的一部分:

public enum Color
{
    RED("#FF0000"),
    BLUE("#0000FF");

    String rgb;
    public Color(String rgb) {
        this.rgb = rgb;
    }
    public getRgb() { return this.rgb; }
}

这样,如果您稍后添加新颜色,则非常需要提供RGB值。它比其他方法更快失败,因为你在编译时而不是在运行时失败。

请注意,如果需要,您可以执行更复杂的操作,包括让每种颜色都提供自己的抽象方法的自定义实现。 Java中的枚举非常强大且面向对象,在大多数情况下,我发现我可以避免首先对switch进行操作。

答案 2 :(得分:8)

在小程序中,没有实际用途,但想到一个在大量文件和开发人员中使用的复杂系统 - 如果在一个文件中定义enum并在另一个文件中使用它,稍后有人在enum添加switch而不更新System > Configuration > Developer语句的值,您会发现它非常有用......

答案 3 :(得分:7)

如果您已涵盖各种cases的所有可能性且default无法发生,则这是assertions的经典用例:

Color color = getColor(); // a method which returns a value of enum "Color"
switch (color) {
    case RED:
       // ...
       break;

    case BLUE:
       // ...
       break;

    default:
       assert false; // This cannot happen
       // or:
       throw new AssertionError("Invalid Colors enum");
}

答案 4 :(得分:6)

为了满足IDE和其他静态链接,我经常将默认情况保留为无操作,以及// Can't happen// Unreachable

等注释

即,如果交换机正在处理所有可能的枚举值,无论是显式还是通过直通,那么默认情况可能是程序员错误。

根据应用程序的不同,我有时会在案例中设置一个断言来防止程序员在开发过程中出错。但是这在运输代码中的价值有限(除非您在启用断言的情况下发货。)

同样,根据情况,我可能会确信会抛出一个错误,因为这实际上是一个无法恢复的情况 - 用户无法做的任何事情都会纠正程序员错误。

答案 5 :(得分:6)

是的,你应该这样做。您可以更改enum但不要更改switch。将来它会导致错误。我认为throw new IllegalArgumentException(msg)是一种很好的做法。

答案 6 :(得分:5)

当枚举常量太多并且您只需要处理少数情况时,null将处理其余的常量。

此外,枚举常量是引用(如果尚未设置引用)或$(function(){ var dir = document.URL; if(dir.indexOf('contact') > -1){ // do stuff in here for contact/index.php... }else if(dir.indexOf('about') > -1){ // do stuff in here for about/index.php... }else{ // everything for the index page goes here } }); 。您可能也必须处理此类案件。

答案 7 :(得分:3)

除了许多人指出的enum可能的未来扩展之外,有些人可能会“改进”你getColor()或在派生类中覆盖它并让它返回无效值。当然编译器应该捕获它,除非有人明确强制不安全的类型转换...

但糟糕的事情恰好发生,最好不要让任何意外的elsedefault路径无人看守。

答案 8 :(得分:3)

我很惊讶其他人都没有这么说过。您可以将int转换为枚举,并且它不会因为该值不是枚举值之一而抛出。这意味着(除其他外),编译器无法判断所有枚举值是否在交换机中。

即使您正确编写代码,在序列化包含枚举的对象时也会出现这种情况。未来的版本可能会添加到枚举中,并且您的代码会在读取它时阻塞,或者某个想要创建混乱的人可能会在其中添加新值。无论哪种方式,关闭交换机很少做正确的事情。所以,除非我们更清楚,否则我们会抛出默认值。

答案 9 :(得分:1)

以下是我将如何处理它,在NULL值旁边,这将导致您可以处理的空指针异常。

如果Color color不是null,则它必须是enum Color中的单身之一,如果您指定对其中一个不是其中一个的对象的任何引用,这将导致运行时错误。

所以我的解决方案是考虑不支持的值。

Test Run

Test.java

public Test
{
  public static void main (String [] args)
  {
    try { test_1(null); }
    catch (NullPointerException e) { System.out.println ("NullPointerException"); }

    try { test_2(null); }
    catch (Exception e) { System.out.println(e.getMessage()); }

    try { test_1(Color.Green); }
    catch (Exception e) { System.out.println(e.getMessage()); }
  }

  public static String test_1 (Color color) throws Exception
  {
    String out = "";

    switch (color) // NullPointerException expected
    {
      case Color.Red:
        out = Red.getName();
        break;
      case Color.Blue:
        out = Red.getName();
        break;
      default:
        throw new UnsupportedArgumentException ("unsupported color: " + color.getName());
    }

    return out;
  }

..或者您也可以将null视为不受支持

  public static String test_2 (Color color) throws Exception
  {
    if (color == null) throw new UnsupportedArgumentException ("unsupported color: NULL");
    return test_1(color);
  }
}

Color.java

enum Color
{
  Red("Red"), Blue("Blue"), Green("Green");
  private final String name;
  private Color(String n) { name = n; }
  public String getName() { return name; }
}

UnsupportedArgumentException.java

class UnsupportedArgumentException extends Exception
{
  private String message = null;

  public UnsupportedArgumentException() { super(); }

  public UnsupportedArgumentException (String message)
  {
    super(message);
    this.message = message;
  }

  public UnsupportedArgumentException (Throwable cause) { super(cause); }

  @Override public String toString() { return message; }

  @Override public String getMessage() { return message; }
}

答案 10 :(得分:0)

在这种情况下,默认情况下使用Assertion是最佳做法。