티스토리 뷰

반응형

 컴파일할 때는 문제가 없던 프로그램도 동작 도중에 종종 오류가 발생한다. 사용자가 항상 개발자의 생각대로 프로그램을 사용하지 않기 때문이다. 숫자만 입력해야하지만 문자열을 입력하기도 하고, 파일을 업로드하기 전 파일의 이름을 지정하지 않기도 한다.





 이럴 때 발생하는 오류를 사전에 방지하는 것은 중요하다. 그런데 개발자가 이러한 오류가 발생할 때마다 프로그램이 종료되는 것을 원치 않을 수 있다. 오류를 무시하고 싶을 수도 있고, 그 오류가 발생 했을 때 수행할 적절한 동작을 직접 정의하고 싶을 수도 있다. 이럴 때 활용하는 것이 try-catch-finally 구문이다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main {
  
    public static void main(String[] args) {
  
        int [] arr = new int [3];
        try{
  
            System.out.println(arr[3]);
            System.out.println(arr[2]);
        } catch (ArrayIndexOutOfBoundsException e) {
  
            System.out.println("오류 발생!");
        } finally {
  
            System.out.println("finally...");
        }
    }
}


 위의 예제를 살펴보자 크기가 3인 int 배열을 선언했는데, index 3에 접근을 시도했다. 이 경우, JVM은 ArrayIndexOutOfBoundsException을 발생할 것이다. catch의 역할은 지정한 오류(Exception)이 발생할 경우의 동작을 정의할 수 있도록 도와준다. finally는 try와 catch구문이 끝났을 때 할 동작을 정의할 수 있는 키워드이다. 즉, 위 소스코드의 동작 결과는 아래와 같다.


1
2
오류 발생!
finally...
cs


 한편, 이러한 try-catch-finally block을 오류가 발생할 만한 모든 구역에 각각 구현하는 것은 조금 번거로운 작업이다. 그래서 throws라는 예약어를 사용하기도 한다. throw는 해당 메소드를 호출한 곳으로 발생한 Exception을 전달한다.(던진다) 아래 예제를 참고하자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Main {
  
    public static void main(String[] args) {
  
        int [] arr = new int [3];
        try {
  
            customFunction(arr);
        } catch (ArrayIndexOutOfBoundsException e) {
  
            System.out.println("Exception 발생!");
        }
    }
  
    public static void customFunction (int [] arr) throws ArrayIndexOutOfBoundsException {
  
        System.out.println("함수 호출!");
        System.out.println(arr[5]);
    }
}


 18번째 줄에서 Exception이 발생했으나, try-catch block 대신, throws를 활용하여 main 메소드에 Exception을 전달했다. 그리고 main 함수에서 예외처리를 진행한다. 이를 활용하면 여러 메소드에서 발생할 수 있는 Exception을 한군데에서 처리할 수 있다. 위 소스코드의 실행 결과는 아래와 같다.


1
2
함수 호출!
Exception 발생!
cs




 try block에서 자원을 할당하는 로직이 있을 경우, Exception이 발생했을 때 자원이 제대로 해제되지 않을 수 있다. catch block 내부에 자원 해제를 구현하는 방법도 있지만,  finally block은 try와 catch의 결과에 상관없이 무조건 실행하는 부분이므로 자원의 해제 로직을 주로 finally에 구현한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Main {
  
    public static void main(String[] args) {
  
        InputStream is = null;
        OutputStream os = null;
         
        try {
  
            is = new FileInputStream("fileName");
            os = new FileOutputStream("fileName");
        } catch (FileNotFoundException e) {
  
            System.out.println("파일이 없어서 Exception 발생!");
        } finally {
  
            try {
  
                is.close();
                os.close();
            } catch (IOException e) {
  
                System.out.println("자원 해제 도중 Exception 발생");
            }
             
        }
    }
}


 위 예제를 살펴보자. 각각 InputStream과 OutputStream 변수에 자원을 할당받았다. 그리고 finally 구문을 통해 안정적으로 해제하고 있는데, 자원 해제에도 예외처리가 필요하여 try-catch 구문을 또 사용하였다. 이렇게보니 조금 번거로워 보인다. 다행히도 JAVA7부터 try-with-resources를 제공한다. 아래 예제를 통해 확인해보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
  
    public static void main(String[] args) {
  
        try(InputStream is = new FileInputStream("fileName");
            OutputStream os = new FileOutputStream("fileName")) {
  
        } catch (IOException e) {
  
            System.out.println("Exception 발생!");
        }
    }
}


 try문을 시작할 때 자원을 할당한 것은 비슷하지만, 자원을 해제하는 finally block이 빠진 것을 확인할 수 있다. try-with-resources를 활용하면 할당된 자원을 Exception 발생시에 자동으로 해제할 수 있다. 그래서 JAVA7 이상을 사용한다면 보다 편리하게 try-catch block을 사용할 수 있다.






-끝-







아래의 '공감' 버튼 클릭은 포스팅에 큰 힘이 됩니다.^^





반응형
최근에 올라온 글
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함
Total
Today
Yesterday