Java在方法中发现了switch语句。该方法是否需要返回一些内容?

时间:2015-12-28 22:50:42

标签: java

我正在阅读一些试图学习新语言的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语句条件而且执行只是从底层掉出来了?是否有必要将未标记为无效的方法始终返回值?

4 个答案:

答案 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);
  }
}

这样编译器就不会抱怨,任何超出范围的值都会引起你的注意。

请注意:

  • 许多人坚持认为所有开关都应该包含默认情况,以便未处理的案例不会以无声方式传递。
  • java.util日期/日历API编号从0开始的月份,而不是示例中的1;如果您使用日历查找月份并将该int传递给此方法,则很容易返回错误的月份。尽可能靠近源处理错误会使跟踪问题变得更加容易。

答案 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语句具有所有分支覆盖范围。除了BT之外,没有F的其他实例。这可以通过创建一个处理新的潜在枚举值的默认分支来解决。