개발자가 의도하지 않은 상황에서 발생하는 문제
예외가 발생할 경우 프로그램이 비정상적으로 종료됨
-> 예외 발생 위치의 아래쪽 코드 실행X
오류와 달리 심각도 낮으며, 예외처리를 통해 비정상적인 종료 막을 수 있음
예외 처리를 위해 try ~ catch
문 사용하여 처리
-> 예외 발생 예상되는 코드들을 try 블록 내 기술
-> 예외 발생 시 JVM에 의해 해당 예외 객체 전달받아 catch 블록 중 일치하는 타입에 대한 블록 실행하여 예외 처리
Exception 클래스 및 하위 클래스 사용하여 예외 처리
두 가지 계열로 나누어짐
-> 컴파일 시점에서 예외 발생 여부 체크 Compile Checked Exception
-> 실행 시점에서 예외 발생 여부 체크 Compile UnChecked Exception
< 예외 처리 기본 문법 >
try { // 예외 발생 예상되는 코드들... } catch(예외클래스명1 변수명) { // 예외클래스명1에 해당하는 예외 발생 시 처리할 코드들... } catch(예외클래스명n 변수명) { // 예외클래스명n에 해당하는 예외 발생 시 처리할 코드들... } finally { // 예외 발생 여부와 관계없이 무조건 실행할 문장들... // DB 자원 반환, I/O 자원 반환 등 }
예외 발생 여부와 관계없이 무조건 수행해야할 문장 기술
return문을 만나서 메서드 종료하더라도 finally 블록 실행 후 호출한 곳으로 돌아감
나눗셈 연산의 피연산자가 0인 경우
ArithmeticException
예외 발생
⭐ 입력
System.out.println(3 / 0);
📌 출력
java.lang.ArithmeticException : / by zero
/ by zero
: 0에 의한 나눗셈으로 인해 예외가 발생했다는 메세지배열에 존재하지 않는 인덱스 접근 시
ArrayIndexOutOfBoundsException
예외 발생
⭐ 입력
int[] arr = {1, 2, 3};
System.out.println(arr[5]);
📌 출력
java.lang.ArrayIndexOutOfBoundsException: Index 5
객체의 주소를 참조하지 않는 참조변수(null) 접근 시
NullPointerException
예외 발생
⭐ 입력
String str = null;
System.out.println(str.length());
📌 출력
java.lang.NullPointerException
try {
// 예외 발생 예상 코드 try 블록 내에 적어주기
System.out.println(3 / 0);
// 만약 여기서 예외가 발생했다면
// 밑의 코드들은 실행되지 않고 바로 catch문으로 이동함
int[] arr = {1, 2, 3};
System.out.println(arr[5]);
String str = null;
System.out.println(str.length());
} catch(ArithmeticException e) {
// 보통 변수명을 e로 많이 쓴댜
// 여기에 예외 발생했을 때 처리할 코드 적어주기
// 예외 발생하지 않으면 이 블록은 실행되지 않음
e.printStackTract();
// 예외 클래스, 발생위치, 원인 등을 자세히 출력
System.out.println("0으로 나눌 수 없음" - e.getMessage());
// 이 문장은 필수 아님
// getMessage() 메서드 이용할 경우 예외 발생 원인 메세지를 문자열로 리턴해줌
} catch(ArrayIndexOutOfBoundsException e) {
e.printStackTract();
} catch(NullPointerException e) {
e.printStackTract();
} catch(Exception e) {
// 위쪽의 catch 블록에서 지정되지 않은 나머지 예외 처리
// 대신 예외 처리 방법 구분 못함
// 반드시 다른 예외 클래스 다 기술한 뒤에 마지막에 적기!!!
e.printStackTract();
} finally {
// 무조건 실행될 문장들...
}
예외 발생한 곳에서 try ~ catch
블록으로 직접 처리할 수 있지만 메서드 호출한 곳으로 예외 처리 위임도 가능
throws
키워드 사용
예외 처리를 위임받은 메서드는 다시 예외 처리에 대한 책임이 발생하여 직접 처리하거나 또 다른 곳으로 위임 가능
최종 단계의 메서드에서는 try ~ catch
블록을 사용하여 예외 직접 처리해야 함
throws
키워드 사용하여 지정하는 예외는 1개 또는 복수 개 지정 가능
< 예외 위임 기본 문법 >
- 메서드 정의 시 메서드 선언부 마지막에 throws 키워드 쓰고 뒤에 예외를 위임할 클래스명을 기술(복수 개일 경우 콤마로 구분)
[제한자] 리턴타입 메서드명([파라미터...]) throws 예외클래스명... {
// 예외 발생 코드...
}
public static void main(String[] args) {
// 메인메서드
// 더 이상 도망갈 곳 없음...
// 여기서는 예외 위임X
// 무조건 처리해야만...
try {
A();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void A() throws Exception {
B();
// 예외를 위임받았으나!
// 여기서도 위임을 하려고 한다면?
// 여기서도 마찬가지로 throws 키워드를 사용해서
// 두 예외 타입 모두 적어도 되지만
// Exception 하나로 적어도 상관없음
// 얘는 모든 예외 포함함
}
public static void B() throws RuntimeException, ClassNotFoundException {
C();
D();
// 예외 위임 받았음
// 직접 try ~ catch문 사용할 경우
// try 블록 안에 C()와 D() 메서드 넣으면 됨
// 근데 여기서도 A에게 위임하고자 한다면
// 또 throws 키워드를 이용해서 위임해야 하는데
// C에서 발생한 오류는 2개임
// 얘네를 둘 다 적어줘도 되는데 상위 타입으로 결합해서 적는 것도 가능함!
}
public static void C() throws ArithmeticException, NullPointerException {
System.out.println(3 / 0);
// 오류 발생1
String str = null;
System.out.println(str.length());
// 오류 발생2
// 직접 try ~ catch 문으로 감싸거나 위임
}
public static void D() throws ClassNotFoundException {
Class.forName("");
System.out.println("D에서 오류 발생);
// 직접 try ~ catch 블록 만들거나
// 위임 가능함
}
개발자 의도대로 예외를 직접 발생 시킬 수 있음
throw
키워드 사용하여 발생시킬 예외 클래스 객체 지정
-> 예외 클래스 인스턴스 생성하여 강제로 해당 예외 발생시킴
예외 클래스 인스턴스를 변수에 저장해서 발생시켜도 되지만 주로 일회성 예외를 발생시키므로 별도의 변수 없이 임시 객체 형태로 사용하는 경우 많음
-> new 예외클래스명() 형태로 객체 생성하여 전달
< 기본 문법 >
예외를 발생시킬 코드 위치에서
throw 예외객체;
기존의 예외 클래스가 발생시킨 예외와 일치하지 않을 경우 Exception
클래스로 예외 처리 시 발생한 예외 파악하기 어려움
예외 클래스를 작성하여 발생시킬 예외에 맞는 객체로 만들어 전달하면 예외 파악 쉬움
사용자 정의 예외 클래스 정의 시 예외 클래스를 상속받아 정의
-> 주로 Exception
클래스 상속받아 정의
보통 생성자 정의하여 슈퍼클래스에 예외 메세지만 초기화
⭐ 입력
public static void main(String[] args) {
try {
printScore(150);
} catch(InvalidScoreException e) {
e.printStackTrace();
}
}
public static void printScore(int score) throws Exception {
// 점수를 입력받아 학점을 계산하는 메서드
// 점수 범위를 0 ~ 100 점 사이로 한정
// 점수 범위를 벗어날 경우 오류 발생 필요함
// 근데 벗어나도 int형 정수 범위에는 포함되니까 자바에서는 오류로 생각안함
// 내가 직접 오류로 만들어야 함!!
if(score < 0 || score > 100) {
System.out.println(score + "점 : 점수 입력 오류");
throw new Exception("점수 입력 오류 : " + score);
}
// throw 키워드 사용해서 해당 예외 클래스 객체를 생성
// 하지만 점수 입력 오류에 대한 예외는 자바에 없기 때문에 Exception 클래스 사용함
// 이렇게 자바에서 표시하는? 오류가 아니면 Exception 크래스 사용하면 됨
// 예외 발생 시 표시할 메세지 생성자 파라미터로 전달
// throw 뒤에 생성한 예외 객체의 참조변수 지정해서 해당 예외 발생시킴
// throw e; 이런 식으로 해야 하는데
// 나는 한 번만 쓰고 버릴 거라서 참조변수 안 쓰고
// 바로 객체 생성했음(얘는 임시객체)
}
public static void userExceptionMethod(int score) throws InvalidScoreException {
if(score < 0 || score > 100) {
throw new InvalidScoreException("점수 입력 오류 : " + score);
}
// Exception 클래스 대신 사용자 정의 예외클래스로 예외 발생 시키기
}
class InvalidScoreException extends Exception {
// 사용자 정의 예외 클래스
// 클래스 이름은 상관 없음 원하는 걸로 아무거나...
// 주로 Exception 클래스 상속 받음
public InvalidScoreException(String name) {
// 생성자 정의해서 예외 메서지를 슈퍼클래스 생성자에 전달함
super(message);
}
}
📌 출력
ExceptionClass.InvalidScoreException: 점수 입력 오류 : 150