Java 中的匿名代码块

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1563030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 14:08:14  来源:igfitidea点击:

Anonymous code blocks in Java

java

提问by Robert Munteanu

Are there any practical uses of anonymous code blocks in Java?

Java 中匿名代码块有什么实际用途吗?

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

Please note that this is not about namedblocks, i.e.

请注意,这与命名块无关,即

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

.

.

采纳答案by David Seiler

They restrict variable scope.

它们限制变量范围。

public void foo()
{
    {
        int i = 10;
    }
    System.out.println(i); // Won't compile.
}

In practice, though, if you find yourself using such a code block that's probably a sign that you want to refactor that block out to a method.

但在实践中,如果您发现自己使用了这样的代码块,这可能表明您想将该块重构为一个方法。

回答by OscarRyz

You may use it as constructor for anonymous inner classes.

您可以将其用作匿名内部类的构造函数。

Like this:

像这样:

alt text

替代文字

This way you can initialize your object, since the free block is executed during the object construction.

这样您就可以初始化您的对象,因为空闲块是在对象构建期间执行的。

It is not restricted to anonymous inner classes, it applies to regular classes too.

它不限于匿名内部类,它也适用于常规类。

public class SomeClass {
    public List data;{
        data = new ArrayList();
        data.add(1);
        data.add(1);
        data.add(1);
    }
}

回答by dfa

Anonymous blocks are useful for limiting the scope of a variable as well as for double brace initialization.

匿名块对于限制变量的范围以及双括号初始化很有用。

Compare

相比

Set<String> validCodes = new HashSet<String>();
validCodes.add("XZ13s");
validCodes.add("AB21/X");
validCodes.add("YYLEX");
validCodes.add("AR2D");

with

Set<String> validCodes = new HashSet<String>() {{
  add("XZ13s");
  add("AB21/X");
  add("YYLEX");
  add("AR5E");
}};

回答by Stephen C

I think you and/or the other answers are confusing two distinct syntactic constructs; namely Instance Initializers and Blocks. (And by the way, a "named block" is really a Labeled Statement, where the Statement happens to be a Block.)

我认为您和/或其他答案混淆了两种不同的句法结构;即实例初始化器和块。(顺便说一句,“命名块”实际上是一个带标签的语句,其中语句恰好是一个块。)

An Instance Initializer is used at the syntactic level of a class member; e.g.

Instance Initializer 用于类成员的语法级别;例如

public class Test {
    final int foo;

    {
         // Some complicated initialization sequence; e.g.
         int tmp;
         if (...) {
             ...
             tmp = ...
         } else {
             ...
             tmp = ...
         }
         foo = tmp;
    }
}

The Initializer construct is most commonly used with anonymous classes as per @dfa's example. Another use-case is for doing complicated initialization of 'final' attributes; e.g. see the example above. (However, it is more common to do this using a regular constructor. The pattern above is more commonly used with Static Initializers.)

根据@dfa 的示例,Initializer 构造最常用于匿名类。另一个用例是对“最终”属性进行复杂的初始化;例如见上面的例子。(但是,使用常规构造函数执行此操作更为常见。上面的模式更常用于静态初始化程序。)

The other construct is an ordinary block and appears within a code block such as method; e.g.

另一个结构是一个普通块,出现在一个代码块中,例如方法;例如

public void test() {
    int i = 1;
    {
       int j = 2;
       ...
    }
    {
       int j = 3;
       ...
    }
}

Blocks are most commonly used as part of control statements to group a sequence of statements. But when you use them above, they (just) allow you to restrict the visibility of declarations; e.g. jin the above.

块最常用作控制语句的一部分以对语句序列进行分组。但是当你在上面使用它们时,它们(只是)允许你限制声明的可见性;例如j在上面。

This usually indicates that you need to refactor your code, but it is not always clear cut. For example, you sometimes see this sort of thing in interpreters coded in Java. The statements in the switch arms could be factored into separate methods, but this may result in a significant performance hit for the "inner loop" of an interpreter; e.g.

这通常表明您需要重构代码,但并不总是很明确。例如,您有时会在用 Java 编码的解释器中看到这种情况。可以将 switch 臂中的语句分解为单独的方法,但这可能会导致解释器“内部循环”的显着性能下降;例如

    switch (op) {
    case OP1: {
             int tmp = ...;
             // do something
             break;
         }
    case OP2: {
             int tmp = ...;
             // do something else
             break;
         }
    ...
    };

回答by Stephen Swensen

@David Seiler's answer is right, but I would contend that code blocks are very useful and should be used frequently and don't necessarily indicate the need to factor out into a method. I find they are particularly useful for constructing Swing Component trees, e.g:

@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);
}

Not only do the code blocks limit the scope of variables as tightly as possible (which is always good, especially when dealing with mutable state and non-final variables), but they also illustrate the component hierarchy much in the way as XML / HTML making the code easier to read, write and maintain.

代码块不仅尽可能严格地限制了变量的范围(这总是好的,尤其是在处理可变状态和非最终变量时),而且它们还以 XML / HTML 制作的方式来说明组件层次结构代码更易于阅读、编写和维护。

My issue with factoring out each component instantiation into a method is that

我将每个组件实例化分解为方法的问题是

  1. The method will only be used once yet exposed to a wider audience, even if it is a private instance method.
  2. It's harder to read, imagining a deeper more complex component tree, you'd have to drill down to find the code you're interested, and then loose visual context.
  1. 该方法只会使用一次,但会暴露给更广泛的受众,即使它是私有实例方法。
  2. 它更难阅读,想象一个更深更复杂的组件树,您必须深入查找您感兴趣的代码,然后松散视觉上下文。

In this Swing example, I find that when complexity really does grow beyond manageability it indicates that it's time to factor out a branch of the tree into a new class rather than a bunch of small methods.

在这个 Swing 示例中,我发现当复杂性确实增长到超出可管理性时,这表明是时候将树的一个分支分解为一个新类而不是一堆小方法了。

回答by Kevin K

It's usually best to make the scope of local variables as small as possible. Anonymous code blocks can help with this.

通常最好使局部变量的范围尽可能小。匿名代码块可以帮助解决这个问题。

I find this especially useful with switchstatements. Consider the following example, without anonymous code blocks:

我发现这对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;
    }
}

And with anonymous code blocks:

并使用匿名代码块:

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;
        }
    }
}

I consider the second version to be cleaner and easier to read. And, it reduces the scope of variables declared within the switch to the case to which they were declared, which in my experience is what you want 99% of the time anyways.

我认为第二个版本更清晰、更易于阅读。而且,它将 switch 中声明的变量的范围缩小到它们被声明的情况,根据我的经验,无论如何,这在 99% 的情况下都是你想要的。

Be warned however, it does notchange the behavior for case fall-through - you'll still need to remember to include a breakor returnto prevent it!

然而,要注意,它并不会改变行为情况下通-你仍然需要记住包括breakreturn阻止它!

回答by stewartbracken

You can use a block to initialize a final variable from the parent scope. This a nice way to limit the scope of some variables only used to initialize the single variable.

您可以使用块从父作用域初始化最终变量。这是限制某些仅用于初始化单个变量的变量范围的好方法。

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
}

In general it's preferable to move the block into a method, but this syntax can be nice for one-off cases when multiple variables need to be returned and you don't want to create a wrapper class.

一般来说,最好将块移动到一个方法中,但是当需要返回多个变量并且您不想创建包装类时,这种语法对于一次性情况可能很好。

回答by Aniket Sahrawat

Instance initializer block:

实例初始化块:

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!"
    }
}

Anonymous initializer block:

匿名初始化块:

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]
        }
    }
}

Variable scope restrict:

变量范围限制:

class Test {
    public static void main() {
        { int i = 20; }
        System.out.println(i); // error
    }
}