프로그램 수행 시 치명적 상황이 발생하여 비정상 종료 상황이 발생한 것.
프로그램 에러라고도 함
빨간글씨 비정상종료 == Error
소스코드 수정으로 처리할 수 있는 에러 == Exception
소스 코드 수정으로 해결 가능한 에러를 예외(Exception)라고 하는데 이러한 예외 상황(예측 가능한 에러) 구문을 처리 하는 방법인 예외 처리를 통해 해결
Java API Document에서 해당 클래스에 대한 생성자나 메소드를 검색하면 그 메소드가 어떤 Exception을 발생시킬 가능성이 있는지 확인 가능.
-> 발생하는 예외를 미리 확인하여 상황에 따른 예외 처리 코드를 작성할 수 있음
예시
BufferedReader : 입출력에 관련된 API
java.io.BufferedReader의 readLine() 메소드

이걸 처리해야한다고 나와있음
구글에 java api 17 검색해서 확인할 수 있음
Exception과 Error 클래스 모두 Object 클래스의 자손이며 모든 예외의 최고 조상은 Exception 클래스
객체로 만들어지면 => 예외가 발생함
자바 실행 시 발생하는 예외는 모두 클래스로 작성되어있음
반드시 예외 처리해야 하는 Checked Exception과 해주지 않아도 되는 Unchecked Exception으로 나뉨

Unchecked Exception으로 주로 프로그래머의 부주의로 인한 오류인 경우가 많기 때문에
예외 처리보다는 코드를 수정해야 하는 경우가 많음
선택적 처리
굳이 예외처리 하지 않아도 되지만 코드 수정은 해야함
ArithmeticException
0으로 나누는 경우 발생
if문으로 나누는 수가 0인지 검사
NullPointerException
Null인 참조 변수로 객체 멤버 참조 시도 시 발생
객체 사용 전에 참조 변수가 null인지 확인
NegativeArraySizeException
배열 크기를 음수로 지정한 경우 발생
배열 크기를 0보다 크게 지정해야 함
ArrayIndexOutOfBoundsException
배열의 index범위를 넘어서 참조하는 경우
배열명.length를 사용하여 배열의 범위 확인
ClassCastException
Cast연산자 사용 시 타입 오류
instanceof 연산자로 객체타입 확인 후 cast연산
InputMismatchException
Scanner를 사용하여 데이터 입력 시
입력 받는 자료형이 불일치할 경우 발생
try~catch문을 이용하여 예외 처리
try(시도하다) : 예외가 발생할 것 같은 코드 수행을 시도
-> 수행 중 예외 발생 시, 예외 객체가 던져짐(throw)
catch(던진 것을 받다) : try에서 던져진 예외를 잡아서 처리
-> 예외 잡아서 처리했기 때문에 프로그램이 종료되지 않음
public void ex1() {
System.out.println("두 정수를 입력받아 나누기한 몫을 출력");
System.out.print("정수 1 입력 : ");
int input1 = sc.nextInt();
System.out.print("정수 2 입력 : ");
int input2 = sc.nextInt();
예외 처리 전
System.out.println("결과 : " + input1/input2);
결과
두 정수를 입력받아 나누기한 몫을 출력
정수 1 입력 : 5
정수 2 입력 : 0
java.lang.ArithmeticException: / by zero
산술적 예외 발생 (0으로 나눌 수 없다.)
예외 처리 후
try {
System.out.println("결과 : " + input1/input2);
// 예외 발생할 것 같은 코드 넣어줌
} catch(ArithmeticException e) {
// try 에서 던져진 예외를 catch 문의 매개변수 e 로 잡음.
System.out.println("infinity"); // 처리코드
}
결과
두 정수를 입력받아 나누기한 몫을 출력
정수 1 입력 : 5
정수 2 입력 : 0
infinity
if문으로 예외 처리
위와 같은 결과 출력
if(input2 != 0) {
System.out.println("결과 : " + input1/input2);
} else {
System.out.println("infinity");
}
// 발생하는 예외 중 일부 예외 try~catch 구문 사용 안해도
// 예외 상황 방지할 수 있다. (if-else 사용)
// 일부 예외 == 대부분 Unchecked Exception
}
InputMismatchException
숫자 입력 창에 숫자 아닌 거 입력했을 때 발생
ArithmeticException
산술 오류
NullPointerException
null 값에서 무언가를 꺼내려 했을 때 발생
public void ex2() {
try {
System.out.print("입력 1 : ");
int num1 = sc.nextInt();
System.out.print("입력 2 : ");
int num2 = sc.nextInt();
System.out.println("결과 : " + num1/num2);
String str = null;
System.out.println(str.charAt(0));
} catch(InputMismatchException e) { // import 해줘야함
System.out.println("타입에 맞는 값만 입력해주세요");
} catch(ArithmeticException e) {
System.out.println("0 으로 나눌 수 없습니다.");
} catch(Exception e) {
System.out.println("뭔지 모르겠으나 예외가 발생해서 처리함.");
e.printStackTrace();
}
}
Exception 클래스 : 모든 예외의 최상위 부모
다형성 - 업캐스팅 : 부모타입 참조변수로 자식객체 참조
(모든 자식 예외들을 다 잡아서 처리 가능)
상위 타입의 예외 클래스를 catch 문에 작성하면 다형성 업캐스팅에 의해 모두 잡아서 처리 가능
발생한 예외에 대한 메서드와 위치에 대한 모든 내용을 출력
e.printStackTrace();
예외 발생 지점 추적
java.lang.NullPointerException: Cannot invoke "String.charAt(int)" because "str" is null at edu.kh.exception.model.service.ExceptionService.ex2(ExceptionService.java:97) at edu.kh.exception.run.ExceptionRun.main(ExceptionRun.java:12)
finally : try 구문에서 예외가 발생 하든 말든 무조건 마지막에 수행
public void ex3() {
try {
System.out.print("입력 1 : ");
int num1 = sc.nextInt();
System.out.print("입력 2 : ");
int num2 = sc.nextInt();
System.out.println("결과 : " + num1/num2);
} catch(ArithmeticException e) {
System.out.println("예외 처리 됨");
} finally {
System.out.println("무조건 수행 됨");
sc.close();
}
}
Resource leak: 'sc' is never closed
메모리 누수 발생
sc.close;
스캐너 통로 닫기 : 메모리 누수 방지
다 사용했으면 닫아줘야함
통로 닫기 할 때 finally 에 작성해줌
매개변수 e : 예외 관련된 정보 + 예외 관련 기능
System.out.println(e.getClass()); // 어떤 예외 클래스인가?
java.lang.ArithmeticException
System.out.println(e.getMessage()); // 예외 발생시 출력된 내용
/ by zero
System.out.println(e); // e.toString()
java.lang.ArithmeticException: / by zero
throws : 호출한 메서드에게 예외를 던짐
-> 호출한 메서드에게 예외를 처리하라고 위임하는 행위
throw : 예외를 강제 발생 구문
public void ex4() {
try {
methodA();
} catch(Exception e) {
// Exception : 모든 예외의 최상위 부모
// == 예외 종류 상관없이 모두 처리
System.out.println("methodC 에서부터 발생한 예외를 ex4에서 잡아 처리함.");
}
}
public void methodA() throws IOException {
methodB();
}
public void methodB() throws IOException {
methodC();
}
public void methodC() throws IOException {
// 예외 강제 발생
throw new IOException();
// try {
// throw new IOException();
//
// } catch(IOException e) {
// e.printStackTrace();
// }
// 메서드마다 다 써줘야함
}
오버라이딩 시 throws하는 Exception의 개수와 상관 없이 처리 범위가 같거나 후손이어야함.
Exception 클래스는 상속이 될 수록 상위 클래스 보다 예외의 내용이 더 상세하게 기술됨

왼쪽 IOException 까지는 가능 범위가 같으니까
Java API에서 제공하는 Exception Class 만으로는 처리할 수 없는 예외가 있을 경우
사용자의 필요에 의해 생성하는 Exception Class.
Exception 발생하는 곳에서 throw new 예외클래스명()으로 발생
public class UserException extends Exception{ // 예외 클래스 상속 받아서
public UserException() {}
public UserException(String msg) {
super(msg);
}
}
public class UserExceptionController {
public void method() throws UserException{
throw new UserException("사용자정의 예외발생");
}
}
public class Run {
public static void main(String[] args) {
UserExceptionController uc
= new UserExceptionController();
try {
uc.method();
} catch(UserException e) {
System.out.println(e.getMessage());
}
}
}