-
Java의 ExceptionJava/이론&문법 2023. 9. 15. 02:31
예외란?
- An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions (Oracle Docs)
- 예외란 프로그램의 실행동안 발생되는 것으로, 프로그램 명령어들의 정상적인 흐름을 방해하는 것을 의미합니다.
Try - Catch - Finally
- 예외가 발생한 경우
- try 내에서 발생한 이후의 문장들은 실행되지 않음
- catch 내에 있는 문장은 실행되고, try-catch 문 이후의 내용이 실행
- 예외가 발생하지 않은 경우
- try 문이 쭉 실행되고, catch 내에 있는 문장은 실행되지 않음.
- finally는 예외 발생 여부와 상관없이 실행되는 문장이다.
- try 블록 내에서 선언한 변수는 try 블록 내에서만 사용이 가능하다.
Catch 블록은 순서를 따진다.
- Exception이 예외의 가장 최상위인 만큼, 마지막 catch 블록에 넣어주어야 한다.
- 아래 코드는 NullPointerException을 발생시킨다.
public static void main(String[] args) { int[] arr = new int[5]; try { arr = null; System.out.println(arr[2]); } catch (NullPointerException e) { System.out.println("NullPointerException"); } catch (Exception e) { System.out.println("ERROR"); } }
- 만약 아래처럼 순서를 바꾸면 어떨까?
public static void main(String[] args) { int[] arr = new int[5]; try { arr = null; System.out.println(arr[2]); } catch (Exception e) { System.out.println("ArrayIndexOutOfBounds"); } catch (NullPointerException e) { System.out.println("NullPointerException"); } }
- try문 다음에 오는 catch 블록은 1개 이상 올 수 있으며, 먼저 선언한 catch 블록의 예외 클래스가 다음에 선언된 catch 블록 예외의 부모라면, 자식에 속하는 catch는 실행될 일이 없으므로 컴파일이 되지 않는다.
- Exception 클래스가 모든 예외의 부모이므로 발생하는 현상.
- 하나의 try 블록에서 예외가 발생하면 그 예외와 관련이 있는 catch 블록을 찾아서 실행한다.
- 발생한 예외와 관련있는 catch 블록이 없다면, 예외가 발생되고 끝나므로 마지막에 Exception 으로 묶어주는 습관을 들일 것.
예외의 종류
Error
- 자바 프로그램 밖에서 발생한 예외
- Exception 클래스와의 가장 큰 차이는 프로그램 안에서 발생했는지, 밖에서 발생했는 지의 여부이다.
- 또한 프로그램이 멈추어 버리는(프로세스에 영향을 주는) 것이 Error이다.
- Exception 클래스는 에러가 아니며, Exception은 스레드에만 영향을 주어 계속 실행이 가능하다.
Runtime Exception ( == Unchecked Exception )
- 예외가 발생할 것을 미리 감지하지 못했을 때 발생
- Runtime Exception을 확장한 예외들이다.
- 컴파일 시에 체크하지 않기 때문에 unchecked Exception이라고도 부르는 것
Checked Exception
- Exception 클래스의 하위 클래스 중 Runtime Exception을 제외한 나머지
- 컴파일러가 예외 처리를 확인한다. (컴파일 단계에서 잡힌다)
- 반드시 예외 처리가 되어야 한다.
- ex) IO의 경우, 무조건 throws IOException 을 main에 달아줘야 하는 등..
Throwable
- 위 그림에서 보면 알 수 있듯, Exception과 Error의 공통 부모 클래스들은 Throwable이다.
- 즉, Exception, Error 모두 상위 클래스인 Throwable로 처리가 가능하다!
- Exception, Error의 성격은 다르지만, 동일한 이름의 메소드를 사용하여 처리할 수 있도록 하기 위함이다.
- Throwable의 생성자는 아래와 같다.
public Throwable() { fillInStackTrace(); } public Throwable(String message) { fillInStackTrace(); detailMessage = message; } public Throwable(String message, Throwable cause) { fillInStackTrace(); detailMessage = message; this.cause = cause; } public Throwable(Throwable cause) { fillInStackTrace(); detailMessage = (cause==null ? null : cause.toString()); this.cause = cause; }
- Throwable 내부에 작성된 메소드 (이것보다 더 많지만 일부만 발췌)
public String getMessage() // 예외 메시지를 String 형태로 제공받음 public String toString() // getMessage보다 더 자세한 형태의 메시지(예외클래스 이름까지) public synchronized Throwable fillInStackTrace() // 코드 내부에서 private native Throwable fillInStackTrace(int dummy) 호출 public void setStackTrace(StackTraceElement[] stackTrace) public void printStackTrace(PrintWriter s) // 메소드들의 호출관계 출력
Throws Exception
- try 문 안에서 throw new Exception ~ 을 통해 예외를 발생시킨다.
- 개발자가 예외 클래스의 객체를 생성, try 문 이후는 실행되지 않고 catch 문으로 넘어간다.
- catch 블록에서 해당하는 예외가 있다면 (동일하거나, 상속 관계에 있는 예외가 있다면) 해당 catch 블록에서 처리
- catch 블록에서 해당하는 예외가 없다면 메소드 밖으로 예외를 던진다. (예외가 발생한 메소드를 호출한 메소드로 처리를 위임)
- 대신, 이 예외가 발생한 메소드가 메소드 밖으로 예외를 던진다면, 걔를 호출한 메소드가 try-catch로 묶어서 처리 해 줘야 한다.
- 예시코드
- throwsException 은 자기를 호출한 main에 예외 처리를 위임
- main(예외발생 메소드를 호출한 메소드) 메소드는 try-catch로 감싸서 이 예외를 처리한다. (안 그러면 컴파일 안됨)
public static void main(String[] args) { try { // ... throwsException(13); } catch (Exception e) { // ... } } public void throwsException(int num) throws Exception { if (num > 12) { throw new Exception("~~~"); } }
Throwable 또는 Exception 상속 받아 예외를 직접 만들수도 있다.
- 예시 코드
public class MyException extends Exception { public MyException() { super(); } public MyException(String Message) { super(message); } } // 실제 사용한다면 public void throwMyException() throws MyException { try { if (num > 12) { throw new MyException("Number is Over"); } } catch (MyException e) { e.printStackTrace(); } }
- 추가적인 예외 처리 전략
- 임의의 예외 클래스를 위처럼 만든다면, try-catch로 묶어줄 필요가 있을 때만 Exception 클래스를 확장한다.
- Runtime Exception은 해당 메소드를 호출하는 애만 try-catch로 잡고, 메소드 자체는 try-catch 안 사용해도 된다.
- 일반적으로 실행 시 예외를 처리할 수 있는 경우에는 RuntimeException 클래스를 확장하는 것을 권장한다.
- catch문 내에는 꼭 로그 처리와 같은 예외 처리를 해줄 것(예외 분석이 어려워지지 않도록)
- 임의의 예외 클래스를 위처럼 만든다면, try-catch로 묶어줄 필요가 있을 때만 Exception 클래스를 확장한다.
기타 참고 자료
더보기자바의 신 1권 14장
Oracle Docs
'Java > 이론&문법' 카테고리의 다른 글
Annotation (0) 2023.09.15 Nested Class (0) 2023.09.15 Interface, abstract class, enum (0) 2023.09.10 자바의 상속, Object 클래스 (0) 2023.09.10 JVM 구성, 동작 방식 (0) 2023.09.01