Programing Language/Java

[Java] 예외 처리(Exception Handling)

vinedpillar 2022. 7. 13. 21:17

예외 처리(Exception Handling)

  • 에러가 발생했을 때 프로그램의 갑작스러운 종료를 막고 실행 상태가 유지될 수 있도록 처리하는 것을 예외 처리라고 합니다.

  • 예외는 예외 처리문을 사용하여 처리합니다.

  • 예외 처리문은 try~catch~finally 로 구성되며, try 내의 작성한 코드가 예외를 발생하면 catch에 지정한 예외 클래스로 보내는 역할을 합니다.
  •  
  • 예외 처리문은 컨스트럭터 내부나 메서드 내부에서 작성됩니다.
예외 처리를 위한 try~catch~finally 구문 사용 방법

try {

    예외가 발생할 가능성이 있는 코드 입력

}
catch(예외클래스 e) {

    발생한 예외에 대한 처리 코드 작성 위치
    catch 블럭은 여러 개가 올 수 있음

}
finally {

    항상 실행되어야 하는 코드 입력 위치
    필요에 따라 생략 가능

}

 

  • try 블록에서 작성한 코드가 예외없이 정상 실행 된다면, catch 블록은 실행되지 않고 finally 블록이 실행됩니다.

  • 그러나 try 블록에서 예외가 발생한다면 catch 블록이 실행되고 finally 블록이 실행됩니다.
  • catch 블록에서 예외 정보를 출력하는 메서드는 대표적으로 아래 방법이 있습니다.
    • e.getMessage(): 예외가 발생한 이유를 반환
    • e.toString(): 예외의 종류와 발생한 이유를 반환
    • e.printStackTrace(): 예외가 어디에서 발생했는지 추적한 내용을 반환
  • 예외 발생 여부와 상관 없이 finally 블록은 항상 실행됩니다.

  • 예외 처리 구문 문법 상 finally 부분은 생략이 가능합니다.

예외 처리문 활용 예시

// 예외 처리를 하지 않았을 경우
public class ExceptionHandlingExample1 {
    public static void printLength(String data) {
    	int result = data.length();
        System.out.println("문자 수: " + result);
    }

    public static void main(String[] args) {
    	System.out.println("프로그램 시작");
        
        printLength("somthingword");
        // 아래 코드는 참조 변수 값이 없기 때문에 실행되지 못하고 에러를 발생
        // nullpointerException 발생 및 프로그램 중단
        printLength(null);
        
        System.out.println("프로그램 종료");
    }
}


// 예외 처리를 할 경우
public class ExceptionHandlingExample2 {
    public static void printLength(String data) {
    	try {
            int result = data.length();
            System.out.println("문자 수: " + result);
        }
        catch(NullpointException e) {
            // 예외의 정보를 얻는 3가지 방법
            System.out,.println(e.getMessage());
            // System.out.println(e.toString());
            // e.printStackTrace();
        }
        finally {
            System.out.println("프로그램 마무리");
        }
    }
    
    public static void main(String[] args) {
    	System.out.println("프로그램 시작");
        
        printLength("somthingword");
        // 예외를 처리했기 때문에 에러가 발생해도 프로그램 계속 실행
        printLength(null);
        
        System.out.println("프로그램 종료");
    }
}

 

 

 

 

예외 종류에 따른 처리

  • try 블럭에서 작성되는 코드에서는 여러 예외가 발생할 수 있습니다.

  • 이 경우 다중 catch를 사용하면 발생 하는 예외 종류에 따라서 적절하게 발생한 예외를 처리할 수 있습니다.

  • 하지만 try 블록에서 여러 예외가 발생할 수 있더라도 한 예외가 발생하면 즉시 실행을 멈추고 catch 블럭으로 이동하기 때문에 catch문의 수가 많아도 실행은 한 블록만 실행됩니다.

  • 만약 여러 개의 catch 블록이 필요하고, 처리해야할 예외 클래스들이 상속 관계에 있다면 하위 예외 클래스를 먼저(위쪽) 작성하고, 상위 예외 클래스를 나중에(아래쪽) 작성해야 합니다.

  • 예외가 발생하면 catch 블록은 위에서부터 차례대로 검사하기 때문에 하위 예외 클래스도 상위 예외 클래스 타입이기 때문에 의도한 대로 예외 처리가 되지 않을 수 있습니다.

다중 catch 사용 예시

public class ExceptionHandlingExample {
    public static void main(String[] args) {
    	String[] array = {"100", "1OO"};
        
        for(int i = 0; i < array.length; i++) {
        	try {
            	int value = Integer.parseInt(array[i]);
                System.out.println("array[" + i + "]: " + value);
            }
            catch(ArrayIndexOutOfBoundsException e) {
            	System.out.println("배열 인덱스가 초과됨: " + e.getMessage());
            }
            catch(NumberFormatException e) {
            	System.out.println("숫자로 변환할 수 없음: " + e.getMessage());
            }
        }
    }
}

 

 

 

 

리소스 자동 닫기

  • 리소스란 데이터를 제공하는 객체를 뜻 하는데, 자바 프로그램에서 특정 정보를 처리하기 위해 다른 파일(리소스)의 데이터를 가져올 수 있습니다. 

  • 리소스는 사용하기 위해 열어야(open)하고, 사용이 끝날 후에는 닫아야(close) 합니다.
    (리소스를 열어야 내용을 읽을 수 있고, 리소스를 닫아야 다른 프로그램에서 사용할 수 있음)

  • 리소스를 사용하다가 예외가 발생할 경우 리소스가 불안정한 상태가 되기 때문에 안전하게 닫는 것이 중요합니다.

  • 이 경우 try~with~resource 구문을 사용하면 예외 발생여부와 관계없이 리소스를 자동으로 닫아줍니다.
  • try~with~resource 구문은 try 블록에 리소스를 여는 코드를 작성했을 때 무사히 실행이 완료되거나 예외가 발생하면 자동으로 리소스를 닫아주는 메서드를 호출해줍니다.

  • 다만 이러한 기능을 원할하게 쓰기 위해서는 자바 기본 라이브러리 중 java.lang.AutoCloseable에 선언된 인터페이스를 구현하여 close() 메서드를 재정의하여야 합니다.

  • 만약 구문 안에서 복수개의 리소스를 사용해야 한다면 파일을 여는 코드를 각각 세미콜론(;)으로 구분합니다.

  • 자바8 버전 이전에는 try 블록 안에 리소스 변수를 선언해야 했지만 자바9 버전 이후부터는 외부 리소스 변수를 활용할 수 있습니다. 

리소스 자동 닫기 사용 예시

// 예외 처리 클래스
// close() 메서드를 구현하기 위해 AutoClosealbe을 구현
public class MyResourse implements AutoCloseable {
    private String name;
    
    public MyResourse(String name) {
    	this.name = name;
        System.out.println("MyResourse(" + name + ") 열기");
    }
    
    public String read1() {
    	System.out.println("MyResourse(" + name + ") 열기");
        return "100";
    }
    
    public String read2() {
    	System.out.println("MyResourse(" + name + ") 열기");
        return "abc"
    }
    
    public void close() throws Exception {
    	System.out.println("MyResourse(" + name + ") 닫기");
    }
}

// 실행 클래스
public class TryWithResourseExample {
    public static void main(String[] args) {
    	try(MyResourse rsc = new MyResource("A")) {
            String data = rsc.read1();
            int value = Integer.parseInt(data);
        }
        catch(Exception e) {
            System.out.println("예외 처리: " + e.getMessage());
        }
        
        System.out.println("------------");
        
        try(MyResourse rsc = new MyResource("A")) {
            String data = rsc.read2();
            int value = Integer.parseInt(data);
        }
        catch(Exception e) {
            System.out.println("예외 처리: " + e.getMessage());
        }
        
        System.out.println("------------");
    	
        MyResource rsc1 = new MyResource("A");
        MyResource rsc2 = new MyResource("B");
        
        // 멀티 리소스를 try 구문에서 동시에 삽입
        try(rsc1; rsc2) {
            String data1 = rsc1.read1();
            String data2 = rsc2.read1();
        }
        catch(Exception e) {
            System.out.println("예외 처리: " + e.getMessage());
        }
    }
}