在Java中省略花括号是否可以?

95

我已经搜索过了,但找不到答案,由于那种当数百人盯着你时的感觉,我不好意思问教授...

无论如何,我的问题是括号的重要性是什么?如果我省略它们会怎样?例如:

for (int i = 0; i < size; i++)  {
   a += b;
}

vs

的翻译是:vs。
for (int i = 0; i < size; i++)
   a += b;
我知道这两个都能用,但是如果我省略括号(由于可见性,我经常这样做),会有什么变化吗?就像我说的,我知道它可以工作,我测试过很多次,但现在我的一些大学作业变得更加庞大了,因为某种原因我对此产生了不理性的恐惧,长远来看,这可能会引起一些问题吗?有没有理由担心呢?

我总是使用代码格式化工具来提高可读性,因为这可以解决许多潜在的混淆原因。这可能会使花括号变得多余。 - Peter Lawrey
16个回答

165

它实际上不会改变任何东西,除了你代码的可维护性。我曾经看到过这样的代码:

for (int i = 0; i < size; i++)
   a += b;
   System.out.println("foo");

这意味着:

for (int i = 0; i < size; i++)
   a += b;
System.out.println("foo");

...但是应该是这样的:

for (int i = 0; i < size; i++) {
   a += b;
   System.out.println("foo");
}

个人而言,我总是包括括号以减少阅读或修改代码时的混淆可能性。

在我所工作的每家公司的编码惯例中都要求这样做 - 这并不意味着其他公司没有不同的惯例...

如果你认为这永远不会有影响,那么请注意:我曾经修复过一个与上述代码几乎等价的错误。 它非常难以发现...(诚然,这是多年前,在我开始进行单元测试之前,单元测试无疑会使其更容易被诊断)。


14
你知道这个问题,但是你只是假设它永远不会影响到你?而且每个阅读你代码的人都知道该期望什么?我只是想说——在我所使用的编码规范中需要它们,这是有原因的。 - Jon Skeet
12
我感觉就像一个私人被军士指挥般地讲话了。是的,虽然对我来说更方便,但是我的团队中的其他人可能会觉得很烦人和有问题。从现在开始,我会确保到处使用括号。 - vedran
14
@vedran的比喻很好,除了Jon Skeet不是军士长,他是最高指挥官 :-) - stivlo
6
@stivlo 哦,我相信他的殿下会原谅轻微的不服从 ;) 就个人而言,我在语句后面放置括号,因为这是我见过的每个编码指南的一部分,但我认为这是一个相当薄弱的论点。由于自动代码格式化已经到处都有了,你应该永远不会看到代码的原始表单,如果缩进正确,花括号就不会提供任何额外的信息。 - Voo
4
始终使用大括号的更多理由:https://www.imperialviolet.org/2014/02/22/applebug.html - MrTJ
显示剩余9条评论

37

使用花括号可以使代码更易于维护和理解。因此,您应该默认考虑使用它们。

我有时会跳过在防卫语句上使用花括号以使代码更紧凑的方法。我的要求是它们必须是跟随着一个跳转语句(如return或者throw)的if语句。此外,我将它们保持在同一行以引起注意,例如:

if (!isActive()) return;

它们也适用于循环内部的代码:

for (...) {
  if (shouldSkip()) continue;
  ...
}

对于不一定在方法体顶部的方法,还有其他的跳转条件。

一些语言(如Perl或Ruby)具有一种类似于条件语句的结构,其中括号不适用:

return if (!isActive());
// or, more interestingly
return unless (isActive());

我认为它与我刚刚描述的内容是等价的,但是它是明确受到语言支持的。


7
循环内的+1守卫条款通常没有花括号更加清晰明了。 - Viccari
2
同意使用守卫条款。在我看来,这使得代码更易读,实际上也增加了可维护性。不过,接受的答案提出的观点非常有效,因此我会将省略大括号的情况限制在守卫条款中。 - ChrisK

12

没有区别。第二个版本的主要问题是你可能最终会写成这样:

for (...) 
  do_something();
  do_something_else();

当你更新那个方法时,以为do_something_else()在循环内部被调用。这会导致令人困惑的调试过程。

第二个问题是花括号版本没有的,它可能更难以发现:

for (int i=0; i<3; i++);
  System.out.println("Why on earth does this print just once?");

所以,除非你有充分的理由,否则请保留大括号,这只需要多输入几个按键。


3
第一点很好,但第二点是错误的。 使用大括号版本仍然可能存在该问题。 for (int i=0;i<3;i++); { System.out.println("为什么这只打印一次?"); }。我知道这是因为我总是使用大括号,但有时会错误地添加额外的分号。 - emory
3
如果花括号与代码在同一行上,那么使用花括号版本是可行的,但是如果花括号放在下一行,这种方法就不太好看了。 - Mat
对我来说,第二个版本和第一个版本一样重要,因为看第二个版本时,几乎不可能发现错在哪里,直到你实际运行它并查看出了什么问题。开发人员花费了很多时间调试这样的代码,如果括号被加入其中,这些问题将很容易被发现。对我来说,省略这些花括号不仅是风格问题,而且也是潜在错误的很好指标。 - theyCallMeJun

7
大多数情况下,到目前为止提到的答案是正确的。但从安全角度来看,它也存在一些缺点。作为支付团队的一员,安全是决策的一个更强因素。假设您有以下代码:
if( "Prod".equals(stage) )
  callBankFunction ( creditCardInput )
else
  callMockBankFunction ( creditCardInput )

现在假设您的代码由于某些内部问题而无法工作。您想要检查输入。所以您进行以下更改:

if( "Prod".equals(stage) )
  callBankFunction ( creditCardInput )
else
  callMockBankFunction ( creditCardInput )
  Logger.log( creditCardInput )

假设您已经解决了这个问题并部署了此代码(也许审阅者和您认为这不会引起问题,因为它不在“Prod”条件内)。神奇的是,您的生产日志现在打印出客户信用卡信息,所有能看到日志的人员都能看到。如果其中任何人(带有恶意意图)获得了这些数据,后果不堪设想。

因此,不给予大括号和一点粗心编码往往会导致安全信息被泄露。这也被CERT - 软件工程研究所,CMU归类为JAVA中的漏洞。


我认为这本来就是一个相当糟糕的设计,但这个观点是正确的。 - Christopher Schneider
非常好的观点。我认为,如果你正在处理如此敏感的数据,那么为了减少错误,我们所做的让程序员开心的事情都会被搁置一边,而选择冗长的代码。但是,对于我们大多数人来说(我想说的是),在单行的if/else语句中不使用括号更容易解析和理解。 - Joshua Pinter

6
我认为,如果您也使用自动格式化,则省略花括号是好的,因为这样您的缩进总是正确的,因此可以轻松地找到任何错误。
说省略花括号是不好、奇怪或难以阅读的是错误的,因为整个语言都基于这个想法,并且它非常流行(例如Python)。
但我必须说,如果不使用格式化工具,这可能会很危险。

1
Python中缩进很重要。在Java、C、C++或其他C风格的语言中,它并不重要。 - Christopher Schneider
1
@ChristopherSchneider 这就是重点。 - Máté Magyar

4

如果只有一个语句,可以省略大括号,但如果有多个语句就必须使用大括号声明代码块。

当你使用大括号时,表示你正在声明一个代码块:

{

//Block of code
}

当您处于嵌套语句的情况下,为了提高可读性,即使只有一个语句,也应该使用括号。例如:
for( ; ; )
  if(a == b) 
    doSomething()

如果没有必要,使用括号可以使IT技术更易读:

for( ; ; ) {
  if(a == b) {
    doSomething()
   }
}

没错 :) 更易读 = 需要更少的努力。因此,为了避免可能的未来错误,我们最终都会陷入括号的泥潭中,我们需要看到和书写 :) - Zbyszek

4
如果你使用括号,你的代码会更易读。如果你需要在同一块中添加一些运算符,你可以避免可能出现的错误。

不使用括号来表示单个指令会使代码变得不够可读,因为这样会让你的眼睛和大脑处理更多的符号,而这些符号并没有提供额外的信息。这也是为什么Python变得越来越受欢迎的原因。在这种语言中编程需要付出较少的努力,因为它的代码更短,不含有不必要的元素。 - Zbyszek

3

现在,重新缩进代码以找出哪个代码块属于哪个iffor/while很容易。如果你坚持认为重新缩进很难做到,那么放置在错误缩进位置的括号同样会让你感到困惑。

for(int i = 0; i < 100; i++) { if(i < 10) {
    doSomething();
} else { for(int j = 0; j < 5; j++) {
        doSomethingElse();
    }
}}

如果你在每个地方都这样做,你的大脑很快就会崩溃。即使有括号,你还是要依赖缩进来直观地找到代码块的开始和结束。
如果缩进很重要,那么你应该已经按照正确的缩进格式书写代码,这样其他人就不需要重新缩进你的代码才能正确阅读。
如果你想争论之前的例子太虚假/刻意了,而括号是用来解决粗心的缩进问题(特别是当你复制/粘贴代码时),那么请考虑以下内容:
for(int i = 0; i < 100; i++) {
    if(i < 10) {
    doSomething();
}
else {
    for(int j = 0; j < 5; j++) {
        doSomethingElse();
    }
}

是的,它看起来比之前的例子要简单一些,但你仍然可能会被这样的缩进弄糊涂。

在我看来,编写代码的人有责任检查代码并确保正确缩进,然后再进行其他操作。


3
使用冗余的大括号声称代码更易维护,这引发了一个问题:如果编写、思考和进一步维护代码的人员存在与缩进或可读性相关的问题,那么他们也许根本不应该从事编程...

3

使用花括号可以将代码未来的修改保护起来。我曾经见过一些情况,其中省略了花括号,并且后来有人添加了一些代码,但并没有在那个时候加上花括号。结果是,他们添加的代码并没有进入他们认为的部分。因此,我认为这是在考虑到代码未来的变化时的良好实践。我已经看到软件组将其作为标准采用,即始终要求使用花括号,即使是单行块也是如此。


我同意这个观点。括号不是为你而设,而是为接下来的维护者所准备的。有好几次,我需要维护一些我不熟悉的代码,它们没有使用括号,并且缩进不当。此时,我可能在解决一个bug,因此知道代码的预期行为非常重要。省略括号会让事情变得不太明显,我必须逐步跟踪代码,浪费时间。 - Christopher Schneider
一个人可能保护自己免受一切伤害,这样是完美的。但是这种状态是不可持续的 :) - Zbyszek

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