[java] 자바에서 goto 문에 대한 대안

Java 에서 goto 키워드에 대한 대체 기능은 무엇입니까 ?

Java에는 goto가 없기 때문에.



답변

레이블이 지정된 BREAK 문을 사용할 수 있습니다 .

search:
    for (i = 0; i < arrayOfInts.length; i++) {
        for (j = 0; j < arrayOfInts[i].length; j++) {
            if (arrayOfInts[i][j] == searchfor) {
                foundIt = true;
                break search;
            }
        }
    }

그러나 올바르게 설계된 코드에서는 GOTO 기능이 필요하지 않습니다.


답변

gotoJava 의 개념 과 직접적으로 동등한 것은 없습니다 . 클래식으로 할 수있는 작업 중 일부 를 수행 할 수있는 몇 가지 구성이 있습니다 goto.

  • breakcontinue문은 루프 또는 스위치 문에서 블록 밖으로 점프 할 수 있습니다.
  • 레이블이 지정된 문 break <label>으로 임의의 복합 문에서 주어진 메서드 (또는 이니셜 라이저 블록) 내의 모든 수준으로 이동할 수 있습니다.
  • 루프 문에 레이블 continue <label>을 지정하면 내부 루프에서 외부 루프의 다음 반복을 계속할 수 있습니다 .
  • 예외를 던지고 잡으면 여러 수준의 메서드 호출에서 (효과적으로) 점프 할 수 있습니다. (그러나 예외는 상대적으로 비용이 많이 들고 “일반적인”제어 흐름 1 을 수행하는 나쁜 방법으로 간주됩니다 .)
  • 물론 return.

이러한 Java 구성 중 어느 것도 현재 명령문과 동일한 중첩 수준에있는 코드의 한 지점 또는 역방향 분기를 허용하지 않습니다. 그들은 모두 하나 이상의 중첩 (범위) 레벨을 continue뛰어 내리고 모두 (제외 ) 아래로 점프합니다. 이 제한은 이전 BASIC, FORTRAN 및 COBOL 코드 2에 내재 된 goto “스파게티 코드”증후군을 방지하는 데 도움이됩니다 .


1- 예외에서 가장 비용이 많이 드는 부분은 예외 개체와 스택 추적의 실제 생성입니다. 정말로 “정상”흐름 제어에 예외 처리를 사용해야하는 경우 예외 개체를 미리 할당 / 재사용하거나 fillInStackTrace()메서드 를 재정의하는 사용자 지정 예외 클래스를 만들 수 있습니다 . 단점은 예외의 printStackTrace()메서드가 유용한 정보를 제공하지 않는다는 것입니다.

2-스파게티 코드 신드롬은 사용 가능한 언어 구조의 사용을 제한 하는 구조적 프로그래밍 접근 방식을 생성했습니다. 이것은 BASIC , FortranCOBOL에 적용될 수 있지만주의와 규율이 필요했습니다. goto완전히 제거 하는 것이 실용적으로 더 나은 해결책이었습니다. 언어로 보관하면 항상 그것을 남용하는 광대가 있습니다.


답변

그냥 재미를 위해, 여기에 자바에서 GOTO 구현입니다.

예:

   1 public class GotoDemo {
   2     public static void main(String[] args) {
   3         int i = 3;
   4         System.out.println(i);
   5         i = i - 1;
   6         if (i >= 0) {
   7             GotoFactory.getSharedInstance().getGoto().go(4);
   8         }
   9
  10         try {
  11             System.out.print("Hell");
  12             if (Math.random() > 0) throw new Exception();
  13             System.out.println("World!");
  14         } catch (Exception e) {
  15             System.out.print("o ");
  16             GotoFactory.getSharedInstance().getGoto().go(13);
  17         }
  18     }
  19 }

실행 :

$ java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo
   3
   2
   1
   0
   Hello World!

“사용하지 마십시오!”를 추가해야합니까?


답변

일부 주석가와 반대 투표자들은 이것이 goto 가 아니라고 주장하지만 , 아래 Java 문에서 생성 된 바이트 코드는 실제로 이러한 문이 goto 의미를 표현한다는 것을 실제로 암시합니다 .

특히 do {...} while(true);두 번째 예제의 루프는 루프 조건을 평가하지 않기 위해 Java 컴파일러에 의해 최적화됩니다.

앞으로 점프

label: {
  // do stuff
  if (check) break label;
  // do more stuff
}

바이트 코드에서 :

2  iload_1 [check]
3  ifeq 6          // Jumping forward
6  ..

뒤로 점프

label: do {
  // do stuff
  if (check) continue label;
  // do more stuff
  break label;
} while(true);

바이트 코드에서 :

 2  iload_1 [check]
 3  ifeq 9
 6  goto 2          // Jumping backward
 9  ..


답변

goto 문과 같은 것을 정말로 원한다면 항상 명명 된 블록으로 분리 할 수 ​​있습니다.

레이블로 분리하려면 블록 범위 내에 있어야합니다.

namedBlock: {
  if (j==2) {
    // this will take you to the label above
    break namedBlock;
  }
}

고토를 피해야하는 이유에 대해서는 설명하지 않겠습니다. 이미 그에 대한 답을 알고 있다고 가정합니다.


답변

public class TestLabel {

    enum Label{LABEL1, LABEL2, LABEL3, LABEL4}

    /**
     * @param args
     */
    public static void main(String[] args) {

        Label label = Label.LABEL1;

        while(true) {
            switch(label){
                case LABEL1:
                    print(label);

                case LABEL2:
                    print(label);
                    label = Label.LABEL4;
                    continue;

                case LABEL3:
                    print(label);
                    label = Label.LABEL1;
                    break;

                case LABEL4:
                    print(label);
                    label = Label.LABEL3;
                    continue;
            }
            break;
        }
    }

    public final static void print(Label label){
        System.out.println(label);
    }


답변

StephenC는 다음과 같이 씁니다.

고전적인 goto로 할 수있는 일을 할 수있는 두 가지 구조가 있습니다.

하나 더…

Matt Wolfe는 다음과 같이 씁니다.

사람들은 항상 goto를 사용하지 않는 것에 대해 이야기하지만, 꽤 잘 알려져 있고 사용되는 정말 좋은 실제 사용 사례가 있다고 생각합니다. 즉, 함수에서 반환하기 전에 일부 코드를 실행해야합니다. 일반적으로 릴리스 잠금 또는 그렇지 않은 것이지만 제 경우에는 필수 정리를 수행 할 수 있도록 반환 직전에 휴식을 취할 수 있기를 바랍니다.

try {
    // do stuff
    return result;  // or break, etc.
}
finally {
    // clean up before actually returning, even though the order looks wrong.
}

http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html

finally 블록은 try 블록이 종료 될 때 항상 실행됩니다. 이렇게하면 예기치 않은 예외가 발생하더라도 finally 블록이 실행됩니다. 그러나 마지막으로 예외 처리 이상의 용도로 유용합니다. 프로그래머가 반환, 계속 또는 중단으로 인해 실수로 정리 코드를 우회하는 것을 방지 할 수 있습니다. 정리 코드를 finally 블록에 넣는 것은 예외가 예상되지 않는 경우에도 항상 좋은 방법입니다.

finally와 관련된 어리석은 인터뷰 질문은 다음과 같습니다. try {} 블록에서 돌아 왔지만 finally {}에도 반환이있는 경우 어떤 값이 반환됩니까?