Что означают фигурные скобки в 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оператора?

Пол Уикс
источник

Ответы:

120

Единственная цель дополнительных фигурных скобок - обеспечить ограничение области действия. List<PExp> copyБудет существовать только в пределах этих скобок, и не будет иметь никакой возможности вне их.

Если это сгенерированный код, я предполагаю, что генератор кода делает это, чтобы он мог вставить некоторый код (например, этот), не беспокоясь о том, сколько раз он вставлял a, List<PExp> copyи не беспокоясь о возможном переименовании переменных, если этот фрагмент вставляется в один и тот же метод более одного раза.

Мэтт Би
источник
9
Дополнительным «преимуществом» в этом случае является то, что copyперед outAMethodExp()возвратом можно выполнить сборку мусора . Если это длительный вызов или вызов, требующий интенсивного использования памяти, это может быть полезно. Я заключил «выгоду» в кавычки, потому что рефакторинг в отдельные методы, как правило, намного чище и понятнее, чем использование преимуществ этого синтаксиса.
dimo414
1
На самом деле, определение области видимости переменной не влияет на сборку мусора. Во всех известных мне современных JVM JIT может определить, что объект имеет право на сборку мусора, независимо от наличия или отсутствия конструкций области видимости, таких как фигурные скобки.
Дэниел Прайден
27

Я вторю тому, что написал Мэтт Б., и добавлю, что еще одно использование анонимных скобок, которое я видел, - это объявление неявного конструктора в анонимных классах. Например:

  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 для получения дополнительной информации.
Завен Нахапетян
1
Технически сначала вызывается конструктор, а блок инициализации экземпляра вызывается сразу после вызова super(...).
Оли
8

Я согласен с ответом на ограничение объема, но добавлю одно.

Иногда вы видите подобную конструкцию в коде людей, которые любят сворачивать разделы своего кода и имеют редакторы, которые автоматически складывают фигурные скобки. Они используют его для сворачивания своего кода в логические секции, которые не попадают в функцию, класс, цикл и т. Д., Которые обычно сворачиваются.

Эли
источник
4

На самом деле я предполагаю, что кто-то забыл заявление else.

Редко есть веская причина даже беспокоиться о создании дополнительных областей видимости блока. В этом и в большинстве случаев гораздо более вероятно, что кто-то забыл ввести свой управляющий оператор, чем что он сделал что-то умное.

Патрик
источник
2
Я голосую за вас просто потому, что это могло случиться, произошло, и Оккам катится в могиле, потому что вас проголосовали против. :)
willasaywhat
1
Он генерируется SableCC. Бьюсь об заклад, 5 $ они не забыли еще
Павел Фельдман
Дополнительные фигурные скобки полезны для предотвращения нарастания глобальных переменных в длинном методе, когда вы хотите сохранить несколько похожих блоков кода в одном месте, где блоки недостаточно сложны, чтобы требовать новых методов.
jayunit100 06
Я отмечаю курсовую работу по Java в университете и вижу, что на самом деле часто именно по этой причине она встречается в коде. При повторном факторинге люди иногда вырезают / вставляют, а затем видят неправильное количество скобок ... просто добавьте одну ... а затем посмотрите, что у вас получится. По этой причине я голосую за это. Не всегда заявление else, но часто просто ошибка.
ThePerson
Я поддержал вас, потому что -1 голос означает, что вы даже не должны были участвовать. Возможно, вы не знали, но вы приложили усилия. Я не о трофеях для всех, но «спасибо» - это как раз то, что я говорю людям, которые пытаются помочь. (+1 == спасибо).
user426364 02
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

Они определяют новую область видимости, что означает, что все, что объявлено в этой области, не видно за пределами фигурных скобок.

fhe
источник
0

Интересное примечание: фигурные скобки фактически включают класс операторов: объявления.

Это незаконно: if(a) int f;

но это законно: if(a) { int f; }

Хьюго
источник
Именно этот код бесполезен, вы не сможете увидеть f вне фигурных скобок. И чтобы использовать его, вам нужно объявить и использовать его в той же области. Итак, вам нужно более одного утверждения, поэтому вам нужны фигурные скобки.
Павел Фельдман,
в этом смысл проверки компилятора, о которой я говорю. Мне интересно, что существует разница в «неявной области видимости» (которую я считаю каждой однострочником без фигурных скобок) и явной. Легко забыть, что компилятор будет иметь значение.
Хьюго
А как насчет if (userWantsTocInReport) {new Toc (report};}? Я не говорю, что это идеальный способ его написания, но это возможность, что кто-то может выбрать по любой причине.
user625488
0

Я думаю, они просто определяют безымянный уровень охвата.

Питер Мортенсен
источник
0

Принесите область видимости, копия не будет видна за ее пределами, поэтому вы можете объявить другую переменную с тем же именем позже. И он может быть собран сборщиком мусора сразу после выхода из этой области. В этом случае копия служит временной переменной, так что это хороший пример.

Павел Фельдман
источник