🔸 프로그램 실행 중 어떤 특정원인에 의해 정상적으로 작동하지 않거나 비정상적으로 종료가 되는 것을
프로그램 오류(에러)라고 한다.🔸 프로그램 오류의 종류
- 컴파일 에러 : 프로그램 실행 전 컴파일 시 발생하는 에러
- 런타임 에러 : 프로그램 실행 시 발생하는 에러
- 논리적 에러 : 프로그램이 실행은 되지만, 프로그래머의 의도와 다르게 동작하는 에러🔸 에러와 예외(런타임 에러)
- 에러 : 프로그램 코드에 의해 수습될 수 없는 오류 -> 일단 발생하면 복구할 수 없음, 비정상적인 종료를 막을 수 없음(심각한 것)
- 예외 : 프로그램 코드에 의해 수습될 수 있는 오류 -> 발생하더라도 적절한 대비 코드를 작성해 놓으면 비정상적인 종료를 막을 수 있음
Exception클래스들은 크게 RuntimeException과 그외 클래스들로 분류해 볼 수 있다.
🔸 RuntimeException클래스 : 프로그래머의 실수로 발생하는 예외
🔸 그외 Exception클래스들 : 사용자의 실수 등의 외부요인으로 발생하는 예외또한 checked, unckecked Exception으로 나눌수 있다.
🔸 unchecked Exception :
- 런타임 시점에서 확인하며,
- 예외처리는 선택사항이다.
- roll-back(O)
- RuntimeException클래스와 자손들
🔸 checked Exception :
- 컴파일 시점에 예외발생을 확인하며,
- 반드시 예외 처리를 해야 한다.
- roll-back(X)
- RuntimeException클래스들를 제외한 Exception클래스들과 그 자손들
➡️ 만약 checked Exception이 발생할 가능성이 있는 메서드라면, try-catch문을 사용하거나 throw로 던져서 예외처리를 반드시 해줘야 한다.
🔸 예외처리란,
프로그램 실행 시 발생할 수 있는 예외의 발생에 대비해서 코드를 작성하는 것으로, 예외로 인한 프로그램의 비정상 종료를 방지하고 정상적인 실행상태를 유지하도록 하는 것
try{ 예외가 발생할 가능성이 있는 코드들 }catch(Exception1 e1){ Exception1이 발생했을 때, 예외를 처리하기 위한 코드 }catch(Exception2 e2){ Exception2이 발생했을 때, 예외를 처리하기 위한 코드 }
🔸 try블럭 내 코드를 수행하다가 예외가 발생하게 되면 여러개의 catch문장 중 발생한 예외와 같은 catch블럭 내 코드를 수행 후 try-catch문을 빠져나가서 다음 코드를 수행한다.
(만약 catch블럭에 같은 예외가 없으면 예외는 처리되지 못한다.)
🔸 try블럭 내에서 예외가 발생하지 않는다면, catch블럭을 거치지 않고 빠져나가서 다음 코드를 수행한다.class Exception{ public static void main(String args[]){ int a = 100; int result = 0; for(int i = 0; i < 5; i++){ try{ result = a / (Math.random() * 10); // 랜덤값에서 0이 나오면 0으로 나눌 수 없으므로 ArithmaticException이 발생할 수 있음 System.out.println(result); }catch(ArithmaticException ae){ System.out.println("0"); } // try-catch } // for } }
🔸 printStackTrace() : 예외가 발생할 때 호출스택에 있었던 메서드의 정보와 예외 메시지를 출력한다.
🔸 getMessage() : 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.try{ ... }catch(ArithmeticException ae){ ae.printStackTrace(); System.out.println(ae.getMessage()); }
🔸 finally 블럭 : 예외 발생에 상관없이 실행되어야 하는 코드들을 넣는다
try{ // 예외가 발생할 가능성이 있는 코드 }catch{ // 예외처리를 위한 코드 }finally{ // 예외 발생과 상관없이 항상 실행되어야 하는 코드 }
🔸 예외 발생 : try -> catch -> finally
예외 발생 안함 : try -> finally
🔸 throw 키워드를 사용하여 예외를 고의로 발생시킬 수 있다.
- new연산자를 이용, 예외클래스의 객체를 만든다
- throw키워드를 이용해서 예외를 발생시킨다.try{ Exception e = new Exception("예외 고의발생"); throw e; }catch(Exception e){ System.out.println(e.getMessage()); e.printStackTrace(); }
🔸 메서드의 선언부에 throws 키워드를 이용해서 메서드 내에서 발생할 수 있는 예외를 적으면 된다.
void method() throws Exception{ ... }
➡️ 메서드를 사용하는 사람이 메서드를 사용할 때 어떤 예외가 처리되어야 하는지 쉽게 알 수 있다.
➡️ 엄밀히 말하자면, throws를 사용하여 예외를 적는 것은 예외처리하는 것이 아니라 '호출한 메서드에게 예외처리를 맡기는 것'이다.class Test{ public static void main(String args[]){ try{ method(); // 여기서 예외가 발생한 것으로 간주됨 }catch(Exception e){ System.out.println(e.getMessage()); e.printStackTrace(); } } static void method() throws Exception{ // method()에서 예외처리하지 않고 throws를 통해서 예외를 호출한 메서드로 넘긴다 throw new Exception(); // 예외 고의로 발생 } }
🔸 주의점 : Exception(최고조상)을 예외선언하면 그 자손타입 예외까지 발생할 수 있다.
🔸 보통은 RuntimeException클래스들은 잘 적지 않는다.
🔸 메서드 내에서 자체적으로 처리가 가능한 것은 메서드 내에서 try-catch문을 통해 예외처리하고,
메서드 호출 시 값을 다시 넘겨 받아야 하는 경우에는 throws를 사용해 예외를 선언하고 호출한 메서드에서 처리한다.
🔸 프로그래머의 필요에 따라서 원하는 예외를 정의하여 사용할 수 있다.
class MyException extends Exception{ MyException(String msg){ // 문자열을 매개변수로 받는 생성자 super(msg); // 조상클래스(Exception)의 생성자 호출 } }
🔸 예외가 발생한 메서드, 호출한 메서드 양쪽에서 처리할 수 있도록 하기 위해서 예외를 처리한 후, 다시 발생시키는 방법
class Test{ public static void main(String args[]){ try{ method(); }catch(Exception e){ e.printStackTrace(); System.out.println("main메서드에서 예외처리 됨."); } } static void method() throws Exception{ try{ throw new Exception(); }catch(Exception e){ System.out.println("method()에서 예외처리 됨."); throw e; // 예외 다시 발생 } } }
- main에서 method()가 호출된다.
- method()가 실행되면서 발생된 예외가 catch문에 걸려서 예외처리가 된 후, 다음코드(throw e)에 의해 다시 예외가 발생된다.
- 다시 발생한 예외로 인해 main에서 catch문에 예외가 걸려서 예외처리가 된다.
🔸 return이 있는 경우 catch블럭에도 return이 있어야 한다.
🔸 예외가 다른 예외를 발생시킬 수도 있다. (A예외가 B예외를 발생시켰다면, A는 B의 원인예외)
🔸 원인 예외를 새로운 예외에 등록한 후 다시 새로운 예외를 발생시키는데, 이를 예외 연결이라 한다.
🔸 연결 예외를 사용하는 이유 :
- 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해서
- checked exception을 unchecked exception으로 바꿀 수 있도록 하기 위해서SpaceException(원인예외)으로 InstallException 발생 try{ startInstall(); // SpaceException 발생! copyFiles(); }catch(SpaceException se){ InstallException ie = new InstallException("설치 중 예외 발생"); // 예외 생성 ie.initCause(se); // ie의 원인예외로 se(SpaceException) 지정 throw ie; // InstallException 발생 }catch(MemoryException me){ ... }
🔸 Throwable initCause(Throwable cause) : 원인예외로 등록
🔸 Throwable getCause() : 원인 예외를 반환❖ Throwable은 Exception의 조상이므로 모든 예외에서 사용 가능함.