if-else 和 switch 语句的替代方案
Posted
技术标签:
【中文标题】if-else 和 switch 语句的替代方案【英文标题】:Alternative of if-else and switch statements 【发布时间】:2014-05-22 02:23:21 【问题描述】:我在 Java 中有以下代码:
public void doSomething(int i)
if (i == 12)
// order should be same
up();
left();
stop();
if (i == 304)
// order should be same
right();
up();
stop();
if (i == 962)
// order should be same
down();
left();
up();
stop();
// similar code can be done using switch case statements.
// all the function can have any functionality and might not resemble to the name given to them.
现在,如果我被要求不要使用 if-else 和 switch case 语句,那该怎么办?代码可以用 Java 或 javascript 编写。
【问题讨论】:
只是确定一下,您实际上可以使用 JS (this language)?如果是这样,那很容易。 用类似'12'
的方法创建一个对象,并在该方法中调用你的函数。
为每个键使用字典,您将拥有函数列表作为值,并根据键选择列表中的函数并迭代列表并调用每个函数。
我永远不会理解要求学生“做 X,但不使用 Y,显然是正确的方法,或 Z 是另一种有效但尴尬的解决方案”的教学原因
“在 Java 或 JavaScript 中”没有意义。它们是两种非常不同的语言,具有两个非常不同的域。为了回答您的问题,两种语言都提供了几种多路 if:if-then-elseif-else
和某种switch
。您当前的实现是有缺陷的,因为它命中了 each if
测试,而不是在第一场比赛后退出。这可能就是教练的意思。
【参考方案1】:
如果你会使用 JavaScript,你可以使用带有函数的对象:
function doSomething(i)
var obj = ;
obj[12] = function ()
// order should be same
up();
left();
stop();
;
obj[304] = function ()
// order should be same
right();
up();
stop();
;
obj[962] = function ()
// order should be same
down();
left();
up();
stop();
;
// apparently we can't use any conditional statements
try
obj[i]();
catch (e)
如果只允许使用 if
和 switch
语句,请将所有 if
语句替换为逻辑 AND 运算符 (&&
):
function doSomething(i)
(i == 12) && (
// order should be same
up(),
left(),
stop()
);
(i == 304) && (
// order should be same
right(),
up(),
stop()
);
(i == 962) && (
// order should be same
down(),
left(),
up(),
stop()
);
【讨论】:
第二个是使用 if 语句,但第一个值得投票 ;-) 如果 OP 甚至禁止使用条件语句,它将是不可接受的 :) 只想指出,第二个建议仅适用于使用短路评估的语言:en.wikipedia.org/wiki/Short-circuit_evaluation 从我的头顶开始只有帕斯卡不使用它。 @Hoffmann,但是 OP 正在谈论 Java 和 JS,两者都短路了。 代替try/catch,我个人认为这样更具可读性:obj[i] && obj[i]();
【参考方案2】:
您可以制作一个输入到操作的字典。在 Java 中,这将是一个Map<Integer, Runnable>
,例如*:
map.put(12, () ->
up();
left();
stop();
);
然后,您可以获取相应的Runnable
并运行它:
Runnable action = map.get(i);
if (action != null)
action.run();
else
// some default action
// This is the "default" case in a switch, or the "else" in an if-else
if-else 不是绝对必要的,但如果没有它,如果 i
不是预期值,您将得到 NullPointerException
— 即您放入地图的值之一。
这个想法在 JavaScript 中是相似的,但使用对象而不是 Map
s,函数(可能是匿名的)而不是 Runnable
s,等等。
此代码适用于 Java 8。在 Java 7 及更低版本中,您可以:
map.put(12, new Runnable()
@Override
public void run()
up();
left();
stop();
);
【讨论】:
@Puru-- 这个想法同样适用于 Java 7。但是,是的,您需要创建一个匿名类而不是使用 lambda。 @sura 是的,但如果您确信i
始终是预期值,则不需要这样做。 (如果你错了,你会在action.run()
得到一个NullPointerException
。)
@yshavit,我想你可以try...catch
NPE 而不是用if...else
创建一个空保护。 :)
@BrianS 你可以,但这通常是个坏主意。如果 Runnable 本身有一个错误并抛出一个 NPE,你永远不会知道,因为那个 catch-and-ignore。最好让它传播出去,这样一些东西就可以对你大喊大叫。
谁说你必须忽略异常? (并不是我认为 try/catch 是 if/else 的 good 替代品,只是在这种情况下它可以,并且符合 OP 的要求。)【参考方案3】:
看,自然你应该用条件表达式检查条件语句! 现在,如果你不想这样做,你可以像这样不自然地这样做:
首先对所有方法(向上、向下、...)执行此操作
java.lang.reflect.Method method;
try
method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
catch (SecurityException e)
// ...
catch (NoSuchMethodException e)
// ...
不要使用整数传递给doSomething
,而是使用包含要调用的方法名称的数组,并在 for 循环中以这种方式调用每个方法:
然后你通过调用来调用该方法
try
method.invoke(obj, arg1, arg2,...);
catch (IllegalArgumentException e)
catch (IllegalAccessException e)
catch (InvocationTargetException e)
很遗憾,Java 没有委托!
【讨论】:
虽然我相信这种方法会工作(因为它会产生预期的结果),但反射是解决这个问题的一个不必要的复杂解决方案,IMO。 @BrianS- 实际上,正如我已经说过的,在 java 中最自然的方法是使用 if 语句,但是由于 OP 不想要它,我尝试尽可能接近 c#代表,这是java中缺少的。 常见的 Java 解决方案是观察者模式的一些变体(yshavit 的回答是简化版本)。不过,我承认,几年前我 wrote a class 以可重用的方式实现您的解决方案。【参考方案4】:对于 js 你可以试试这个:
// define ur actions here
var actions =
"12" : function () up(); left(); stop(); ,
"304" : function () right(); up(); stop(); ,
"962" : function () down(); left(); up(); stop();
;
function doSomething(i)
var fn = actions[i];
try
fn();
catch (err)
console.error(err);
//
doSomething(12); //invoke here
【讨论】:
写得非常巧妙。【参考方案5】:这是在 JavaScript 中完成此操作的简单方法:
function up() console.log("up");
function down() console.log("down");
function left() console.log("left");
function right() console.log("right");
function stop() console.log("stop");
var fnmaps =
12: [up, left, stop],
304: [right, up, stop],
962: [down, left, up, stop]
;
function doSomething(i)
var fnmap = fnmaps[i] || [], j;
for (j = 0; j < fnmap.length; j++)
fnmap[j]();
doSomething(12);
doSomething(304);
doSomething(962);
只需编辑地图变量即可添加/排序功能。
【讨论】:
【参考方案6】:那就用while和break吧,没有条件检查就没有办法了
public void doSomething(int i)
while(i == 12)
// order should be same
up();
left();
stop();
break;
while(i == 304)
// order should be same
right();
up();
stop();
break;
while(i == 962)
// order should be same
down();
left();
up();
stop();
break;
【讨论】:
替代,同样糟糕:(i == 12 && (up (), left (), stop ())); (i == 304 && (右(), 上(), 停止())); (i == 962 && (下(), 左(), 上(), 停()));【参考方案7】:在 Java 中,这应该可以工作..
public class IfTest
public static void main(String[] args)
IfTest ifTest = new IfTest();
ifTest.doSomething(12);
ifTest.doSomeThingWithoutIf(12);
ifTest.doSomething(304);
ifTest.doSomeThingWithoutIf(304);
ifTest.doSomething(962);
ifTest.doSomeThingWithoutIf(962);
ifTest.doSomething(42);
ifTest.doSomeThingWithoutIf(42);
public void doSomeThingWithoutIf(int i)
boolean x = i == 12 ? f12() : (i == 304 ? f304() : (i == 962 ? f962() : false));
public boolean f12()
up();
left();
stop();
return true;
public boolean f304()
right();
up();
stop();
return true;
public boolean f962()
down();
left();
up();
stop();
return true;
public void doSomething(int i)
if(i == 12)
// order should be same
up();
left();
stop();
if(i == 304)
// order should be same
right();
up();
stop();
if(i == 962)
// order should be same
down();
left();
up();
stop();
private boolean retfalse()
return false;
private void down()
System.out.println("down");
private void right()
System.out.println("right");
private void stop()
System.out.println("stop");
private void left()
System.out.println("left");
private void up()
System.out.println("up");
【讨论】:
我会假设它是因为你用三元运算符做了 if-else。我认为 OP 想要一个没有 if-else 或同义词的解决方案。 如果是这样的话,他肯定说过“不使用条件运算符”左右。我不擅长 JS,但是如果我查看为 Java 发布的解决方案,它们要么使用反射,要么使用 Map/Dictionary 等。对于这么简单的事情,我发现两者的性能和内存占用都很糟糕 我不一定不同意你zencv。我只是提供了一个可能的原因来说明为什么它被否决了;)【参考方案8】:这个问题可以使用 OOP 技术来解决。
在java中它看起来像这样:
public abstract class AObject
public abstract void doSomething();
public void up()
//do something here
public void down()
//do something here
public void left()
//do something here
public void right()
//do something here
public void stop()
//do something here
public class AObject12 extends AObject
public void doSomething()
up();
left();
stop();
public class AObject304 extends AObject
public void doSomething()
right();
up();
stop();
public class AObject962 extends AObject
public void doSomething()
down();
left();
up();
stop();
在具体类的实例上执行 doSomething 将触发适当的行为。所以不再需要 if/else。示例见以下代码:
AObject A12 = new AObject12();
A12.doSomething();
// Will run Up left stop in that order
AObject A304 = new AObject304();
A304.doSomething();
// Will run right Up stop in that order
AObject A962 = new AObject962();
A962.doSomething();
// Will run down left up stop in that order
更多关于这种编程的信息可以在这里找到:http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29
如果您希望能够动态更改对象的行为,可以考虑应用状态模式:http://en.wikipedia.org/wiki/State_pattern
【讨论】:
你现在如何有条件地调用一个? @Ven 您在对象的实例上调用 do instance,它将执行属于该实例的代码。假设您希望这种行为是可设置的。那么你可以考虑使用状态模式:en.wikipedia.org/wiki/State_pattern. 但是你如何实例化正确的类呢?您没有在这里回答主要问题。 这仍然不正确,您正在执行每一个行为,而不是依赖于“i”的值。 i 的值在对象中表示,它不再是 var。但这取决于对象的类型。它仍然包含与 OP 的代码类似的逻辑,但没有 if/else,就像 OP 所要求的那样。 :)【参考方案9】:Wahahahahaha,你拯救了我的一天 :) 这应该有效,现在无法测试..
public void doSomething(int i)
try
int x = 1/(12-i); // fails for i==12
catch (ArithmeticException e)
up();
left();
stop();
等等,尽情享受吧!
【讨论】:
【参考方案10】:在 JAVA 中可以通过使用逻辑 AND 运算符的短路来实现所需的行为,如下所示:
public static Boolean seq12()
// order should be same
up();
left();
stop();
return true;
public static Boolean seq304()
// order should be same
right();
up();
stop();
return true;
public static Boolean seq962()
// order should be same
down();
left();
up();
stop();
return true;
public static void doSomething(int i)
Boolean tmp;
tmp = (i == 12 && seq12());
tmp = (i == 304 && seq304());
tmp = (i == 962 && seq962());
这段代码非常简单,并且依赖于逻辑与运算符仅在第一个操作数为 true 时计算第二个操作数的事实。
【讨论】:
以上是关于if-else 和 switch 语句的替代方案的主要内容,如果未能解决你的问题,请参考以下文章
switch语句和switch-case与if-else之间的转换