카테고리 없음

Exception 예외처리(try-catch, throw, throws)

백코딩 2023. 11. 21. 11:43
728x90

오류(Error) vs 예외(Exception)

 

오류(Error)는 시스템 비정상적인 상황이 생겼을 때 발생한다. 이는 시스템 레벨에서 발생하기 때문에 심각한 수준의 오류이다. 따라서 개발자가 미리 예측하여 처리할 수도 없기에 오류에 대한 처리는 신경쓰지 않는다.

 

예외(Exception)는 오류와 반대로, 비정상적인 상황이 예측하여 처리하는 것이다. 개발자는 자신이 구현한 로직에서 예외를 예측하고 그에 따른 예외처리를 신경써야 한다.

 

 

 

Checked Exception vs Unchecked Exception

 

Exception은 수많은 자식 클래스들이 있다. ComplieException(Checked Exception)과 RuntimeException(Unchecked Exception)을 구분할 필요가 있다.

 

1) Checked Exception

체크 예외는 예외를 잡아서 처리하거나(try ~ catch), 이게 안되면, 예외를 밖으로 던지는 throw 예외를 필수로 선언해야 한다.

그렇지 않으면 컴파일 오류가 발생한다.

 

- 장점 : 개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 문제를 잡아주는 훌륭한 안전 장치이다.

- 단점 : 하지만 실제로는 개발자가 모든 체크 예외를 반드시 잡거나 던지도록 처리해야 하기 때문에, 너무 번거로운 일이 된다. 크게 신경쓰고 싶지 않은 예외까지 모두 챙겨야 한다. 특히 의존관계가 생긴다.!

 

  • IOException : 파일, 소켓 등에 대한 읽기 또는 쓰기와 같이 잘못될 수 있는 입출력 작업에 대한 일반적인 예외
  • SQLException : 데이터베이스 관련 예외를 처리하는 데 사용
  • ClassNotFoundException : 일반적으로 Java의 리플렉션 메커니즘을 사용할 때 런타임에 클래스를 찾을 수 없을 때 발생

2) RuntimeException(Uncheckd Exception)

런타임 예외란 프로그래밍 소스코드를 작성하여 컴파일과정에서는 문제를 발견하지 못하고 정상적으로 컴파일이 진행되었으나, 프로그램을 실행중에 발생하는 오류사항들을 대체로 예외라고 정의한다. Unchecked Exception은 이 런타임 예외를 상속한다.

 

Unchecked Exception은 복구 불가능한 예외이다.

=> 예외 발생시 런타임 중지! 즉, 프로그램이 종료가 된다는 뜻이다.

 

Checkd Exception을 만나면 더 구체적인 Unchecked Exception을 발생시켜 정확한 정보를 전달하고 로직의 흐름을 끊는 것이 좋다.

Spring이나 JPA 등에서 SQLExeception을 처리하지 않는 이유도 적절한 RuntimeException으로 던져주고 있기 때문이다.

* NullPointerException : null 참조를 사용하여 객체의 메서드나 필드에 액세스하려고 하면 발생
* ArithmeticException : 산술 연산(예: 0으로 나누기)으로 인해 오류가 발생
* ArrayIndexOutOfBoundsException : 잘못된 인덱스가 있는 배열 요소에 액세스하려고 하면 발생
* IllegalArgumentException : 잘못된 인수가 메소드에 전달되면 발생
* InvalidFormatException : 데이터 형식이 유효하지 않은 상황에 직면하고 이 문제를 나타내기 위해 예외를 발생
* NumberFormatException : 문자열을 숫자로 변환하려고 시도했지만 형식이 유효하지 않은 경우 발생
...

 

Exception 처리

 

1) try~catch(finally) - 다른 작업 흐름으로 유도

2) throws  - 호출한 쪽 (부모)에게 예외 처리 위임하도록

3) throw - 명확한 의미의 예외로 바로 처리 -> 개발자들이 비즈니스 로직에서 처리하는 방식

 

1) try-catch

try{
	예외가 생길 가능성이 있는 코드 작성
} catch(예외발생 클래스명 e){
	예외처리 코드
}

 

마지막에 finally를 추가하거나 하는 방법이 있다.

public class HelloWorld {
    public static void main(String[] args){
        int n1, n2;

        n1 = 12;
        n2 = 0;

        try {
            System.out.println(n1/n2);
        } catch (Exception e){
            System.out.println("e.getMessage(): " + e.getMessage());
        }
    }
}
/Users/baegseungchan/Library/Java/JavaVirtualMachines/corretto-11.0.21/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=59031:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/baegseungchan/Desktop/Springboot/javapra/out/production/javapra HelloWorld
e.getMessage(): / by zero

Process finished with exit code 0


public class HelloWorld {
    public static void main(String[] args){
//        int n1, n2;

        int[] intArray = {0,1,2};
//        n1 = 12;
//        n2 = 0;

        try {
            //index 번호를 넘어선 에런
            System.out.println(intArray[3]);
        } catch (ArrayIndexOutOfBoundsException e){
            System.out.println("e.ArrayIndexOutOfBoundsException(): " + e.getMessage());
        } catch (ArithmeticException e) {
            // n1/n2 라면 발생했을 것
            System.out.println("ArithmeticException: " + e.getMessage());
        } finally {
            System.out.println("무조건 실행된다.");
        }
    }
}

 

이런식으로 작성해주면 finally의 구문은 무조건 실행된다.

 

 

2) throws는 자신을 호출하는 메소드에 예외처리의 책임을 떠넘기는 것이다.

- 기본적으로 체크 예외 전략이다.

- Uncheck(런타임)예외는 체크예외와 다르게 throws 예외 선언을 하지 않아도 된다. 예외를 잡지 않아도 자연스럽게 상위로 넘어가기 때문이다.

 


public class HelloWorld {
    public static void main(String[] args){
        int a1, a2;

        a1 = 12;
        a2 = 0;

        try {
            throwTest(a1, a2);
        } catch (ArithmeticException e){
            // n1/n2 라면 발생했을 것
            System.out.println("ArithmeticException  " + e.getMessage());
        }
    }

    public static void throwTest(int a, int b) throws ArithmeticException{
        System.out.println("throw a/b: "+ a/b);
    }
}

 

ArithmeticException예외가 발생하면 <이 메서드를 호출한 곳(main메서드)에서 예외처리를 넘겨주라는 뜻이다.

반드시 try-catch구문으로 메서드호출부분을 감싸줘야한다. 그렇지 않으면 예외처리를 하는 구문이 없으면 오류처리를 아무도 안하게 되는 것이다.! throws를 쓰면 그 호출한 메서드에서 try~catch 구문을 해줘야되는 것을 잊으면 안된다!

 

 

3) throw

throw는 개발자 직접 예외를 발생시키고 싶을 때 쓰는 것이다.

주로 RuntimeException(UncheckedException) 처리를 위해 쓰는 방식이다.

throw라는 키워드를 이용하며, 주로 비즈니스 로직을 구현하는 과정 중 컴파일에는 문제가 없지만 해당 비지니스 로직이 개발자가 의도한 대로 통과하지 못했을 경우 고의로 예외를 발생시켜야 할 때 사용합니다.

 


public class HelloWorld {
    public static void main(String[] args){
        int a, b;

        a = 12;
        b = 5;
        try {
            devide(a, b);
        } catch (ArithmeticException e){
            e.printStackTrace();
        }
    }

    public static void devide(int a, int b) throws ArithmeticException {
        if(b == 0){
            throw new ArithmeticException("0으로 나눌 수 없습니다.");
        }
        System.out.println(a / b);
    }

}

 

throw를 사용하는 이유는 예외가 발생할 수 있는 코드가 있다는 것을 인지시키고 예외처리를 가용하며, 여러 가지 발생 가능한 예외들을 호출할 메서드에서 한 번에 처리할 수 있게 하여 관리를 용이하게 해 줄 수 있다.

 

throw는 강제로 예외를 발생시키는 것이며 개발자의 판단에 따른 처리가 가능합니다. throws는 자신을 호출한 메서드에게 책임을 전가하여 호출한 메서드에서 예외처리르 하도록 강요합니다.

728x90