Search

예외 처리 2

예외 발생시키기

키워드 throw를 통해 고의로 예외 발생 가능
1.
연산자 new를 이용해 발생시키려는 예외 클래스의 객체 생성
Exception e = new Exception("고의로 발생시켰음");
2.
키워드 throw를 통해 예외 발생
throw e;
Exception 인스턴스 생성 시, 생성자에 String을 넣어 주면, Exception 인스턴스에 메세지로 저장됨. → getMessage()을 이용해 호출 가능
ExceptionEx8.java
예외 발생 가능성이 있는 문장들을 예외 처리 해주지 않으면 컴파일 조차 되지 않음.
ExceptionEx9.java
RuntimeException 클래스와 그 자손들에 해당하는 에외는 프로그래머의 실수에 의해 발생하는 예외들이므로 예외 처리가 강제가 아니라 컴파일은 되지만, 실행 시 오류 발생
ExceptionEx10.java
컴파일러가 예외처리를 확인하는 Exception 클래스 → checked 예외
컴파일러가 예외처리를 확인하지 않는 RuntimeException 클래스 → unchecked 예외

메소드에 예외 선언하기

메소드 선언부에 키워드 throws 사용
void method() throws Exception1, Exception2, ... ExceptionN { // 메소드 내용 }
Java
최고 조상 Exception 클래스를 메소드에 선언하면 모든 종류의 예외가 발생할 가능성을 의미
void method() throws Exception { // 메소드 내용 }
Java
Java API메소드들의 설명을 통해 반드시 처리를 해주어야 하는 예외 목록들을 알 수 있음.
메소드에 선언하는 throws는 사실 예외 처리가 아니라, 자신을 호출한 메소드에게 예외를 전달하여 에외 처리를 떠맡기는 역할
ExceptionEx11.java
throws를 통해 예외를 넘겨주면 어느 곳에선 반드시 try-catch문을 통해 예외 처리 필요
ExceptionEx12.java
ExceptionEx13.java
ExceptionEx14.java
ExceptionEx15.java

finally 블럭

예외 발생여부와 관계없이 실행되어야 할 코드를 포함시킬 목적으로 사용 try-catch-fianlly의 순서로 try-catch문 끝에 덧붙여 사용
예외 발생한 경우 try→catch→finally, 발생하지 않은 경우 try→finally 순서로
try { // 예외 발생 가능성이 있는 문장 } catch (Exception e1) { // 예외 처리를 위한 문장 } finally { // 예외 발생여부와 관계없이 항생 수행되어야할 문장 // finally 블럭은 try-catch문 맨 만지막에 위치 }
Java
예외 발생여부와 상관없이 필요한 메소드를 실행시키는 경우
FinallyTest.java
finally 블럭을 사용하는 경우
FinallyTest2.java
try-catch문에서 return문이 수행되더라도 finally 블럭이 수행됨.
FinallyTest3.java

자동 자원 반환 - try-with-resources문

JDK 1.7부터 추가된, try-catch문의 변형
입출력(I/O)과 관련된 클래스 사용 시 유용
입출력과 관련된 클래스 중엔 사용했던 자원(resources)의 반환을 위해 사용한 후 꼭 닫아줘야 하는 것들이 있는데..
// DataInputStream을 사용해 파일로부터 데이터를 읽는 코드 try { fis = new FileInputStream("score.dat"); dis = new DataInputStream(fis); ... } catch (IOException ie) { ie.printStackTrace(); } finally { dis.close(); // 작업 중 예외가 발생하더라도, dis가 닫히도록 finally 블럭에 넣음 } // 위 코드에서 close()가 예외를 발생시킬 수 있으므로 // finally에 try-catch문을 넣음 try { fis = new FileInputStream("score.dat"); dis = new DataInputStream(fis); ... } catch (IOException ie) { ie.printStackTrace(); } finally { try { if (dis != null) dis.close(); } catch (IOException ie) { ie.printStackTrace(); } }
Java
위 코드는 복잡하며, tryfinally블럭 모두에서 예외가 발생하면, try블럭의 예외는 무시된다는 단점이 있음. → try-with-resources문의 등장
// try () 안에 객체 생성 문장을 넣으면 // 따로 close()를 호출하지 않아도 try를 벗어나는 순간 자동으로 close() 호출 // 그 뒤로 finally가 수행됨. try (FileInputStream fis = new FileInputStream("score.dat"); DataInputStream dis = new DataInputStream(fis)) { while (true) { score = dis.readInt(); System.out.println(score); sum += score; } } catch (EOFException e) { System.out.println("점수의 총합은 " + sum + "입니다."); } catch (IOException ie) { ie.printStackTrace(); }
Java
try-with-resources문에 의해 자동으로 객체의 close()가 호출되려면, 클래스가 AutoCloseable 인터페이스를 구현한 것이어야 함.
public interface AutoCloseable { void close() throws Exception; }
Java
자동 호출된 close()에서 에외가 발생한다면?
TryWithResourceEx.java
exceptionWork()에서 예외가 발생하고 자동으로 호출된 close()에서도 예외가 발생한다면suppressed 출력과 함께 억제된 CloseExecption 예외의 정보는 WorkException에 저장
기존 try-catch문에선 먼저 발생한 WorkException은 무시됨.
Thorwable에 정의된 억제된 예외 관련 메소드
void addSuppressed(Throwable exception) : 억제된 예외를 추가
Throwable[] getSuppressed() : 억제된 예외(배열)을 반환

사용자 정의 예외 만들기

기존 정의된 예외 클래스 외에 필요에 따라 사용자 정의 예외 클래스 정의 가능
일반적으로 Exception 이나 RuntimeException 클래스로부터 상속받아 클래스를 만들지만, 필요에 따라 알맞은 예외 클래스 선택 가능
class MyException extends Exception { // 메세지 저장을 위해 String을 매개변수로 받는 생성자 추가 MyException(String msg) { // 문자열을 매개변수로 받는 생성자 super(msg); // 조상 Exception 클래스의 생성자 호출 } } // 에러코드 값도 저장할 수 있도록 멤버 축차 class MyException extends Exception { // 에러 코드 값 저장을 위한 필드 추가 private final int ERR_CODE; // 생성자를 통해 초기화 MyException(String msg, int errCode) { // 생성자 super(msg); ERR_CODE = errCode; } MyException(String msg) { // 생성자 this(msg, 100); // ERR_CODE를 100(기본값)으로 초기화 } public int getErrCode() { // 에러 코드를 얻을 수 있는 메소드 추가 return ERR_CODE; // 주로 getMessage()와 함께 사용될 메소드 } }
Java
기존 예외 클래스는 Exception을 상속 받아 checked예외로 작성하는 경우가 많았으나, 요즘은 선택적 예외처리가 가능한 RuntimeException을 상속받아 작성하는 쪽으로 바뀌고 있음.
checked예외보단 unchecked예외로!
NewExceptionTest.java

예외 되던지기(Exception Re-Throwing)

한 메소드에서 발생할 수 있는 예외가 여럿일 경우, 몇 개는 try-catch문으로, 나머지는 선언부에 지정하여 호출한 메소드에서 처리함으로써, 양쪽으로 나눠 처리 가능
예외가 하나만 있어도 발생한 메소드, 호출한 메소드 양쪽에서 처리 가능
예외 되던지기 : 예외 처리 후 인위적으로 예외를 다시 발생시키는 것
try-catch문에서 예외 처리 후, catch문에서 thorw문을 사용해 다시 예외 발생
예외가 전달된 메소드의 try-catch문에서 다시 예외 처리
하나의 예외에 대해서 예외가 발생한 메소드와 이를 호출한 메소드 양쪽 모두에서 처리해 줘야 할 작업이 있을 때 사용
예외가 발생할 메소드에서는 try-catch문을 사용해서 예외처리, 동시에 메소드 선언부에 발생할 예외를 throws를 통해 지정
ExceptionEx16.java
반환값이 있는 return문의 경우, catch블럭에도 return문이 있어야 함.
catch블럭에서 예외 되던지기로 호출한 메소드로 예외를 전달하면, return문이 없어도 됨. 검증에서도 assert문 대신 AssertError를 생성해서 던짐.

연결된 예외 (Chained Exception)

한 예외가 다른 예외를 발생시키는 경우
try { startInstall(); // SpaceException 발생 copyFiles(); } catch (SpaceException e) { InstallException ie = new InstallException("설치 중 예외발생"); // 예외 생성 ie.initCause(e); // InstallException의 원인 예외를 SapceException으로 지정 throw ie; // InstallException 발생 } catch (MemoryException me) { ...
Java
Throwable initCause(Throwable cause) : 지정한 예외를 원인 예외로 등록
Throwable getCause() : 원인 예외를 반환
원인 예외를 등록해서 다시 예외를 발생시키는 이유?
여러가지 예외를 하나의 큰 부류의 예외로 묶어 다루기 위해
조상 클래스로 묶어서 예외를 처리하는 건 어떤 예외가 발생했는지 알 수 없다는 문제가..
예외가 원인 예외를 포함할 수 있게 하면 두 예외가 상속 관계가 아니어도 됨!
checked에외를 unchecked예외로 바꿀 수 있도록 하기 위해
unchecked예외를 사용하면 선택적 예외 처리 가능
ChaineExceptionEx.java

참고 자료