Java中的花括号本身是什么意思?


79

我有一些以两种方式使用花括号的Java代码

// Curly braces attached to an 'if' statement:
if(node.getId() != null)
{
    node.getId().apply(this);
}

// Curly braces by themselves:
{
    List<PExp> copy = new ArrayList<PExp>(node.getArgs());
    for(PExp e : copy)
    {
        e.apply(this);
    }
}
outAMethodExp(node);

在第一个if语句之后,这些独立的花括号是什么意思?

Answers:


120

额外括号的唯一目的是提供范围限制。这些List<PExp> copy将仅存在于这些大括号内,并且将不在它们之外。

如果这是生成的代码,则我假设代码生成器会执行此操作,因此它可以插入一些代码(例如此代码),而不必担心它插入了a的次数,List<PExp> copy并且不必担心如果此代码段可能会重命名变量多次插入同一方法。


9
在这种情况下,另一个好处是copy可以在outAMethodExp()返回之前进行垃圾回收。如果这是长时间运行或占用大量内存的电话,则可能会有所帮助。我将“好处”用引号引起来,因为将重构分解为单独的方法通常比利用此语法更简洁明了。
dimo414

1
实际上,确定范围的变量并没有对垃圾收集的效果。在我所知道的所有现代JVM中,JIT都可以确定对象是否符合GC的条件,而不管是否存在诸如括号之类的作用域构造。
丹尼尔·普赖登

27

我第二次讲了matt b写的内容,然后我补充说,我看到的匿名括号的另一种用法是在匿名类中声明一个隐式构造函数。例如:

  List<String> names = new ArrayList<String>() {
    // I want to initialize this ArrayList instace in-line,
    // but I can't define a constructor for an anonymous class:
      {
        add("Adam");
        add("Eve");
      }

  };

一些单元测试框架将此语法带入了另一个层次,这确实允许一些看起来完全不可编译的漂亮东西起作用。由于他们看起来不熟悉,所以我自己并不是一个忠实拥护者,但是如果您遇到这种情况,至少应该认识到发生了什么是值得的。


抱歉,我不理解此代码。是“添加”类或函数。如果是函数:它属于哪个类?在这种情况下,ArrayList是否接受委托类型?
彼得·莫滕森

7
“添加”是一个功能。花括号中的内容在构造函数之前被调用以执行一些初步的初始化。您可以查看c2.com/cgi/wiki?DoubleBraceInitialization了解更多信息。
Zaven Nahapetyan 2010年

1
从技术上讲,首先调用构造函数,然后在调用之后立即调用实例初始化块super(...)
奥利(Oli)2015年

8

我同意范围限制的答案,但会增加一件事。

有时,您会在代码中看到类似的结构,这些人喜欢折叠其代码的某些部分,并希望编辑器会自动折叠大括号。他们使用它在逻辑部分中折叠他们的代码,这些逻辑部分通常不属于函数,类,循环等。


4

实际上,我猜想有人忘记了其他声明。

几乎没有充分的理由烦恼创建其他块作用域。在这种情况下,大多数情况下,某人可能忘记输入自己的控制语句,而不是他们做的很聪明。


2
我之所以投票支持您,是因为它可能会发生,已经发生,而Occam却因为您被否决而在他的坟墓中滚动。:)
willasaywhat

1
它是由SableCC生成的。我敢打赌,$ 5,他们没忘了其它的
帕维尔·费尔德曼

额外的花括号对于防止全局变量在较长的方法上蔓延非常有用,在较长的方法中,您要将几个相似的代码块都保留在同一位置,而这些代码块的复杂程度不足以保证使用新方法。
jayunit100 2011年

我在大学里标记了Java课程,并且可以看到,这实际上通常是在代码中找到它的确切原因。当人们进行分解时,有时会剪切/粘贴,然后看到错误的括号数量,..只需添加一个..然后看看最终得到的结果。因此,我对此表示赞成。并非总是一个else语句,而是一个简单的错误。
ThePerson

我投票支持您,因为-1票意味着您甚至都不应该参加。也许您不知道,但是您付出了努力。我并不是要为所有人提供奖杯,但是“感谢”就是我对试图提供帮助的人所说的。(+1 ==谢谢)。
user426364 2014年

2

它们构成了内部作用域。在这些花括号内声明的变量在它们外面不可见。这也适用于C / C ++。


1

大括号对于减小switch / case语句的范围也很有用。

switch(foo) {
  case BAR:
     int i = ...
     ...
  case BAZ:
     int i = ... // error, "i" already defined in scope
}

但是你可以写

switch(foo) {
  case BAR:{
     int i = ...
     ...
  }
  case BAZ:{
     int i = ... // OK
  }
}

1

它也用于初始化块


可能值得一提的是,这仅适用于构造函数外部的静态类初始化。OPs代码段位于方法块中(仅在可能的位置)。
mmoore

如果初始化块前面带有实例初始化块,static则该初始化块用于静态类初始化。
加百利

真实的故事。感谢您的澄清。
mmoore

0

它们定义了一个新的范围,这意味着在该范围中声明的所有内容在花括号外都不可见。


0

需要注意的是:花括号实际上使能一类语句:声明。

这是非法的: if(a) int f;

但这是合法的: if(a) { int f; }


正是这段代码没有用,您将无法在花括号之外看到f。要使用它,您需要在相同范围内声明和使用它。因此,您需要多个陈述,因此需要大括号。
帕维尔·费尔德曼

这就是我要提到的编译器检查的重点。我发现有趣的是,“隐式作用域”(我认为每个大括号不带括号)和显式作用域都有区别。很容易忘记编译器会有所作为。
雨果

?那么如果(userWantsTocInReport){新的TOC(报告};}我不是说这是写它的理想方式,但它是一个可能性,有人可以选择,不管是什么原因
user625488


0

带作用域的副本在其外部将不可见,因此您以后可以声明另一个具有相同名称的变量。并且可以在退出该范围之后立即由垃圾收集器收集。在这种情况下,副本用作临时变量,因此这是一个很好的示例。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.