如果我使用enum来确定任务的类型。
public enum TaskType {
TYPE_ONE("Type1"),TYPE_TWO("Type2"),TYPE_THREE("Type3");
private final String type;
private StageType(String type) {
this.type = type;
}
@Override
public String toString() {
return type;
}
}
我怎样才能确保我的申请中的某一点
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
}
是否使用了每个enum值?
我的意思是如果有一天我需要添加一个新的TYPE_FOUR,我需要找到我使用enum的代码中的每个地方,所以我问自己是否有更好的方法以便我避免{ {3}}并使用其他一些概念,或者我可以确保在该段代码中使用enum的每个值。
答案 0 :(得分:5)
有findbugs类型工具可以做到这一点,但你可以考虑完全删除if-then-else并将处理放在enum
内。在这里,添加新的TYPE_FOUR
会强制您编写doProcessing()
方法。
public interface DoesProcessing {
public void doProcessing();
}
public enum TaskType implements DoesProcessing {
TYPE_ONE("Type1") {
@Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
@Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
@Override
public void doProcessing() {
}
},
TYPE_FOUR("Type4") {
// error: <anonymous com.oldcurmudgeon.test.Test$TaskType$4> is not abstract and does not override abstract method doProcessing() in DoesProcessing
};
private final String type;
private TaskType(String type) {
this.type = type;
}
@Override
public String toString() {
return type;
}
}
public void test() {
DoesProcessing type = TaskType.TYPE_TWO;
type.doProcessing();
}
如果您更喜欢abstract
方法,那么这可行:
public enum TaskType {
TYPE_ONE("Type1") {
@Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
@Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
@Override
public void doProcessing() {
}
};
private final String type;
private TaskType(String type) {
this.type = type;
}
// Force them all to implement doProcessing.
public abstract void doProcessing();
@Override
public String toString() {
return type;
}
}
答案 1 :(得分:2)
您可以将进程方法作为抽象方法放在TaskType中,然后在枚举中的每个任务中覆盖它。如果您创建一个界面,可能是一个更好的主意,例如:
public interface Task {
void process();
}
然后你要让你的枚举实现这个界面。或者,可能更好,您创建实现此接口的具体类。每个任务类型都有一个类。
答案 2 :(得分:1)
AFAIK你不能自动&#34;。
为了尽量减少忘记为新值添加if / case的风险,您可以拥有一个&#34; service&#34;每个枚举值的类和为枚举值提供特定服务的工厂。
E.g。而不是:
void methodA(TaskType type) {
doSth();
switch(type) {
case TYPE_ONE:
foo1();
break;
case TYPE_TWO:
foo2();
break;
...
}
}
void methodB(TaskType type) {
doSthElse();
switch(type) {
case TYPE_ONE:
bar1();
break;
case TYPE_TWO:
bar2();
break;
...
}
}
做的:
interface Service {
foo();
bar();
}
class ServiceFactory {
Service getInstance(TaskType type) {
switch(type) {
case TYPE_ONE:
return new TypeOneService();
case TYPE_TWO:
return new TypeTwoService();
default:
throw new IllegalArgumentException("Unsupported TaskType: " + type);
}
}
}
然后上面的方法可以改写如下:
void methodX(TaskType type) {
doSth();
ServiceFactory.getInstance(type).foo();
}
这样你只需要一个点来添加新枚举值的处理。
答案 3 :(得分:1)
我想你是说你想要编译器告诉你所有的枚举值都被考虑了。
不幸的是,Java并不支持。
你可能认为你可以这样写:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
}
// not reachable ... no return required
}
...并依赖编译器告诉您是否遗漏了切换案例中的一个枚举值。
不幸的是,它不起作用!! 以上是编译错误。根据JLS可达性规则,switch语句需要default:
臂才能使该方法有效。 (或者你可以在最后添加return
...)
这种奇怪的原因很有道理。 JLS二进制兼容性规则表示向enum
添加新值是二进制兼容的更改。这意味着在添加枚举值之后,任何带有switch
语句的开启enum
的代码仍需要保留有效(可执行)代码。如果method
开头有效,则在二进制兼容更改后,它将无效(因为返回路径中没有return
语句)。
实际上,这就是我编写上面代码的方式:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
default:
throw new AssertionError("TaskType " + t + " not implemented");
}
// not reachable ... no return required
}
这并不是假装编译时安全的,但它是快速失败的,并且它不会涉及糟糕的OO设计。
答案 4 :(得分:0)
HashMap<String, Integer> hm=new HashMap<String, Integer>();
...
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
hm.put(TaskType.TYPE_ONE, 1)
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
hm.put(TaskType.TYPE_TWO, 1)
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
hm.put(TaskType.TYPE_THREE, 1)
}
...
for (TaskType t : TaskType.values()) {
if(hm.get(t)!=1)
// Trigger the alarm
}
如果需要,您甚至可以计算元素计数的次数
答案 5 :(得分:0)
您可以在枚举上切换案例,如果达到默认值,则会失败:
switch(taskType ){
case TYPE_ONE: ... break;
case TYPE_TWO: ... break;
case TYPE_THREE: ... break;
default:
throw new IllegalStateException("Unsupported task type:"+taskType);
}