>  기사  >  Java  >  Java에서 try, finally 및 return 문의 실행 순서

Java에서 try, finally 및 return 문의 실행 순서

黄舟
黄舟원래의
2017-08-23 10:19:432306검색

이 글은 주로 Java의 try finally return 문의 실행 순서에 대한 간략한 분석을 소개합니다. 필요하신 분들은 참고하시면 됩니다.

문제 분석

finally 문 블록이 실행될까요?

아마도 많은 분들의 첫 반응은 '꼭 시행하겠다' 겠지만, 잘 생각해보면 꼭 시행하겠다고 하면 그런 SB에게 묻지 않을 것입니다.

Demo1


public class Test {
  public static void main(String[] args) {
    System.out.println("return value of test(): " + test());
  }
  public static int test() {
    int i = 1;
    // if (i == 1) {
    // return 0;
    // }
    System.out.println("the previous statement of try block");
    i = i / 0;
    try {
      System.out.println("try block");
      return i;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo1의 실행 결과는 다음과 같습니다.


the previous statement of try block
Exception in thread "main" java.lang.ArithmeticException: / by zero
  at com.becoda.bkms.bus.basics.web.Test2.test(Test2.java:15)
  at com.becoda.bkms.bus.basics.web.Test2.main(Test2.java:5)

또한 위 예제의 주석을 제거하면 실행 결과는


return value of test(): 0

위의 두 가지 상황에서 finally 문 블록이 실행되지 않는데 무엇이 문제인가요? finally 문 블록은 finally 문 블록에 해당하는 try 문 블록이 실행될 때만 실행됩니다. 그러나 위의 모든 반환(return) 또는 try 문 블록 이전에 예외를 발생시키므로 try에 해당하는 finally 문 블록이 실행됩니다. 문이 실행되지 않습니다. 그렇다면 finally에 해당하는 try 문 블록이 실행되더라도 finally 문 블록은 반드시 실행될까요? 그런데 다음 예제

Demo2


public class Test {
  public static void main(String[] args) {
    System.out.println("return value of test(): " + test());
  }
  public static int test() {
    int i = 1;
    try {
      System.out.println("try block");
      System.exit(0);
      return i;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo2의 실행 결과는 다음과 같습니다.


try block

finally 문 블록이 여전히 실행되지 않는 이유는 무엇입니까? 일반적으로 이 작업을 수행하지는 않지만 Java 가상 머신의 실행을 종료하는 try 문 블록에서 System.exit(0) 문을 실행했기 때문입니다. try 문 블록이나 catch 문 블록을 실행하는 도중 스레드가 중단(interrupted)되거나 종료(kill)되는 경우 해당 finally 문 블록이 실행되지 않는 상황도 있습니다. 더 극단적인 상황도 있습니다. 즉, 스레드가 try 문 블록이나 catch 문 블록을 실행 중일 때 갑자기 충돌이 발생하거나 전원이 꺼지고 finally 문 블록이 실행되지 않는 경우입니다.

최종 문장 예시 설명

아래의 간단한 예시를 보세요

Demo3


public class Test {
  public static void main(String[] args) {
    try {
      System.out.println("try block");
      return;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo3의 실행 결과는 다음과 같습니다.

Demo3에서는 finally 문이 다음과 같이 설명됩니다. 블록은 명령문 블록의 return 문 이전에 실행 시도 중입니다. 또 다른 예를 살펴보겠습니다.


Demo4

try block
finally block

Demo4의 실행 결과는 다음과 같습니다.


public class Test {
  public static void main(String[] args) {
    System.out.println("reture value of test() : " + test());
  }
  public static int test() {
    int i = 1;
    try {
      System.out.println("try block");
      i = 1 / 0;
      return 1;
    } catch (Exception e) {
      System.out.println("exception block");
      return 2;
    } finally {
      System.out.println("finally block");
    }
  }
}

Demo4는 finally 문 블록이 catch 문 블록의 return 문 이전에 실행되는 것을 보여줍니다.


위의 Demo3 및 Demo4를 보면 실제로 try 또는 catch에서 return 문 이전에 finally 문 블록이 실행되는 것을 볼 수 있습니다. 보다 일반적으로 finally 문 블록은 제어 전달 문 이전에 실행되어야 합니다. transfer 문에는 break와 continue도 포함됩니다.

다음 두 가지 예를 보세요

Demo5

try block
exception block
finally block
reture value of test() : 2

Demo5의 실행 결과는 다음과 같습니다.


getValue()의 반환 값: 1

Demo6

르리이

Demo6의 실행 결과는 다음과 같습니다.


public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  public static int getValue() {
    try {
      return 0;
    } finally {
      return 1;
    }
  }
}

위 분석에서 도출한 결론을 사용하면 try 또는 catch에서 return 문 이전에 finally 문 블록이 실행됩니다. 이를 통해 Demo5의 실행 결과가 1이라는 것을 쉽게 이해할 수 있습니다. finally의 return 1; 문은 try의 return 0; 문보다 먼저 실행되므로 finally의 return 1; 문이 실행된 후에는 프로그램의 제어가 호출자 main() 함수로 전달되고 값은 다음과 같습니다. 1. 그러면 Demo6의 반환 값이 2가 아닌 1인 이유는 무엇입니까? Demo5의 분석 로직에 따르면, try?에서 return i 전에 finally의 i++; 문이 실행되어야 합니다. i의 초기 값은 1이고, i++를 실행하면 2가 되며, return i를 실행하면 2가 되어야 하지 않나요? 어떻게 1이 되었나요?


이 문제를 설명하려면 Java 가상 머신이 finally 문 블록을 컴파일하는 방법을 이해해야 합니다.

Java 메소드는 스택 프레임에서 실행됩니다. 스택 프레임은 메소드를 실행하는 스레드가 메소드 실행 시 메모리 공간으로 각 메소드에 작은 공간을 할당합니다. 세 가지 영역으로 구분:

1. 실행 중인 표현식의 피연산자를 저장하는 데 사용되는 피연산자 스택

2. 메소드 매개변수, 메소드 내부에 선언된 변수를 포함하여 메소드에 사용되는 변수를 저장하는 데 사용되는 지역 변수 영역 메소드에 사용된 객체의 멤버 변수나 클래스의 멤버 변수(정적 변수) 중 마지막 두 변수는 로컬 변수 영역에 복사되므로 멀티 스레드 환경에서는 이러한 변수를 다음과 같이 선언해야 합니다. 필요에 따라 휘발성 유형

3, 바이트코드 명령 영역

예를 들어 다음 코드

public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  public static int getValue() {
    int i = 1;
    try {
      return i;
    } finally {
      i++;
    }
  }
}

우선 finally 문은 반드시 실행될 것이라는 것을 알고 있는데 실행 순서는 어떻게 되나요? 실행 순서는 다음과 같습니다.


1. 실행: 표현식, 표현식 계산 및 결과를 피연산자 스택 상단에 저장합니다.

2. 실행: 피연산자 스택의 최상위 값을 복사합니다. 반환 값으로 지역 변수 영역에

3、执行:finally语句块中的代码;

4、执行:将第2步复制到局部变量区的返回值又复制回操作数栈顶;

5、执行:return指令,返回操作数栈顶的值;

我们可以看到,在第一步执行完毕后,整个方法的返回值就已经确定了,由于还要执行finally代码块,因此程序会将返回值暂存在局部变量区,腾出操作数栈用来执行finally语句块中代码,等finally执行完毕,再将暂存的返回值又复制回操作数栈顶。所以无论finally语句块中执行了什么操作,都无法影响返回值,所以试图在finally语句块中修改返回值是徒劳的。因此,finally语句块设计出来的目的只是为了让方法执行一些重要的收尾工作,而不是用来计算返回值的。

这样就能解释Demo6的问题了

让我们再来看以下 3 个例子。

Demo7


public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  @SuppressWarnings("finally")
  public static int getValue() {
    int i = 1;
    try {
      i = 4;
    } finally {
      i++;
      return i;
    }
  }
}

Demo7的执行结果为:


return value of getValue(): 5

Demo8


public class Test {
  public static void main(String[] args) {
    System.out.println("return value of getValue(): " + getValue());
  }
  public static int getValue() {
    int i = 1;
    try {
      i = 4;
    } finally {
      i++;
    }
    return i;
  }
}

Demo8的执行结果为:


return value of getValue(): 5

Demo9


public class Test {
  public static void main(String[] args) {
    System.out.println(test());
  }
  public static String test() {
    try {
      System.out.println("try block");
      return test1();
    } finally {
      System.out.println("finally block");
    }
  }
  public static String test1() {
    System.out.println("return statement");
    return "after return";
  }
}

Demo9的执行结果为:


try block
return statement
finally block
after return

总结:

1、finally 语句块不一定会被执行

2、finally 语句块在 try 语句块中的 return 语句之前执行

3、finally 语句块在 catch 语句块中的 return 语句之前执行

4、finally 语句块中的 return 语句会覆盖 try 块中的 return 返回

5、试图在 finally 语句块中修改返回值不一定会被改变

위 내용은 Java에서 try, finally 및 return 문의 실행 순서의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.