자바스터디 - 9주차

megaseunghan·2022년 4월 16일
0

자바스터디

목록 보기
3/15
post-thumbnail

목표

자바의 예외 처리에 대해 학습하세요.

학습할 것 (필수)

  • 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
  • 자바가 제공하는 예외 계층 구조
  • Exception과 Error의 차이는?
  • RuntimeException과 RE가 아닌 것의 차이는?
  • 커스텀한 예외 만드는 방법

자바에서 예외 처리 방법 (try, catch , throw, throws, finally)

try - catch-finally 문

자바에서는 프로그램이 실행되는 도중 발생하는 예외를 처리하기 위해 try / catch / finally 문을 사용한다.

try {
    // 예외 발생시 throw 하고자 하는 코드
    catch(XXXException e1) {
        // e1 예외가 발생할 경우에 실행될 코드
    }
    catch(XXXException e2) {
        // e2 예외가 발생할 경우에 실행될 코드
    }
    ...
        
    finally {
        // 예외 발생과 상관없이 무조건 실행할 코드
    }
}
  • try 블럭에는 여러 개의 catch 블록이 올 수 있으며, 발생하는 예외의 종류와 일치하는 단 한 개의 catch 블록만 수행된다.
  • try블록에서 예외가 발생하면 throw 키워드를 사용하여 예외가 던져진다. 던져진 예외는 catch 블록에 의해 잡힐 수 있다.
  • catch 블록에서는 발생한 예외 코드나 예외 객체를 전달 받아 그 처리를 담당한다. 다중 catch문으로 작성할 때의 주의할 점은 범위가 낮은 예외들부터 작성을 해야 한다는 것이다(예외는 상속 관계를 가지고 있기 때문이다.).
  • finally 키워드는 예외와 별개로 반드시 실행시키고 싶은 소스들을 처리하고 싶을 때 사용한다.

try-catch-try-catch 문

try {
    // 예외 발생시 trhow 하고자 하는 코드
} catch(XXXException e1) {
    // 예외 발생시 실행될 코드
    try {
        // 예외 발생시 throw 하고자 하는 코드
        catch(XXXException e2) {
            // 예외 발생시 실행될 코드
        }
    }
}

catch 블록 내에 다시 try-catch문을 사용할 수 있는데 이 때 주의할 점은 참조되는 변수의 이름이 중복되면 안된다.

catch - printStackTrace() , getMessage()

예외가 발생하였을 때 해당 인스턴스에는 발생한 예외의 정보들이 담겨져 있다. 이에 대해 알고 싶을 때 printStackTrace() , getMessage()를 사용하여 예외의 정보를 얻는다.

printStackTrace()

  • 에러의 발생 근원지를 찾아서 단계별로 에러를 출력한다.
  • 매우 자세하게 나오며, 개발할 때에만 사용해야 한다. 운영할 시스템에 적용하면 엄청난 양의 로그가 쌓인다. 적재적소에만 사용해야 한다

getMessage()

  • 에러의 원인을 간단하게 출력한다.

throw

throw 키워드를 사용하면 고의로 예외를 발생시킬 수 있다.

class User {
   int age; 
}
class UserException {
    
    public static void main(String[] args) {
        
        Scanner sc = new Scanner(System.in);
 		User user = new User();
        
        System.out.println("나이를 입력하세요");
        user.age = sc.nextInt();
        
        try {
            if(user.age < 0 || user.age > 120) {
                throw new IllegalArgumentException("정확한 값을 입력해주세요");
            }
        } catch(IllegalException e) {
            System.out.println(e.getMessage());
        }
    }
}

IllegalArgumentException 인스턴스를 생성하여 throw로 예외를 발생시켰다.

throws

throws 키워드를 통해 메서드에 예외를 선언할 수도 있다.

public void 예외_던져줭() throws Exception {
    // 메서드 내용
}

예외_던져줭() 메서드에 예외를 선언해두고 해당 메서드를 호출할 때 어떤 예외를 처리해야 되는지 알려준다.

,를 기준으로 여러개 선언도 가능하다.

public void 예외_많이_던져줭 throws Exception1, Exception2, Exception3 {
    // 메서드 내용
}

throws 자체는 예외의 처리와는 관계가 없다. 메서드를 호출한 호출자가 이 예외를 처리해야 하기 떄문이다.

try-with-resources

1.7부터 자원의 해제를 자동으로 해주는 try-with-resources 구문이 추가되었다. resources는 DataSource, Connection, FileInpuStream 등 사용이 끝날 때 닫아줘야 하는 자원을 말한다.

try-with-resources는 try 키워드 {}이전에 ()를 열어 소괄호에 사용하게 될 자원을 입력하여 사용한다. 모든 자원이 ()에 들어갈 수 있는 것은 아니고 AutoCloseable 인터페이스를 구현한 객체만 사용 가능하다.

  • 1.7 이전
 public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        MysqlDataSource ds = getMySQLDataSource();

        try {

            con = ds.getConnection();
            pst = con.prepareStatement("SELECT VERSION()");
            rs = pst.executeQuery();

            if (rs.next()) {

                String version = rs.getString(1);
                System.out.println(version);
            }
        } catch (IOException e) {
            ...
        } catch (SQLException e) {
            ...
        } finally {

            if (rs != null) {
                rs.close();
            }

            if (pst != null) {
                pst.close();
            }

            if (con != null) {
                con.close();
            }
        }
    }
}
  • 1.7 이후
 public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        MysqlDataSource ds = getMySQLDataSource();

        try(con = ds.getConnection();
            pst = con.prepareStatement("SELECT VERSION()");
            rs = pst.executeQuery()) {

            if (rs.next()) {
                
                String version = rs.getString(1);
                System.out.println(version);
            }

        } catch (IOException e) {
            ...
        } catch (SQLException e) {
            ...
        }
    }
}

자바에서 제공하는 예외 계층 구조

출처 : https://www.javamadesoeasy.com/2015/05/exception-handling-exception-hierarchy.html

RuntimeException과 RE가 아닌 것의 차이는?

  • Checked Exception

    컴파일 시점에서 확인될 수 있는 예외. 만약 코드 내에서 이 예외를 발생시킨다면 해당 예외는 반드시 처리되거나 해당 코드가 속한 메서드 선언부에 예외를 선언해줘야 한다.

    치명적인 예외 상황을 발생시키기 때문에 try-catch문으로 감싸줘야 한다. 예외가 발생할 가능성이 있는 구문을 예외처리하지 않았다면 컴파일 에러가 발생한다.

  • Unchecked Exception(Runtime Exception)

    컴파일 단계에서 확인되지 않는 예외이다. Java에서는 Runtime Exception과 그 하위 클래스 ,그리고 Error와 그 하위 클래스가 이에 속한다. 이 예외들은 개발자가 알아서 처리 해야한다.

    try / catch 보다는 해당 예외가 발생하지 않도록 주의하여 코드를 짜는 것이 좋다.

예외와 에러의 차이

예외와 에러의 가장 큰 차이는 System Level의 문제와 Application Level의 문제의 차이다.

에러란

프로그램을 사용하다가 프로그램이 비정상적으로 종료될 때 이러한 결과를 초래하는 원인

Error는 빌트인 클래스 Throwable의 서브 클래스이다. 에러는 근본적으로 JVM에서 생성되거나 나타나는 예외이다. 오류는 일반적으로 프로그램에서 처리할 수 없는 치명적인 오류로 인해 발생한다. 프로그램에서 처리할 수 없다는 뜻은 사용자가 제어할 수 없다는 뜻이다.

컴파일러는 발생에 대한 지식이 없으므로 오류는 항상 검사되지 않은 유형이다. 오류는 항상 런타임 환경에서 발생한다. 예를 들면 스택 오버플로우, 메모리 부족, 시스템 충돌 등이 해당한다. 이러한 종류의 오류는 시스템으로 인한 것이다. 오류가 발생하면 프로그램이 비정상적으로 종료된다.

따라서 에러는 기본적으로 Unchecked Exception이다.

예외란

발생하더라도 프로그래머가 미리 적절한 코드를 사용해서 프로그램이 비정상적으로 종료되지 않도록 핸들링 해줄 수 있다.

예외는 내장 클래스 Throwable의 하위 클래스이기도 하다. 예외는 런타임 환경에서 발생하는 예외적인 조건이다. 예외의 대부분은 프로그램의 코드로 인해 발생하지만 예외는 복구할 수 있으므로 프로그램 자체에서 예외를 처리할 수 있다. 예외는 3개의 키워드 try, catch , throw 를 사용하여 처리한다.

예외와 에러의 차이는 ?

비교오류예외
기본시스템 자원이 부족하여 오류가 발생함코드로 인해 예외가 발생함
회복오류는 복구할 수 없다.예외는 복구할 수 있다.
키워드프로그램 코드에서 오류를 처리할 수 있는 방법은 없다.예외는 3개의 키워드 try, catch, throw를 사용하여 처리된다.
결과오류가 감지되면 프로그램이 비정상적으로 종료된다.예외가 감지되면 throw 및 catch 키워드에 따라 예외가 발생한다.
유형오류는 검사되지 않은 유형으로 분류된다.예외는 체크되거나 확인되지 않은 유형으로 분류 된다.
패키지Java에서 오류는 java.lang.Error패키지로 정의된다.Java에서 예외는 java.lang.Exception 패키지로 정의된다.
  • 시스템 자원이 부족한 경우에만 오류가 발생하지만 코드에 문제가 있는 경우 예외가 발생한다.
  • 오류는 복구할 수 없지만 예외를 처리할 코드를 준비하면 예외를 복구할 수 있다.
  • 오류는 결코 처리할 수 없지만 예외를 throw하는 코드가 try 및 catch 블록 내에 작성된 경우 예외가 코드에 의해 처리될 수 있다.
  • 오류가 발생하면 프로그램이 비정상적으로 종료된다. 반면에 예외가 발생하면 프로그램은 예외를 throw하고 try & catch 블록을 사용하여 처리된다.
  • 오류는 검사되지 않은 유형이다. 오류는 컴파일러에 대한 지식이 아니지만 예외는 검사된 것과 검사되지 않은 것으로 분류된다.

커스텀한 예외 만드는 방법

  • 일반 예외로 선언할 경우 Exception 을 상속받아 구현한다.
  • 실행 예외로 선언할 경우 RuntimeException을 상속받아 구현한다.
  • 사용자 정의 예외 클래스는 컴파일러가 체크하는 일반 예외(Checked Exception)와 컴파일러가 체크하지 않는(Unchecked Exception)로 선언할 수 있다.
  • 커스텀으로 만든 예외는 Exception으로 끝나는 것을 권장한다.
  • 생성자는 기본 생성자, 예외 발생 원인을 전달하기 위해 String 타입의 매개변수를 갖는 생성자 두개를 선언하는 것이 일반적이다. 예외 메세지는 catch의 {} 블록의 예외 처리에서 이용하기 위함이다.

커스텀 예외 생성

public class CustomException extends RuntimeException {
    // 1. 매개 변수가 없는 생성자
    public CustomException() {
        
    }
    
    // 2. 예외 발생 원인을 전달하기 위해 String 타입의 매개변수를 갖는 생성자
    public CustomException(String message) {
        super(message); // RuntimeException 클래스의 생성자를 호출한다.
    }
}

커스텀 예외 사용

public static void main(String[] args) {
    try {
        test();
    } catch(CustomException e) {
        System.out.println("아ㅋㅋ 예외라고");
        System.out.println(e.getMessage());
    }
}

public static void test() throws CustomException {
    throw new CustomException("ㅋㅋ아 예외라고");
}

출처

0개의 댓글