Анонимные блоки кода на Java



существуют ли какие-либо практические применения анонимных блоков кода в Java?



public static void main(String[] args) {
// in
{
// out
}
}


Пожалуйста, обратите внимание, что это не о имени блоки, т. е.



name: { 
if ( /* something */ )
break name;
}


.

419   8  

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, что упрощает чтение, запись и обслуживание кода.

моя проблема с факторингом каждого экземпляра компонента в метод заключается в том, что

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

в этом примере 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

    Ничего не найдено.