假设我有一个包含2个可能值的枚举Color
:RED
和BLUE
:
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");
}
答案 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()
或在派生类中覆盖它并让它返回无效值。当然编译器应该捕获它,除非有人明确强制不安全的类型转换...
但糟糕的事情恰好发生,最好不要让任何意外的else
或default
路径无人看守。
答案 8 :(得分:3)
我很惊讶其他人都没有这么说过。您可以将int转换为枚举,并且它不会因为该值不是枚举值之一而抛出。这意味着(除其他外),编译器无法判断所有枚举值是否在交换机中。
即使您正确编写代码,在序列化包含枚举的对象时也会出现这种情况。未来的版本可能会添加到枚举中,并且您的代码会在读取它时阻塞,或者某个想要创建混乱的人可能会在其中添加新值。无论哪种方式,关闭交换机很少做正确的事情。所以,除非我们更清楚,否则我们会抛出默认值。
答案 9 :(得分:1)
以下是我将如何处理它,在NULL
值旁边,这将导致您可以处理的空指针异常。
如果Color color
不是null
,则它必须是enum Color
中的单身之一,如果您指定对其中一个不是其中一个的对象的任何引用,这将导致运行时错误。
所以我的解决方案是考虑不支持的值。
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是最佳做法。