关于Java中的switch语句 - 在每个case中使用return并省略break的影响。

73

根据这种方法,这是否代表了一些过分的风格或语义错误:

private double translateSlider(int sliderVal) {
    switch (sliderVal) {
        case 0:
            return 1.0;
        case 1:
            return .9;
        case 2:
            return .8;
        case 3:
            return .7;
        case 4:
            return .6;
        default:
            return 1.0;
    }
}  

显然这与 Java 教程 这里 不符。

然而,它表达清晰,简洁,并且迄今为止已经得到了我所需要的结果。是否有一个令人信服、实用的理由来创建一个本地变量,在每个 case 中分配一个值,给每个 case 添加一个 break 并在方法结尾返回该值?


7
对我来说,这看起来很好。switch语句是该方法唯一的内容,它清晰易读,所以非常合理。 - Michelle
更喜欢清晰简单的代码,而不是聪明的代码。我花了1秒钟就立刻理解了OP的方法,然后我盯着AlexWien的方法看了1分钟,我的大脑根本无法解读它。阿门。 - jumping_monkey
11个回答

89

将值分配给一个本地变量,然后在最后返回该变量被认为是一种好的实践。具有多个出口的方法更难调试,并且可能难以阅读。

话虽如此,这仍是这种范例唯一剩下的优点。它起源于只有低级过程语言存在的时候。当时这种做法更有意义。

顺便说一句,您必须看看这个。这是一篇有趣的文章。


15
链接到一个 Stack Overflow 的帖子,指出多个出口是不好的。该问题中得票最高的回答开头是“这主要取决于个人喜好”,结尾是“我认为实施单一出口是毫无意义甚至可能产生反作用”。-_-长叹一声 - Millie Smith
@MillieSmith 两个最受欢迎的答案中都没有提到“either”或“neither”。我错过了什么吗? - Ungeheuer
@Adrian 我所提到的问题链接我所参考的答案 - Millie Smith
@MillieSmith 哦,我点击了另一个链接。解释了为什么我没看到它哈哈 - Ungeheuer
@MillieSmith 用户指出了关于这个话题的各种不同观点,并在最后表达了自己的意见,看起来还不错。 - rocketboy
使用我们今天所使用的技术和工具,“难以调试”的论点变得不成立了。 - v.ladynev

11
如果是Java 14及以上版本,您可以像这样使用switch的函数表达式:
return switch(region) {
    case "us-east-1" -> Region.US_EAST_1;
    default -> Region.US_EAST_1;
};

7

从人类智慧的角度来看,您的代码没问题。但是从静态代码分析工具的角度来看,有多个返回语句,这使得调试变得更加困难。例如,在 return 之前不能立即设置一个唯一的断点。

此外,在专业应用程序中,您不会硬编码四个滑块步骤。可以通过计算 max-min 等值或在数组中查找这些值来获得它们:

public static final double[] SLIDER_VALUES = {1.0, 0.9, 0.8, 0.7, 0.6};
public static final double SLIDER_DEFAULT = 1.0;


private double translateSlider(int sliderValue) {
  double result = SLIDER_DEFAULT;
  if (sliderValue >= 0 && sliderValue < SLIDER_VALUES.length) {
      ret = SLIDER_VALUES[sliderValue];
  }

  return result;
}

在这里使用数组有一个缺点。数组中的索引隐含地对应可能的滑块输入值。但这是非常隐晦的。如果有人决定让滑块从1开始或以5的增量移动,会发生什么?从滑块值到输出值使用映射(HashMap<Integer, Double>)可能更加灵活。无论哪种方式,这都比跳转到switch语句更快,所以很好。 - Andrew Puglionesi

3

我认为你所写的内容完全没有问题。同时,使用多个return语句也不会影响可读性。

我总是喜欢在代码中知道要返回的点上进行返回,这样可以避免在返回后执行下面的逻辑。

有人认为在调试和记录日志时应该只有一个返回点。但是,在你的代码中,如果我们使用它,就不存在调试和记录日志的问题。你所写的方式非常简单易懂。


2

人类逻辑转换成计算机生成的字节码的最佳方式是使用以下代码:

private double translateSlider(int sliderVal) {
  float retval = 1.0;

  switch (sliderVal) {
    case 1: retval = 0.9; break;
    case 2: retval = 0.8; break;
    case 3: retval = 0.7; break;
    case 4: retval = 0.6; break;
    case 0:
    default: break;
  }
  return retval;
}

因此,消除了方法中的多个出口,并合理利用语言。(例如,当sliderVal是1-4范围内的整数时,更改浮点值,否则如果sliderVal为0且所有其他值,则retval保持1.0的浮点值)
然而,如果sliderVal的每个整数值都是(n-(n/10))这样的形式,那么只需要使用lambda表达式就可以获得更快的结果。
private double translateSlider = (int sliderVal) -> (1.0-(siderVal/10));

编辑: 为保持逻辑(即(n-(n/10))%4)),可能需要使用模数4。

9
你需要在每个case的上方添加break;语句 - 目前1-4都会继续执行,导致retval = 0.6 - stevek_mcc
1
哇,2015年..作为一名开发人员,我肯定已经成长了。回顾这段代码,人们开始思考,“为什么不将其实现为具有哈希映射的查找表呢?” - Dwight Spencer

0

为什么不直接

private double translateSlider(int sliderval) {
if(sliderval > 4 || sliderval < 0)
    return 1.0d;
return (1.0d - ((double)sliderval/10.0d));
}

或者类似的?


1
这个方案的计算速度不如你的快,因此如果你想节省计算周期,浮点运算可能不是一个很好的选择 - 或者如果你正在寻找更多的“配置”(也就是说,数学不总是能够很好地工作)。 - SubSevn
@SubSeven,当用户用他的慢手指移动滑块时,从不需要节省循环。即使是最慢的嵌入式设备也远远超过他的手指。代码的可读性和清晰度是最大化的原则。 - AlexWien
硬编码的数字4会触发另一个警告(魔法数字)。 - AlexWien
不应该是 if (sliderVal > 0 && sliderVal <= 4) retval ::= 1.0 - sliderVal/10) 吗?否则 retval ::= 1.0。 - Dwight Spencer

0

不,你现在的代码已经很好了。你也可以将其作为公式来实现 (sliderVal < 5 ? (1.0 - 0.1 * sliderVal) : 1.0) 或使用 Map<Integer,Double>,但你现在的代码已经足够好了。


3
如果乘以sliderVal,由于0.1没有精确的二进制表示,你会使精度误差叠加,并且结果不同于OP代码。 - Rohit Jain
在一般情况下,当然会出现这种情况;但在这种情况下,对于 0 <= i <= 10,你会得到相同的值:http://ideone.com/3F9y8K。如果OP无论如何都在使用双精度浮点数,很可能还会有其他舍入误差需要处理,因为这是常规情况下的问题。 - yshavit
三目运算符不被鼓励使用:您提出的解决方案解决了多个返回警告,但触发了三目运算符警告。 - AlexWien
3
“被弃用”?不要让这听起来像一个绝对的规则;有很多人使用未加限制的三元运算符也没问题。如果你不喜欢它,就在脑海中将其展开为if-else语句;我的主要观点是,可以解决这个问题而不用粗暴地增加六个选项。 - yshavit
地图是个不好的主意。在这里用大炮打小鸟(可能翻译得不太好)是不必要的。一个简单的固定数组就足够了。 - AlexWien

0

我建议您不要使用字面值。

除此之外,样式本身看起来很好。


那个比较在哪里?开关是一个整数。 - yshavit
在我自以为是的脑海中 :) 误读了,认为双重回车是一个 case 语句。 - William Morrison

0
如果你只是想运行 switch 并返回一些值的方法,那么这种方式确实可行。但是如果你想在一个方法中使用其他东西的 switch,那么你不能使用 return,否则方法内部的其余代码将不会执行。请注意教程中代码后面的打印输出?你的代码将无法做到这一点。

0

虽然这个问题已经很老了,但现在仍然可以作为参考。

从语义上讲,这正是Java 12引入的内容(https://openjdk.java.net/jeps/325),因此,在提供的这个简单示例中,我看不到任何问题或缺点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接