[혼공자]6주차 - chap10
- 기본 숙제
p.486 10-2 확인 문제 2번 풀고 과정 설명하기
정답은 4번, 예외를 떠넘기기 위해 사용하는 것이지 새로운 예외를 발생시키기 위해 사용되는 것은 아니다.
- 추가 숙제
java.lang 패키지에 속하는 주요 클래스와 용도를 정리해서 포스팅하기
10. 예외처리
10 - 1 예외 클래스
기계로 인해 발생하는 문제는 에러(error), 사람이 하는 실수는 예외(exception).
예외에는 두 종류가 있는데 일반 예외와 실행 예외가 있다.
- 일반 예외(exception) : 컴파일러 체크 예의라고도 한다. 프로그램 실행 시 예외가 발생할 확률이 높기 때문에 컴파일러 과정에서 예외처리 코드가 있는지 검사한다.
- 실행 예외(runtime exception) : 컴파일러 넌 체크 예외라고도 한다. 실행 시 예측할 수 없이 갑자기 발생하기 때문에 예외 처리 코드 검사는 하지 않는다.
자바는 예외를 클래스로 관리한다. JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체 생성 후 예외처리(exception handling) 코드에서 예외 객체를 이용할 수 있도록 해준다. 모든 예외 클래스는 다음과 같이 java.lang.Exception 클래스를 상속받는다.
일반 예외와 실행 예외 클래스는 RuntimeException을 기준으로 구별한다. RuntimeException의 하위 클래스가 아니면 일반 클래스이고, 하위클래스라면 실행 예외 클래스이다. 클래스 상속 관계에서 부모(조상)에 RuntimeException이 있다면 실행 예외 클래스이다.
실행 예외는 자바 컴파일러가 체크하지 않기 때문에 오로지 개발자의 경험에 의해 예외처리코드를 작성해야 한다. 만약 실행 예외에 대해 예외처리 코드를 넣지 않는다면, 해당 예외가 발생했을 때 프로그램은 곧바로 종료된다.
- NullPointerException
객체 참조가 없는 상태로, 즉 null 값을 갖는 참조 변수로 객체 접근 연산자인 도트(.)를 사용했을 때 발생한다. 객체가 없는 상태에서 객체를 사용하려 했으니 예외가 발생된다.
- ArrayIndexOutOfBoundsException
배열에서 인덱스 범위를 초과할 경우 발생한다. 배열값을 읽기 전에 배열의 길이를 먼저 조사하며 보완할 수 있다. 실행 매개값이 없거나 부족할 경우 조건문을 이용해 사용자에게 알려준다.
- NumberFormatException
문자열로 되어있는 데이터를 숫자로 변경하는 경우 Interger와 Double은 포장(Wrapper) 클래스라 하고, 포장 클래스의 정적 메소드인 parseXXX() 메소드를 이용하면 변환할 수 있다. 이 메소드들은 매개값이 문자열이 숫자로 변환할 수 있다면 숫자를 리턴 하지만, 숫자로 변환할 수 없다면 예외가 발생한다.
리턴 타입 | 메소드 이름(매개변수) | 설명 |
int | Integer.parseInt(String s) | 주어진 문자열을 정수로 변환해 리턴 |
double | Double.parseDouble(String s) | 주어진 문자열을 실수로 변환해 리턴 |
- ClassCastException
타입 변환을 뜻하는 casting을 보아 클래스는 다른 타입으로 변환할 수 없는데 그럴 경우에 발생하는 예외라 볼 수 있다. 타입 변환은 상위 클래스와 하위 클래스 간(= 상속 관계)에 발생하고, 구현 클래스와 인터페이스 간(= 구현 관계)에도 발생한다. 이러한 관계가 아니라면 다른 타입으로 변환되지 않는다.
-> 대입된 객체가 아닌 다른 클래스 타입으로 타입 변환하면 발생한다. 이 예외를 발생시키지 않으려면 instanceof 연산자로 타입 변환 전에 타입 변환이 가능한지 확인하는 게 좋다. 연산의 결과가 true라면 좌항 객체를 우항 타입으로 변환 가능하다. ex) ( animal instanceof Dog )라면 animal이 Dog로 변환 가능한지 확인하고 변환한다.
- 확인 문제
10 - 2 예외 처리
예외 처리 : 프로그램에서 예외가 발생했을 경우 프로그램의 갑작스러운 종료를 막고, 정상 실행을 유지할 수 있도록 처리하는 것이다.
자바 컴파일러는 소스 파일을 컴파일할 때 일반 예외가 발생할 가능성이 있는 코드를 발견하면 컴파일 에러를 발생시켜 개발자가 강제적으로 예외처리 코드를 작성하도록 요구하는데 반해. 실행 예외는 컴파일러가 체크해주지 않기 때문에 개발자의 경험을 바탕으로 예외 처리 코드를 작성해야 한다.
예외 -> 컴파일러 -> RuntimeException 라면 통과(실행예외니까)
-> RuntimeException이 아닌 경우는 검사.
- 예외 처리 코드 방법
- try-catch-finally 블록은 생성자 내부와 메소드 내부에서 작성되어 일반 예외와 실행 예외가 발생할 경우 예외 처리할 수 있도록 해준다.
try {
예외 발생 코드
} catch(예외클래스 e) {
예외 처리
} finally {
항상 실행;
}
- 예외가 발생한다면 즉시 실행을 멈추고 catch 블록으로 이동해 예외 처리 코드 실행한다. 그리고 finally 블록을 실행한다.
- 예외가 발생하지 않는다면 catch문 실행하지 않고 finally 블록의 코드를 실행한다.
- finally 블록은 생략 가능하다. 예외 발생 여부와 상관없이 항상 실행할 내용이 있을 경우에만 작성한다. 심지어 try블록과 catch 블록에서 return문을 사용하더라도 finally 블록은 항상 실행된다.
이클립스는 일반 예외가 발생할 가능성이 있는 코드가 있다면 빨간 밑줄을 그어 예외처리 코드의 필요성을 알려준다. 빨간 밑줄에 마우스 포인터를 가져다 놓으면 Unhandledexception(처리되지 않은 예외) 정보를 알 수 있다.
Class.forName() 메소드는 매개값으로 주어진 클래스가 존재하면 class 객체를 리턴 하지만, 존재하지 않으면 ClassNotFoundException 발생한다. ClassNotFoundException은 일반 예외이므로 컴파일러는 개발자에게 예외처리코드를 작성하도록 요구한다.
- 다중 catch
발생하는 예외별로 예외 처리 코드를 다르게 하는 다중 catch 블록을 가질 수 있다. 다중 catch문 작성 시 주의할 점은 상위 예외 클래스가 하위 예외 클래스보다 아래에 위치해야 한다. 하위 예외는 상위 예외를 상속했기 때문에 상위 예외 타입도 되기 때문이다. 그래서 구별을 위해 구체적인 예외인 하위 예외 클래스를 먼저 작성하고, 그다음에 그 이후의 모든 예외를 포함하는 상위 예외 클래스로 작성해야 한다. 발생되는 예외별로 예외 처리 코드를 다르게 하기 위해서
- 예외 떠넘기기
메소드를 호출한 곳으로 예외 떠넘기기. 이때 사용하는 키워드가 throws. throws는 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 역할. throws 키워드 뒤에는 떠넘길 예외 클래스를 쉼표로 구분해 나열해 주면 된다.
리턴타입 메소드이름(매개변수, ...) throws 예외클래스1, 예외 클래스2, ... {
}
발생할 수 있는 예외의 종류별로 throws 뒤에 나열하는 것이 일반적이지만, 다음과 같이 throws Exception 만으로 모든 예외를 떠넘길 수도 있다.
리턴타입 메소드이름(매개변수, ...) throws Exception {
}
throws 키워드가 붙은 메소드는 반드시 try 블록 내에서 호출되어야 한다. 그리고 catch 블록에서 떠넘겨 받은 예외를 처리해야 한다.
- 확인문제