1. try 구문 내에서 리턴에 도달했을 경우
try 내에서 리턴에 정상적으로 도달하였으므로, 리턴시킬 값을 임시 저장한 뒤 바로 finally 문을 최종 실행시키고 메소드를 종료합니다. 실제 리턴은 finally문이 종료된 이후에 실행됩니다. 이경우에는 try-catch-finally 이후에 지정된 리턴문이 있어도 무시됩니다.
2. try 구문 내에서 return에 도달하지 못하고 예외 발생했을 경우
이경우에는 catch-finally문이 작동한 뒤, 이후 코드를 계속 실행해 나가다가 리턴값을 만나면 리턴해줍니다. 따라서 예외 발생 시에 리턴시킬 값을 지정할 때는 try-catch-finally문 바깥에 리턴문을 작성해주면 됩니다. finally안에서 리턴시키는 것은 경고가 뜨는데, 이는 만약 try문에서 리턴값을 가진채로 finally로 넘어오면 두 리턴값이 충돌할 수 있기 때문입니다.
리턴시킬 값이 원시타입 변수라면 catch와 finally 문에서는 리턴될 값에 대해 관여할 수 없습니다. 리턴값을 임시 복사할 때 "값의 복사"가 일어나기 때문입니다. 원본을 리턴하는게 아니라 try문의 리턴값을 복사해두고 catch와 finally를 실행하기 때문에 이미 저장된 리턴값이 반환됩니다.
아래 예시 코드를 보시면 catch문과 finally문에서 a 변수의 값을 바꿔주고 있지만 리턴값은 try문에서 지정한 5가 되는 것을 확인할 수 있습니다. 물론 현재는 예외 발생이 없기 때문에 catch문은 실제로 작동하지는 않습니다.
package test;
public class Test {
public static void main(String[] args) {
Test t1 = new Test();
System.out.println(t1.test()); // 5
}
public int test() {
int a = 0;
try {
a = 5;
return a;
} catch(Exception e) {
e.printStackTrace();
a = 7;
} finally {
a = 10;
}
return 10000;
}
}
하지만 객체타입이라면 리턴될 객체의 "메모리 주소의 복사"가 일어나기 때문에 catch와 finally문에서 값에 관여할 수 있게 됩니다. 임시 저장된 리턴 객체의 "메모리 주소" 안에 들어 있는 값을 변경시키기 때문입니다. 객체는 최종 리턴되기 전까지 그 안의 값이 바뀌다가 최종적으로 10이 리턴됩니다. 역시 예외 발생 없는 코드라 catch문은 실제로 실행되지는 않습니다.
package test;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Test t1 = new Test();
// {10,2,30}
System.out.println(Arrays.toString(t1.test()));
}
public int[] test() {
int[] a = { 1, 2, 3 };
try {
a[0] = 10;
return a;
} catch (Exception e) {
e.printStackTrace();
a[1] = 20;
} finally {
a[2] = 30;
}
return new int[] { 3, 4, 5 };
}
}
관계없는 얘기지만 추가적으로 한가지를 더 살펴보면, String은 객체지만 아래 코드에서 try 구문에서 지정한 문자열이 리턴됩니다. 이유는 String의 값을 바꿀 때는 실제 메모리 주소 안에 값을 바꾸는게 아니라 새로운 문자열을 가진 String 생성 후 해당 메모리 주소로 변수값을 바꿔주기 때문입니다.
리턴시킬 객체를 임시 저장할 때는 "try"가 저장돼 있는 메모리 주소이고, finally문에서는 "finally" 문자열을 가진 메모리 주소를 반환하기 때문에 임시 저장된 "try" 문자열의 주소가 그대로 반환되게 됩니다. 이 구조에 대해서는 아래 글을 참조하시면 됩니다.
2019/12/09 - [· JAVA/- 기본상식] - Java의 메모리 구조_메소드의 매개변수 [3/3]
package test;
public class Test {
public static void main(String[] args) {
Test t1 = new Test();
System.out.println(t1.test()); // "try"
}
public String test() {
String a;
try {
a = "try";
return a;
} catch(Exception e) {
e.printStackTrace();
a = "catch";
} finally {
a = "finally";
}
return "마지막 리턴";
}
}
'▸JAVA > 기본 문법' 카테고리의 다른 글
콜백(Callback) 패턴을 사용한 비동기 방식의 원리와 사용법 (8) | 2020.02.07 |
---|---|
네트워크_NIO_논블로킹 채팅 서버/클라이언트 [3/3] (2) | 2020.02.06 |
네트워크_소켓(Socket) 통신_NIO 입출력(논블로킹) [2/3] (4) | 2020.02.04 |
네트워크_소켓(Socket) 통신_IO 입출력 [1/3] (2) | 2020.02.04 |
Thread (스레드)_스레드풀 [3/3] (2) | 2020.02.01 |
댓글