의도치 않게 종료되는 것을 방지하기 위해원인과 위치를 쉽게 파악하기 위해try-catch로 처리try예외가 발생할 수 있는 코드를 작성catch예외가 발생하면 실행되는 블록자식 예외들도 모두 받을 수 있음여러 개의 catch문을 작성할 수 있음계층 구조로 예외가 잡힘
catch문은 try문에서 어떤 예외가 발생하느냐에 따라 결정됨
public class CatchExceptionLater {
public static void main(String[] args) {
CatchExceptionLater obj = new CatchExceptionLater();
obj.catchException();
}
void catchException() {
int[] Array = new int[3];
try {
Array = null; //null 예외 발생
Array[5] = 1;
} catch (NullPointerException e) {
System.out.println("널 예외 발생"); //NullPointerException 예외 캐치함
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("인덱스 범위 벗어난 예외 발생"); //실행x
} catch (Exception e) {
System.out.println("나머지 예외사항 발생"); //실행x
}
System.out.println("무조건 실행되는 문장");
}
}
catch에서 사용하는 변수catch 블록에서도 변경된 값을 사용함
→ try 블록에서 사용되었다고 해서 catch 블록에 전혀 영향을 줄 수 없다는게 아님!!
void printMonth(int number) {
int a = 0;
try {
a = 10;
if (number > 12) {
throw new Exception("1월에서 12월만 있음");
}
System.out.println(number + "월달 입니다.");
} catch (Exception e) {
System.out.println(a); // 10 출력
e.printStackTrace();
}
}
throws)throws를 사용해 예외를 던지는 메소드임을 명시해야 함
public class MonthClass {
void printMonth(int number) throws IllArgumentException {
if (number > 12) {
throw new IllArgumentException("1월에서 12월만 있음");
}
System.out.println(number + "월달 입니다.");
}
}
예외 발생 시 printMonth()를 호출한 곳에서 예외를 처리해야함
떠넘기는 경우해당 메소드를 사용했을 때 발생할 수 있는 예외를 명시하기 위해
예외를 발생시키는 메소드를 간결하게 작성하기 위해
현재 메소드 내에서 굳이 예외를 처리할 필요가 없을 때 경우
= 해당 메소드를 사용하는 곳에서 처리하는게 더 좋은 경우
항상 실행
void printMonth(int number) {
try {
if (number > 12) {
throw new Exception("1월에서 12월만 있음");
}
System.out.println(number + "월달 입니다.");
} catch (Exception e) {
e.printStackTrace();
return;
} finally {
System.out.println("2022년");
}
}
catch 블록 실행 후 실행됨
void printMonth(int number) {
try {
if (number > 12) {
throw new Exception("1월에서 12월만 있음");
}
System.out.println(number + "월달 입니다.");
} catch (Exception e) {
e.printStackTrace();
return;
}
System.out.println("2022년");
}
finally 블록 vs try-catch 블록 밖에 작성한 코드Anti Patterntry문에서 예외가 발생하지 않아도 return문이 실행되지 않고 finally문의 return문이 실행됨
public class AntiPattern {
int returnInFinally(boolean flag) {
try {
System.out.println("try");
if (flag) {
throw new RuntimeException();
}
return 1;
} catch (RuntimeException e) {
System.out.println("catch");
return 2;
} finally {
System.out.println("finally");
return 3;
}
}
public static void main(String[] args) {
AntiPattern anti = new AntiPattern();
System.out.println(anti.returnInFinally(false)); // 예외가 발생하지 않았는데도 return 3
}
}

프로그램 밖에서 발생하는 예외
프로그램 안에서 발생하는 예외
getMessage()
toString()
printStackTrace()
스택정보 출력public class ExceptionOverridingMethod {
public static void main(String[] args) {
ExceptionOverridingMethod obj = new ExceptionOverridingMethod();
obj.OverridingMethod3();
}
void OverridingMethod3(){
int[] Array = new int[5];
try{
Array[6] = 1;
} catch (Throwable e){ //exception 캐치함
System.out.println("---------getMessage/간단히---------");
System.out.println(e.getMessage()); //String 반환
System.out.println("---------toString/자세히---------");
System.out.println(e.toString()); //String 반환
System.out.println("---------printStackTrace/더 자세히 에러 내용 출력---------");
e.printStackTrace(); //예외 스택정보 출력
}
}
}
<결과>
--------getMessage/간단히---------
Index 6 out of bounds for length 5
---------toString/자세히---------
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 5
---------printStackTrace/더 자세히 에러 내용 출력---------
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 5
at chapter14.ExceptionOverridingMethod.OverridingMethod3(ExceptionOverridingMethod.java:14)
at chapter14.ExceptionOverridingMethod.main(ExceptionOverridingMethod.java:8)
UncheckedExceptionRuntimeException을 상속받은 예외컴파일 에러를 발생시키지 않음CheckedException나머지 예외컴파일 시 예외 체크를 함컴파일 에러를 발생시킬 수 있음JDK가 제공하는 예외가 있으면 기존것을 사용하는게 좋다. 정말 없어서 만들어야 할 경우에만 만들 것
CheckedException을 만들고 싶은 경우Exception을 상속UncheckedException을 만들고 싶은 경우RuntimeException을 상속커스텀 예외가 발생하게 된 cause를 같이 넘겨받아서 사용하기
public class MyException extends RuntimeException{
public MyException(String message, Throwable cause) {
super(message, cause);
}
}
public class ChangeException {
public static void main(String[] args) {
ChangeException ce = new ChangeException();
try {
ce.changeByMyException();
} catch (MyException e) {
System.out.println("내가 만든 예외로 던져짐");
System.out.println("원인인 " + e.getCause());
}
}
void throwIllegalArgumentException() {
throw new IllegalArgumentException();
}
void changeByMyException() {
try {
throwIllegalArgumentException();
} catch (IllegalArgumentException e) {
throw new MyException("내가 만든 예외로 바꿔서 던지기", e);
}
}
}
NullPointerExceptionString nullString = null;
nullString.toString();

ArrayIndexOutOfBoundsExceptionint[] arr = new int[3];
arr[4] = 1;

StringIndexOutOfBoundsExceptionString a = "0123";
a.charAt(4);

ArithmeticException산술 연산 시 잘못된 연산 조건을 사용할 시 발생
overflow
int a = 2_100_000_000; //21억
int b = 2_100_000_000; //21억
Math.addExact(a, b);

divide by zero
int a = 10;
int b = 0;
int c = a / b;

다운 캐스팅 시캐스팅 될 수 없는 자식 타입으로 캐스팅 될 때 발생class Parent {
}
class Child1 extends Parent {
}
class Child2 extends Parent {
}
public static void main(String args[]) {
Parent child = new Child1();
Child2 child2 = (Child2) child; // 에러 발생
}

매개변수로 잘못된 값을 입력할 때 발생ArrayList<Integer> numbers = new ArrayList<>(-1);

IllegalStatementException호출 시점이 잘못된 경우 발생@GetMapping("/add")
public void method1() {}
@GetMapping("/add")
public void method2() {}

여러 개의 catch 블락을 하나로 합칠 수 있는 기능
서로 다른 예외지만 처리하는 내용이 같은 경우 (catch 블락 내용이 같은 경우) 사용java 7 이후로 제공하는 기능public class MultiCatchBlock {
void originBlock(int flag) {
try {
if (flag == 1) {
throw new IllegalArgumentException();
}
if (flag == 2) {
throw new ArithmeticException();
}
if (flag == 3) {
throw new NullPointerException();
}
} catch (IllegalArgumentException e) {
System.out.println("예외 발생");
} catch (ArithmeticException e) {
System.out.println("예외 발생");
} catch (NullPointerException e) {
System.out.println("예외 발생");
}
}
void useMultiCatch(int flag) {
try {
if (flag == 1) {
throw new IllegalArgumentException();
}
if (flag == 2) {
throw new ArithmeticException();
}
if (flag == 3) {
throw new NullPointerException();
}
} catch (IllegalArgumentException | ArithmeticException | NullPointerException e) {
System.out.println("예외 발생");
}
}
}상속 관계가 있으면?컴파일 에러 발생
예외 처리 시
자원 해제를자동으로 처리해주는 기능
Closeable 인터페이스를 구현한 클래스만 가능java 7 이후로 제공하는 기능public class TryWithResource {
void originMethod() throws IOException {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.println("hi");
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("반드시 실행되어야 하므로 finally에 작성");
bw.close();
br.close();
}
}
void useTryWithResource() {
try ( -> 소괄호
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
) { -> 중괄호
System.out.println("hi");
} catch (IOException e) {
e.printStackTrace();
}
}
}
하나의 예외가 다른 예외를 발생시키는 경우
다른 예외를 발생시키는 이유는?하나의 큰 분류의 예외를 두고 세부적인 예외로 처리하기 위해
public class LoseMoneyException extends RuntimeException {
private String message = "돈을 잃어버려서 집을 못감";
@Override
public String getMessage() {
return message;
}
}
public class ShutDownBusException extends RuntimeException{
private String message = "버스가 끊겨서 집을 못감";
@Override
public String getMessage() {
return message;
}
}
public class ChainedException {
public static void main(String[] args) {
ChainedException ce = new ChainedException();
Scanner sc = new Scanner(System.in);
int cause = sc.nextInt();
try {
ce.goHome(cause);
} catch (CantGoHomeException e) {
System.out.println(e.getCause().getMessage());
}
}
void goHome(int flag) throws CantGoHomeException {
try {
if (flag == 1) {
throw new LoseMoneyException();
}
if (flag == 2) {
throw new ShutDownBusException();
}
System.out.println("집에 잘 감");
} catch (LoseMoneyException e) {
// 원인을 저장
throw new CantGoHomeException(e);
} catch (ShutDownBusException e) {
throw new CantGoHomeException(e);
}
}
}
CheckedException → UncheckedException 변환
RuntimeException으로 감싸서 UncheckedException으로 처리public void chained() {
try {
throw new IOException();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
예외 처리로 비지니스 로직을 처리하지 마라!
Throwable의 fillInStackTrace()가 원인이라고 함
→ 입력값을 조절하거나 if문을 사용하는 등 로직으로 처리할 수 있으면 하는게 좋음
multicatch block, try-with-resource, Chained Exception
커스텀 예외 생성 시 주의 사항
예외 처리 전략
오라클 공식 문서 참고