티스토리 뷰

반응형

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





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





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을 전달한다.(던진다) 아래 예제를 참고하자.


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에 구현한다. 


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를 제공한다. 아래 예제를 통해 확인해보자.


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을 사용할 수 있다.






-끝-







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





«   2022/06   »
      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
809,652
Today
23
Yesterday
129