8 ответов:
они ограничивают область видимости переменной.
public void foo() { { int i = 10; } System.out.println(i); // Won't compile. }на практике, однако, если вы оказываетесь, используя такой блок кода, который, вероятно, признак того, что вы хотите рефакторинг этого метода.
@David Seiler ответ правильный, но я бы утверждал, что блоки кода очень полезны и должны использоваться часто и не обязательно указывать на необходимость учета в методе. Я считаю, что они особенно полезны для построения деревьев компонентов Swing, например:
JPanel mainPanel = new JPanel(new BorderLayout()); { JLabel centerLabel = new JLabel(); centerLabel.setText("Hello World"); mainPanel.add(centerLabel, BorderLayout.CENTER); } { JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0,0)); { JLabel label1 = new JLabel(); label1.setText("Hello"); southPanel.add(label1); } { JLabel label2 = new JLabel(); label2.setText("World"); southPanel.add(label2); } mainPanel.add(southPanel, BorderLayout.SOUTH); }блоки кода не только максимально сильно ограничивают область переменных (что всегда хорошо, особенно при работе с изменяемыми состояниями и неокончательными переменными), но и проиллюстрируйте иерархию компонентов так же, как XML / HTML, что упрощает чтение, запись и обслуживание кода.
моя проблема с факторингом каждого экземпляра компонента в метод заключается в том, что
- метод будет использоваться только один раз, но будет доступен более широкой аудитории, даже если это метод частного экземпляра.
- это труднее читать, представляя себе более глубокое более сложное дерево компонентов, вам придется детализировать, чтобы найти интересующий вас код, и затем освободите визуальный контекст.
в этом примере Swing я нахожу, что когда сложность действительно выходит за пределы управляемости, это указывает на то, что пришло время разложить ветвь дерева на новый класс, а не на кучу небольших методов.
обычно сделать область видимости локальных переменных как можно меньше. Анонимные блоки кода могут помочь в этом.
Я нахожу это особенно полезно с
switchзаявления. Рассмотрим следующий пример, без анонимных блоков кода:public String manipulate(Mode mode) { switch(mode) { case FOO: String result = foo(); tweak(result); return result; case BAR: String result = bar(); // Compiler error twiddle(result); return result; case BAZ: String rsult = bar(); // Whoops, typo! twang(result); // No compiler error return result; } }и с анонимных блоков кода:
public String manipulate(Mode mode) { switch(mode) { case FOO: { String result = foo(); tweak(result); return result; } case BAR: { String result = bar(); // No compiler error twiddle(result); return result; } case BAZ: { String rsult = bar(); // Whoops, typo! twang(result); // Compiler error return result; } } }Я считаю, что вторая версия будет чище и легче читать. И, это уменьшает область действия переменных, объявленных в переключитесь на дело, в котором они были объявлены, что, по моему опыту, вы хотите 99% времени в любом случае.
будьте осторожны, однако, это делает не изменить поведение для случая падения-вы все равно должны помнить, чтобы включить
breakилиreturnчтобы предотвратить это!
Я думаю, что вы и / или другие ответы путают две различные синтаксические конструкции; а именно инициализаторы экземпляра и блоки. (И, кстати," именованный блок " - это действительно помеченный оператор, где оператор оказывается блоком.)
инициализатор экземпляра используется на синтаксическом уровне члена класса; например
public class Test { final int foo; { // Some complicated initialization sequence; e.g. int tmp; if (...) { ... tmp = ... } else { ... tmp = ... } foo = tmp; } }конструкция инициализатора чаще всего используется с анонимными классами в соответствии с примером @dfa. Другой вариант использования - это делать сложная инициализация "окончательных" атрибутов; например, см. пример выше. (Однако чаще это делается с помощью обычного конструктора. Приведенный выше шаблон чаще используется со статическими инициализаторами.)
другая конструкция является обычным блоком и появляется в блоке кода, таком как метод; например
public void test() { int i = 1; { int j = 2; ... } { int j = 3; ... } }блоки чаще всего используются как часть управляющих операторов для группировки последовательности операторов. Но когда вы используете их выше, они (просто) позволяют вы должны ограничить видимость объявлений; например
jв выше.это обычно означает, что вам нужно рефакторинг кода, но это не всегда ясно. Например, вы иногда видите такие вещи в интерпретаторах, закодированных на Java. Операторы в плечах коммутатора могут быть разделены на отдельные методы, но это может привести к значительному снижению производительности для "внутреннего цикла" интерпретатора; например
switch (op) { case OP1: { int tmp = ...; // do something break; } case OP2: { int tmp = ...; // do something else break; } ... };
вы можете использовать его в качестве конструктора для анонимных внутренних классов.
такой:
alt текст http://img113.imageshack.us/img113/888/capturadepantalla200910.png
таким образом, вы можете инициализировать свой объект, так как свободный блок выполняется во время построения объекта.
Это не ограничивается анонимными внутренними классами, это относится и к обычным классам тоже.
public class SomeClass { public List data;{ data = new ArrayList(); data.add(1); data.add(1); data.add(1); } }
анонимные блоки полезны для ограничения области действия переменной, а также для двойной дубль инициализации.
сравнить
Set<String> validCodes = new HashSet<String>(); validCodes.add("XZ13s"); validCodes.add("AB21/X"); validCodes.add("YYLEX"); validCodes.add("AR2D");С
Set<String> validCodes = new HashSet<String>() {{ add("XZ13s"); add("AB21/X"); add("YYLEX"); add("AR5E"); }};
блок инициализатора экземпляра:
class Test { // this line of code is executed whenever a new instance of Test is created { System.out.println("Instance created!"); } public static void main() { new Test(); // prints "Instance created!" new Test(); // prints "Instance created!" } }анонимный блок инициализатора:
class Test { class Main { public void method() { System.out.println("Test method"); } } public static void main(String[] args) { new Test().new Main() { { method(); // prints "Test method" } }; { //========================================================================= // which means you can even create a List using double brace List<String> list = new ArrayList<>() { { add("el1"); add("el2"); } }; System.out.println(list); // prints [el1, el2] } { //========================================================================== // you can even create your own methods for your anonymous class and use them List<String> list = new ArrayList<String>() { private void myCustomMethod(String s1, String s2) { add(s1); add(s2); } { myCustomMethod("el3", "el4"); } }; System.out.println(list); // prints [el3, el4] } } }ограничение области действия переменной:
class Test { public static void main() { { int i = 20; } System.out.println(i); // error } }
вы можете использовать блок для инициализации конечной переменной из родительской области. Это хороший способ ограничить область действия некоторых переменных, используемых только для инициализации одной переменной.
public void test(final int x) { final ClassA a; final ClassB b; { final ClassC parmC = getC(x); a = parmC.getA(); b = parmC.getB(); } //... a and b are initialized }В общем случае предпочтительно переместить блок в метод, но этот синтаксис может быть хорош для одноразовых случаев, когда необходимо вернуть несколько переменных, и вы не хотите создавать класс-оболочку.
Comments