我有一种情况需要检查多种情况,其中每种组合都有不同的结果。在我的具体情况下,我有2个变量,它们是枚举类型,每个变量可以是2个不同的值。
enum Enum1
{
COND_1,
COND_2
}
enum EnumA
{
COND_A,
COND_B
}
Enum1 var1;
EnumA varA;
这给了我4种可能的条件,这需要4种不同的结果。我想出了几种不同的方法,使用if语句或switch语句:
if(var1 == Enum1.COND_1 && varA == EnumA.COND_A)
{
// Code
}
else if(var1 == Enum1.COND_1 && varA == EnumA.COND_B)
{
// Code
}
else if(var1 == Enum1.COND_2 && varA == EnumA.COND_A)
{
// Code
}
else if(var1 == Enum1.COND_2 && varA == EnumA.COND_B)
{
// Code
}
或者:
switch(var1)
{
case COND_1:
switch(varA)
{
case COND_A:
// Code
break;
case COND_B:
// Code
break;
}
break;
case COND_2:
switch(varA)
{
case COND_A:
// Code
break;
case COND_B:
// Code
break;
}
break;
}
我已经想过其他人了,但是不想用代码填写:P我想知道最好的方法是做什么。我认为开关更容易阅读,但ifs更短。我认为如果开关有多种条件会很酷,但我还没有听说过。这也引出了一个问题:使用任意数量的变量和可能的值,最好的方法是什么?
答案 0 :(得分:9)
对于您的小用例,我可能会选择嵌套的if
语句。但是如果你有足够的enum
常量,那么使用流的模式可能会使你的代码更容易阅读和维护(性能损失很小)。你可以使用这样的流解决它:
Stream.of(new Conditional(COND_1, COND_A, () -> {/* do something */}),
new Conditional(COND_1, COND_B, () -> {/* do something */}),
new Conditional(COND_2, COND_A, () -> {/* do something */}),
new Conditional(COND_2, COND_B, () -> {/* do something */}))
.filter(x -> x.test(var1, varA))
.findAny()
.ifPresent(Conditional::run);
这需要一个支持类:
class Conditional implements BiPredicate<Enum1, EnumA>, Runnable
{
private final Enum1 var1;
private final EnumA varA;
private final Runnable runnable;
public Conditional(Enum1 var1, EnumA varA, Runnable runnable) {
this.var1 = var1;
this.varA = varA;
this.runnable = runnable;
}
@Override
public boolean test(Enum1 enum1, EnumA enumA) {
return var1 == enum1 && varA == enumA;
}
@Override
public void run() {
runnable.run();
}
}
答案 1 :(得分:7)
这里的性能差异可能微不足道,所以我会关注简洁性和可读性。所以我只想通过使用临时变量来简化if
:
boolean is_1 = (var1 == Enum1.COND_1);
boolean is_A = (varA == EnumA.COND_A);
if(is_1 && is_A)
{
// Code
}
else if(is_1 && !is_A)
{
// Code
}
else if(!is_1 && is_A)
{
// Code
}
else if(!is_1 && !is_A)
{
// Code
}
答案 2 :(得分:3)
我更喜欢没有嵌套的if
变体,因为它很短并且你在一行中拥有所有条件。
在调试期间停止代码时,它会变得乏味,因为你必须跨越所有先前的条件,即O(n)。执行代码时,这无关紧要,因为编译器可能会优化代码。
没有明显的最好方法,所以你需要进行一些实验。
答案 3 :(得分:3)
我绝对更喜欢扁平版本,它可以使用更少的重复:
// If you can't make the variables final, make some final copies
final Enum1 var1 = Enum1.COND_2;
final EnumA varA = EnumA.COND_B;
class Tester { // You could also make an anonymous BiPredicate<Enum1, EnumA>
boolean t(Enum1 v1, EnumA vA) {
return var1 == v1 && varA == vA;
}
};
Tester tes = new Tester();
if (tes.t(Enum1.COND_1, EnumA.COND_A)) {
// code
} else if (tes.t(Enum1.COND_1, EnumA.COND_B)) {
// code
} else if (tes.t(Enum1.COND_2, EnumA.COND_A)) {
// code
} else if (tes.t(Enum1.COND_2, EnumA.COND_B)) {
// code
}
运行here。你可以通过static import of the enums来避免提及枚举名称,使其更短,更少冗余。 tes.t(COND_1, COND_B)
。或者,如果您愿意放弃一些编译时安全性,您可以传递一个字符串,该字符串将转换为两个枚举值,例如: tes.t("COND_1 COND_A")
(实现留给读者)。
答案 4 :(得分:1)
也许是疯狂的想法,但你可以使用标志构造一个int或一个字节,并在一个开关中使用它。
private int getIntegerStateForConditions(boolean... conditions ){
int state = 0;
int position = 0;
for(boolean condition: conditions){
if(condition){
state = state || (1 << position++);
}
}
return state;
}
...
switch(getIntegerStateForCondition((var1 == Enum1.COND_1), (var2 == EnumA.COND_A)){
case 0: ... //both condition false
case 1: ... //first condition true second false
case 2: ... //first false, second true ...
}
...
我认为这远不是干净的代码,但它看起来更好。
答案 5 :(得分:1)
如果我是你,我将依赖位标志,以便只有一个byte
(因为你只有4个用例)来处理并在{{1}上使用switch
语句管理所有用例。
这样的事情:
byte
然后你的测试将是:
private static final int COND_2 = 1;
private static final int COND_B = 2;
private byte value;
public void setValue(Enum1 enum1) {
if (enum1 == Enum1.COND_1) {
this.value &= ~COND_2;
} else {
this.value |= COND_2;
}
}
public void setValue(EnumA enumA) {
if (enumA == EnumA.COND_A) {
this.value &= ~COND_B;
} else {
this.value |= COND_B;
}
}
public Enum1 getEnum1() {
return (this.value & COND_2) == COND_2 ? Enum1.COND_2 : Enum1.COND_1;
}
public EnumA getEnumA() {
return (this.value & COND_B) == COND_B ? EnumA.COND_B : EnumA.COND_A;
}
答案 6 :(得分:1)
我个人更喜欢这个:
if(understandableNameInContextName1(var1, varA))
{
// Code
}
else if(understandableNameInContextName2(var1, varA))
{
// Code
}
else if(understandableNameInContextName3(var1, varA))
{
// Code
}
else if(understandableNameInContextName4(var1, varA))
{
// Code
}
private boolean understandableNameInContextName1(Object var1, Object varA){
return (var1 == Enum1.COND_1 && varA == EnumA.COND_A);
}
private boolean understandableNameInContextName2(Object var1, Object varA){
return (var1 == Enum1.COND_1 && varA == EnumA.COND_B);
}
private boolean understandableNameInContextName3(Object var1, Object varA){
return (var1 == Enum1.COND_2 && varA == EnumA.COND_A);
}
private boolean understandableNameInContextName4(Object var1, Object varA){
return (var1 == Enum1.COND_2 && varA == EnumA.COND_B);
}
方法的名称可以是,isOrderShippedAndDelivered(),isRequestSendAndAckRecieved()。
原因是这将使代码更具可读性。 除非你有数据可以引导你回到这些if语句,否则不会有太多的优势来优化这些。
答案 7 :(得分:0)
取决于代码的复杂程度和组合的数量,但另一个选项是一个字典,其中的键包含枚举的元组和代码的委托值。