티스토리 뷰

11.1 예외와 예외 클래스

  • 에러: 컴퓨터 하드웨어의 고장으로 응요프로그램 실행 오류가 발생하는 것
  • 예외: 잘못된 사용 또는 코딩으로 인한 오류로 예외가 발생하면 프로그램은 곧바로 종료되지만
  • 예외 처리를 통해 계속 실행 상태 유지 가능
  • 일반 예외: 컴파일러가 예외 처리 코드 여부를 검사하는 예외
  • 실행 예외: 컴파일러가 예외 처리 코드 여부를 검사하지 않는 예외 
  • 모든 에러와 예외 클래스는 Throwable을 상속받아 만들어지고, 
  • 예외 클래스는 java.lang.Exception 클래스를 상속받는다
  • 자바는 자주 사용되는 예외 클래스를 표준 라이브러리로 제공

 

11.2 예외 처리 코드

  • 예외 처리 코드: 예외가 발생했을 때 프로그램의 종료를 막고 정상 실행을 유지할 수 있도록 처리하는 코드
  • finally 블록: 예외 발생 여부와 상관 없이 항상 실행되며, return 문이 있어도 실행된다. 생략 가능

 

 

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("start");
        printLength("java");
        printLength(null);
        System.out.println("end");
    }

    public static void printLength(String data) {
        try {
            int result = data.length();
            System.out.println(result);
            
        // try블록에서 예외가 발생하면 실행되는 블록    
        } catch (NullPointerException e) {
        
            // 예외가 발생한 이유만 리턴
            // Cannot invoke "String.length()" because "data" is null
            System.out.println(e.getMessage());
          
           // 예외의 종류도 리턴
           // java.lang.NullPointerException: Cannot invoke "String.length()" because "data" is null
            System.out.println(e.toString());
            
            // 예외가 어디서 발생했는지 추적한 내용까지도 출력
            e.printStackTrace();
        } finally {
            System.out.println("언제나 실행");
        }
    }
}

 

11.3 예외 종류에 따른 처리

  • 다중 catch를 사용하면 발생하는 예외에 따라 예외 처리 코드를 다르게 작성 가능
  • 해당 타입의 예외가 발생하면 catch 블록이 선택되어 실행
  • catch가 여러개더라도 하나만 실행 -> 왜냐면 하나의 예외가 발생하면 즉시 실행을 멈추고 catch블록으로 이동하기 때문에
  • 예외 클래스들이 상속 관계에 있을 때는 하위 클래스를 먼저 작성하고 상위 클래스를 작성
public class ExcetionDemo2 {
    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(i + value);
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("배열 인덱스 초과" + e.getMessage());
            } catch (NumberFormatException e) {
                System.out.println("숫자로 변환할 수 없음" + e.getMessage());
                
                // 두개 이상의 예외를 동일하게 처리하고 싶을 때는 | 사용
            // } catch (NullPointerException e | Exception ) {
                
            }
        }
    }
}

 

11.4 리소스 자동 닫기

  • 리소스: 데이터를 제공하는 객체로, 사용하기 위해 open해야 하고 사용 후에는 close를 해야한다.
  • 따라서 예외가 발생하더라도 안전하게 닫는 것이 중요
  • finally블록에서 close() 함수를 호출하면 예외 발생 여부와 상관 없이 언제나 닫아 준다.
  • try-with-resources블록을 사용하면 마찬가지로 예외 발생 여부와 상관 없이 언제나 리소르를 닫아 준다.
  • 이 때, AutoCloseable 인터페이스의 close() 메소드를 재정의해야한다.
public class TryWithResourceDemo {
    public static void main(String[] args) {
        // try-with-resources블록
        try (MyResource res = new MyResource()) {
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("닫기");    
    }
}

 

11.5 예외 떠넘기기

  • throws 키워드를 사용해서 메소드를 호출한 곳으로 예외를 떠넘길 수 있음
  • 이 메소드를 호출하는 곳에서 예외를 받아 처리해야 한다.
  • main()메소드에서 예외를 떠넘기면 JVM이 최종적으로 처리하는데, 예외 내용을 콘솔에 출력하는 것으로 처리한다.
public class ThrowsDemo {
    public static void main(String[] args) {
        
        // 호출한 곳에서 예외 처리
        try {
            findClass();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    // 호출한 곳으로 예외를 떠넘김
    public static void findClass() throws ClassNotFoundException {
        Class.forName("java");
    }
}

 

11.6 사용자 정의 예외

  • 표준 라이브러리에 존재하지 않는 예외는 직접 에외 클래스를 정의해서 사용
  • 일반 예외로 선언 가능 - Exception의 자식 클래스로 선언
  • 실행 예외로 선언 가능 - RuntimeException의 자식 클래스로 선언
public class AccountDemo {
    public static void main(String[] args) {
        Account account = new Account();

        account.deposit(10000);

        try {
            account.withdraw(30000);
        } catch (InsufficientException e) {
            // Throwable 의 getMessage에서 저정된 필드값을 반환
            String message = e.getMessage();
            System.out.println(message);
        }
    }
}

class Account {
    private long balance;

    public Account() {
    }

    public long getBalance() {
        return balance;
    }

    public void deposit(int money) {
        balance += money;
    }

    public void withdraw(int money) throws InsufficientException {
        if (balance < money) {
            throw new InsufficientException("잔고 부족");
        }

        balance -= money;
    }
}

// 잔고 붖ㄱ 시 처리할 사용자 정의 예외 클래스
class InsufficientException extends Exception {
    public InsufficientException() {
    }

    public InsufficientException(String message) {
        // Exception의 부모인 Throwable 에 있는 필드에 저장된다
        super(message);
    }
}
최근에 올라온 글