IT박스

자바의 익명 코드 블록

itboxs 2020. 11. 29. 10:06
반응형

자바의 익명 코드 블록


Java에서 익명 코드 블록을 실제로 사용합니까?

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

이것은 명명 된 블록 에 대한 것이 아닙니다.

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

.


변수 범위를 제한합니다.

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

그러나 실제로 이러한 코드 블록을 사용하는 경우에는 해당 블록을 메서드로 리팩토링하려는 신호일 수 있습니다.


@David Seiler의 대답은 옳지 만 코드 블록은 매우 유용하며 자주 사용되어야하며 반드시 메서드를 고려할 필요성을 나타내지는 않는다고 주장합니다. 스윙 컴포넌트 트리를 구성하는 데 특히 유용합니다. 예 :

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

Initializer 구문은 @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;
         }
    ...
    };

익명 내부 클래스의 생성자로 사용할 수 있습니다.

이렇게 :

대체 텍스트

이렇게하면 개체 생성 중에 사용 가능한 블록이 실행되기 때문에 개체를 초기화 할 수 있습니다.

익명의 내부 클래스로 제한되지 않고 일반 클래스에도 적용됩니다.

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
}

일반적으로 블록을 메서드로 이동하는 것이 좋지만이 구문은 여러 변수를 반환해야하고 래퍼 클래스를 만들고 싶지 않은 일회성 경우에 유용 할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/1563030/anonymous-code-blocks-in-java

반응형