在我的第一次代码评审中(不久前),有人告诉我,在所有switch语句中包含一个default子句是一种很好的实践。我最近想起了这个建议,但不记得理由是什么了。现在我听起来很奇怪。

是否有一个合理的理由总是包含默认语句? 这是语言依赖吗?我不记得当时我在用什么语言了——也许这适用于一些语言而不是其他语言?


当前回答

我不同意上面Vanwaril投票最多的回答。

任何代码都会增加复杂性。此外,还必须为此进行测试和文档编制。所以用更少的代码编程总是好的。我的观点是,我对非穷举switch语句使用default子句,而对穷举switch语句不使用default子句。为了确保我做对了,我使用了静态代码分析工具。让我们来详细了解一下:

Nonexhaustive switch statements: Those should always have a default value. As the name suggests those are statements which do not cover all possible values. This also might not be possible, e.g. a switch statement on an integer value or on a String. Here I would like to use the example of Vanwaril (It should be mentioned that I think he used this example to make a wrong suggestion. I use it here to state the opposite --> Use a default statement): switch(keystroke) { case 'w': // move up case 'a': // move left case 's': // move down case 'd': // move right default: // cover all other values of the non-exhaustive switch statement } The player could press any other key. Then we could not do anything (this can be shown in the code just by adding a comment to the default case) or it should for example print something on the screen. This case is relevant as it may happen. Exhaustive switch statements: Those switch statements cover all possible values, e.g. a switch statement on an enumeration of grade system types. When developing code the first time it is easy to cover all values. However, as we are humans there is a small chance to forget some. Additionally if you add an enum value later such that all switch statements have to be adapted to make them exhaustive again opens the path to error hell. The simple solution is a static code analysis tool. The tool should check all switch statements and check if they are exhaustive or if they have a default value. Here an example for an exhaustive switch statement. First we need an enum: public enum GradeSystemType {System1To6, SystemAToD, System0To100} Then we need a variable of this enum like GradeSystemType type = .... An exhaustive switch statement would then look like this: switch(type) { case GradeSystemType.System1To6: // do something case GradeSystemType.SystemAToD: // do something case GradeSystemType.System0To100: // do something } So if we extend the GradeSystemType by for example System1To3 the static code analysis tool should detect that there is no default clause and the switch statement is not exhaustive so we are save.

还有一件事。如果我们总是使用默认子句,那么静态代码分析工具可能无法检测穷尽性或非穷尽性switch语句,因为它总是检测到默认子句。这是非常糟糕的,因为如果我们将枚举扩展为另一个值,并且忘记将其添加到一个switch语句中,我们将不会得到通知。

其他回答

如果你知道switch语句只有一组严格定义的标签或值,那么就这样做,以覆盖基础,这样你总是会得到有效的结果。只需将默认值放在标签之上,从编程/逻辑上来说,它将是其他值的最佳处理程序。

switch(ResponseValue)
{
    default:
    case No:
        return false;
    case Yes;
        return true;
}

这是一个可选的编码“约定”。是否需要取决于用途。我个人认为,如果你不需要它,它就不应该在那里。为什么要包含一些用户不会使用或接触到的内容?

如果情况的可能性是有限的(即一个布尔值),那么默认子句是多余的!

在我的公司,我们为航空电子设备和国防市场编写软件,我们总是包含一个默认语句,因为switch语句中的所有情况都必须显式处理(即使它只是一个说“什么都不做”的注释)。我们不能让软件只是行为不端,或者仅仅是在意外值(甚至是我们认为不可能的值)上崩溃。

可以讨论的是,默认情况并不总是必要的,但通过总是需要它,我们的代码分析人员很容易检查它。

在不真正需要的时候使用默认子句是防御性编程 这通常导致代码过于复杂,因为有太多的错误处理代码。 这种错误处理和检测代码损害了代码的可读性,使维护更加困难,并最终导致比解决更多的错误。

因此,我认为如果不应该达到默认值—您不必添加它。

注意,“不应该达到”意味着如果达到了,这是软件中的一个错误——你确实需要测试可能包含不需要的值的值,因为用户输入等等。

如果switch语句中没有缺省情况,则在缺省情况下行为可能是不可预测的 在某个时间点出现,这在发展阶段是无法预测的。这是一个很好的练习 要包含默认大小写。

switch ( x ){
  case 0 : { - - - -}
  case 1 : { - - - -}
}

/* What happens if case 2 arises and there is a pointer
* initialization to be made in the cases . In such a case ,
* we can end up with a NULL dereference */

这样的做法可能会导致错误,如NULL解引用,内存泄漏以及其他类型的 严重的错误。

例如,我们假设每个条件初始化一个指针。但如果默认情况是 应该是上升的,如果我们不初始化这个例子,那么就完全有可能上升 一个空指针异常。因此,建议使用默认case语句,即使它 可能是微不足道的。