我正在阅读一些试图学习新语言的Java教科书,并且我遇到了这种方法。
private String monthName (int month) { // bad example since this method needs to return a String
switch (month) {
case 1:
return "January";
case 2:
return "February";
...
case 12:
return "December";
}
}
此代码后面的陈述说:
编译器将拒绝此代码,因为它可以到达 结束时没有返回值。
所以在Java中,我假设一个方法有单词" String"在方法名称之前,必须返回一个字符串?这个switch语句的问题是可能没有满足case语句条件而且执行只是从底层掉出来了?是否有必要将未标记为无效的方法始终返回值?
答案 0 :(得分:6)
方法签名是一种合同,它指定了作为参数的内容以及它有义务返回的内容。声明返回void以外的东西的方法必须返回一些东西或扔东西,不允许在没有返回任何东西的情况下掉头(如果有的话,仍然必须分配从方法调用中分配返回值的变量)东西)。
具体来说,如果声明一个方法返回一个String,那么通过该方法获取的每个可能路径都必须以返回一个String结束,返回null(null是任何引用类型的允许值),或抛出一个Throwable实例。这就是引用的段落告诉你的,编译器可以检测到你没有这样做并且会抱怨它。
如果传入的整数不在预期范围内,您可以让代码抛出异常。让你的方法验证他们正在为他们的参数接收合理的值是一件好事。使用默认值或返回null不是很好,因为它不会立即暴露问题,而是会给调用者提供一个可能没有意义的值,并且因为错误可见的地方可能会更难调试发生的事情。距离问题的起因还有很长的路要走。这种方法可以写成:
private String monthName (int month) { // bad example since this method needs to return a String
switch (month) {
case 1:
return "January";
case 2:
return "February";
...
case 12:
return "December";
default:
throw new IllegalArgumentException("found unexpected value " + month);
}
}
这样编译器就不会抱怨,任何超出范围的值都会引起你的注意。
请注意:
答案 1 :(得分:2)
if a method has the word "String" before the method name, it MUST return a String
这几乎是正确的,它也可以返回一个特殊值,'null'。
方法可能不返回值,在这种情况下,String
将替换为void
,表示没有返回值。
答案 2 :(得分:2)
不,我认为这本书指的是编译器将通过Switch语句,如果没有命中1,2或12,那么它根本不会返回任何内容。< / p>
任何具有返回类型的方法都必须返回该类型。所以在这个例子中,你必须返回一个String。
要修复该代码,我会执行以下操作:
private String monthName (int month) { // bad example since this method needs to return a String
String retVal = "";
switch (month) {
case 1:
retVal = "January";
break; // essential in a switch statement
case 2:
retVal = "February";
break;
case 12:
retVal = "December";
break;
default:
retVal = "Invalid Month number";
break;
}
return retVal;
}
您可能会注意到我在方法的顶部设置了返回值,然后只需在switch语句中为其赋值,然后只返回函数末尾的retVal。这样编译器就满意了。您的代码示例的另一个问题是您的交换机/案例块中没有中断。
如果发生这种情况,那么无论遇到哪种情况,都会执行每一行。
答案 3 :(得分:1)
是。具有返回类型的方法(在本例中为String
)必须始终返回String
。
有趣的是,在这种情况下,为什么会出现编译错误并不简单。让我们简单地说明原因。
// Won't compile
String foo(boolean a) {
if (a) {
return "foo";
}
}
这会抛出编译器错误,因为程序的所有分支都不会返回。有可能到达函数的末尾(如果a
不是true
)并且仍然没有返回String
。
但并不总是一个方法必须以return语句结束。编译器非常智能,可以在所有分支返回时实现。
// Compiles
String foo(boolean a) {
if (a) {
return "foo";
} else {
return "bar";
}
}
即使在else之后没有return语句,这也会编译,因为它表明if / else的每个分支都以return形式结束。
让我们转到switch语句。
// Won't compile
String foo(char c) {
switch (c) {
case 'a':
return "foo";
}
}
上面的代码不会编译,因为对于c != 'a'
的所有输入都没有return语句。但我们可以通过添加默认值来解决这个问题。
// Compiles
String foo(char c) {
switch (c) {
case 'a':
return "foo";
default:
return "bar";
}
}
这里对于c的所有值,都有一个返回值,因此编译器不会抱怨。
让我们看一下编译器不够智能以进行分支预测的一些边缘情况。
// Won't compile
String foo(char c) {
if (c != 'a') {
return "bar";
}
switch (c) {
case 'a':
return "foo";
}
}
编译器不明白进入交换机,'c'必须等于'a',所以即使认为它可能看起来应该编译它也不会。
这是一个令人困惑的案例,其中涵盖了所有分支,但java编译器仍然选择了编译失败。
// Won't compile
enum B { T, F }
String foo(B a) {
switch (a) {
case T:
return "foo";
case F:
return "bar";
}
}
看起来switch语句具有所有分支覆盖范围。除了B
和T
之外,没有F
的其他实例。这可以通过创建一个处理新的潜在枚举值的默认分支来解决。