finally 블록에서 반환 된 변수를 변경해도 반환 값이 변경되지 않는 이유는 무엇입니까?
아래와 같이 간단한 Java 클래스가 있습니다.
public class Test {
private String s;
public String foo() {
try {
s = "dev";
return s;
}
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
}
}
이 코드의 출력은 다음과 같습니다.
Entry in finally Block
dev
블록 s
에서 재정의되지 않고 finally
인쇄 출력을 제어 하는 이유는 무엇 입니까?
try
의 실행으로 완료 블록 return
문과 값 s
상기 시점에서 return
문이 실행은 메소드에 의해 리턴 된 값이다. 이 finally
절이 나중에 s
( return
명령문이 완료된 후) 값을 변경 한다는 사실 은 그 시점에서 리턴 값을 변경하지 않습니다.
위의 내용 은 참조 하는 객체가 아니라 블록 s
자체 의 값 변경을 처리합니다 . 경우 변경 가능한 객체에 대한 참조가 있었다 (이 아니다)하고 콘텐츠 오브젝트가 변경되었다 블록 다음 그 변경은 리턴 값을 보일 것이다.finally
s
s
String
finally
이 모든 작동 방식에 대한 자세한 규칙 은 Java 언어 사양의 14.20.2 섹션에 나와 있습니다. return
명령문의 실행은 try
블록 의 갑작스러운 종료로 계산됩니다 ( " try 블록의 실행이 다른 이유로 갑자기 완료 되는 경우 R .... "이 적용되는 섹션 ). 명령문이 갑작스러운 블록 종료 인 이유 는 JLS 14.17 섹션을 참조하십시오 return
.
더 자세하게 말하면, 진술로 인해 문장 의 try
블록과 finally
블록이 try-finally
갑자기 종료되면 return
§14.20.2의 다음 규칙이 적용됩니다.
try
R이 [예외를 던지는 것 외에] 다른 이유로 갑자기 블록의 실행이 완료되면finally
블록이 실행 된 다음 선택 사항이 있습니다.
- 은 if
finally
블록은 다음, 정상적으로 완료try
이유 R.위한 문이 완료 갑자기- 상기 중간
finally
블록이 이유에 대해 S 급격 완료 후try
갑자기 이유 S에 대한 문이 완료 (이성 R은 폐기된다).
결과적으로 블록 의 return
명령문 finally
이 전체 try-finally
명령문 의 리턴 값을 결정 하고 블록의 리턴 된 값 try
이 삭제됩니다. 비슷한 일이 발생 try-catch-finally
경우 문 try
블록, 그것이 의해 잡힌 예외가 발생 catch
블록을, 그리고 두 catch
블록과 finally
블록이 return
문을.
마지막으로 호출하기 전에 반환 값이 스택에 배치되기 때문입니다.
바이트 코드를 살펴보면 JDK가 크게 최적화되었으며 foo () 메서드가 다음과 같이 나타납니다.
String tmp = null;
try {
s = "dev"
tmp = s;
s = "override variable s";
return tmp;
} catch (RuntimeException e){
s = "override variable s";
throw e;
}
그리고 바이트 코드 :
0: ldc #7; //loading String "dev"
2: putstatic #8; //storing it to a static variable
5: getstatic #8; //loading "dev" from a static variable
8: astore_0 //storing "dev" to a temp variable
9: ldc #9; //loading String "override variable s"
11: putstatic #8; //setting a static variable
14: aload_0 //loading a temp avariable
15: areturn //returning it
16: astore_1
17: ldc #9; //loading String "override variable s"
19: putstatic #8; //setting a static variable
22: aload_1
23: athrow
Java는 리턴하기 전에 "dev"문자열이 변경되지 않도록 보존했습니다. 실제로 여기에는 마침내 막히지 않습니다.
여기에 주목할만한 두 가지가 있습니다.
- Strings are immutable. When you set s to "override variable s", you set s to refer to the inlined String, not altering the inherent char buffer of the s object to change to "override variable s".
- You put a reference to the s on the stack to return to the calling code. Afterwards (when the finally block runs), altering the reference should not do anything for the return value already on the stack.
I change your code a bit to prove the point of Ted.
As you can see in the output s
is indeed changed but after the return.
public class Test {
public String s;
public String foo() {
try {
s = "dev";
return s;
} finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
System.out.println(obj.s);
}
}
Output:
Entry in finally Block
dev
override variable s
Technically speaking, the return
in the try block won't be ignored if a finally
block is defined, only if that finally block also includes a return
.
It's a dubious design decision that was probably a mistake in retrospect (much like references being nullable/mutable by default, and, according to some, checked exceptions). In many ways this behaviour is exactly consistent with the colloquial understanding of what finally
means - "no matter what happens beforehand in the try
block, always run this code." Hence if you return true from a finally
block, the overall effect must always to be to return s
, no?
In general, this is seldom a good idiom, and you should use finally
blocks liberally for cleaning up/closing resources but rarely if ever return a value from them.
Try this: If you want to print the override value of s.
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
return s;
}
'development' 카테고리의 다른 글
Javascript를 사용하여 DOM 요소를 대체하는 방법은 무엇입니까? (0) | 2020.06.15 |
---|---|
키로 사전 값을 얻습니다 (0) | 2020.06.15 |
Java 메소드 순서 규칙이 있습니까? (0) | 2020.06.15 |
matplotlib의 산점도에서 각 계열에 대해 다른 색상 설정 (0) | 2020.06.15 |
C #의 콤보 상자에서 요소 편집을 비활성화하는 방법은 무엇입니까? (0) | 2020.06.15 |