✔ 단순한 문법 오류가 아닌 실행 중간에 발생하는 정상적이지 않은 상황
을 의미
✔ Exception과 Error는 다름
✔ 자바는 예외처리 매커니즘을 제공
예시
👉 line 14에서 발생한 예외
발생한 예외 문구를 콘솔창에 띄워주는 주체 = JVM
문제가 발생한 지점에서 프로그램을 종료시키고 해당 클래스의 어느 라인에서 어떤 에러가 발생했는지 알려줌 (자바의 기본 예외처리 매커니즘)
💡 예제
1️⃣ try~catch 문 적용 전
public class TryCatchTest {
public static void main(String[] args) {
int a = 1/0;
System.out.println(a);
}
}
👉 에러가 발생 (에러 발생시키는 주체는 JVM)
2️⃣ try~catch 문 적용 후
public class TryCatchTest {
public static void main(String[] args) {
int a = 0; // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
try {
a = 1/0;
} catch (Exception e) {
}
System.out.println("트라이캐치 밖");
System.out.println(a);
}
}
👉 프로그램이 죽지 않고 에러 없이 잘 실행됨
3️⃣ catch문 활용
public class TryCatchTest {
public static void main(String[] args) {
int a = 1; // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
int b = 0;
try {
b = a / b;
System.out.println(a);
} catch (Exception e) {
System.out.println("캐치" + a);
System.out.println("캐치" + b);
}
System.out.println("try~catch~ 밖");
}
}
👉 try문이 아닌 catch문 내의 소스 코드 실행
4️⃣ catch 문의 Exception 객체 활용하기
public class TryCatchTest {
public static void main(String[] args) {
int a = 1; // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
int b = 0; // 에러 사항 (원인)
try {
b = a / b;
System.out.println("트라이 안" + a);
} catch (Exception e) {
e.printStackTrace();
System.out.println("캐치" + a);
System.out.println("캐치" + b);
}
System.out.println("try~catch~ 밖");
System.out.println(a);
}
}
👉 디버깅을 위한 e.printStackTrace()
를 이용하여 어떤 에러가 발생하였는지 확인 가능
👉 catch 문의 () 안에 Exception객체는 ArithmeticException객체로 대신 사용할 수 있음 (다형성)
👉 객체를 따로 생성해주지 않아도 사용가능한 이유는 JVM이 자동으로 생성해주기 때문
5️⃣ finally 활용
public class TryCatchTest {
public static void main(String[] args) {
int a = 1; // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
int b = 0; // 에러 사항 (원인)
try {
b = a / b;
System.out.println("트라이 안" + a);
} catch (Exception e) {
e.printStackTrace();
System.out.println("캐치" + a);
System.out.println("캐치" + b);
} finally {
System.out.println("파이널리 입니다.");
}
System.out.println("try~catch~ 밖");
System.out.println(a);
}
}
👉 에러와 상관없이 무조건 실행되는 코드를 finally
문 안에 넣어줌
6️⃣ e.getMessage()
와 e.printStackTrace()
차이
import java.util.Scanner;
public class ExceptionCase3 {
public static void main(String[] args) {
Scanner kb = new Scanner(System.in);
try {
System.out.print("a/b... a? ");
int n1 = kb.nextInt();
System.out.print("a/b... b? ");
int n2 = kb.nextInt();
System.out.printf("%d / %d = %d \n", n1, n2, n1 / n2);
} catch (ArithmeticException e) {
System.out.println("----e.getMessage()-----");
System.out.println(e.getMessage()); // 어떤 에러인지 메세지로 간단히 뿌려줌
System.out.println();
System.out.println("-----e.printStackTrace()------ ");
e.printStackTrace();
} finally {
System.out.println("무조건 실행");
}
System.out.println("Good bye~~!");
}
}
7️⃣ catch문을 2개 이상 사용해보기
import java.util.InputMismatchException;
import java.util.Scanner;
public class ExceptionCase3 {
public static void main(String[] args) {
Scanner kb = new Scanner(System.in);
try {
System.out.print("a/b... a? ");
int n1 = kb.nextInt();
System.out.print("a/b... b? ");
int n2 = kb.nextInt();
System.out.printf("%d / %d = %d \n", n1, n2, n1 / n2);
} catch (ArithmeticException e) {
System.out.println("----e.getMessage()-----");
System.out.println(e.getMessage()); // 어떤 에러인지 메세지로 간단히 뿌려줌
System.out.println();
System.out.println("-----e.printStackTrace()------ ");
e.printStackTrace();
} catch (InputMismatchException e) {
System.out.println("문자가 입력되었습니다.");
System.out.println(e.getMessage());
} catch (Exception e) { // 다형성의 원리로 위의 에러에 해당되지 않는 예외들은 모두 여기로 넘어옴
e.printStackTrace();
System.out.println(e.getMessage());
}finally {
System.out.println("무조건 실행");
}
System.out.println("Good bye~~!");
}
}
⚠ Exception을 이용한 catch문이 가장 위에 있다면 Exception으로 모든 에러를 잡아내서 그 밑의 예외 처리 코드들이 Dead Code가 되기 때문에 컴파일 에러 발생
✔ 메서드에서 처리해야 할 하나 이상의 예외를 호출한 곳으로 전달 (처리를 위임)
👉 예외가 없어지는 것❌ 단순히 전달
👉 예외를 전달받은 메서드는 다시 예외 처리의 책임이 발생함
💡 예제
import java.io.IOException;
// throws
public class ThrowsTest {
public static void main(String[] args) throws IOException {
byte[] byteArr = {'a', 'b', 'c'}; // 숫자로 변환되어 배열에 저장됨
System.out.write(byteArr);
}
}
System.out.write()
란?@Override
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
👉 byte를 출력하거나 아스키 코드 등을 출력할 때 쓰이는 메소드✔ write함수는 IOException
을 throws
를 이용하여 예외처리를 하였으므로
write 함수를 호출한 main() 함수에도 마찬가지로 IOException을 위한 예외처리를 해주어야 함
✔ 위의 코드처럼 main 함수에서 throws
를 이용한 예외처리를 할 경우, (main함수를 호출하는)
JVM이 예외처리를 받아 콘솔에 발생한 예외 메세지를 띄우고 프로그램을 종료하게 됨
✔ 자바에서는 예외를 클래스를 통해 관리한다.
✔ 모든 예외 클래스는 java.lang패키지의 Exception 클래스의 상속을 받는다.
✔ 크게 두 종류로 구분할 수 있다.
✔ 체크 예외는 컴파일 과정에서 예외를 검사하고 예외 처리를 하지 않으면 컴파일 오류가 발생된다.
✔ 컴파일 시 발생 가능한 예외에 대한 대부분의 처리가 가능하다.
✔ 체크 예외는 Exception 클래스를 상속받으나 RuntimeException 클래스는 상속받지 않는다.
✔ 언체크 예외는 컴파일 시 예외를 검사하지 않는다.
✔ 따라서 예외 처리를 하지 않아도 컴파일이 가능하다.
✔ 하지만 컴파일이 가능하다고 해서 예외처리가 필요 없는 것이 아니다.
✔ 체크 예외는 개발자가 처리하지 않아도 컴파일 과정에서 처리가 가능하다.
✔ 언체크 예외는 개발자의 경험에 따라서 예외가 발생 가능한 코드에 대해서 예외 처리를 알아서 해줘야 한다.
public static void main(String[] args) {
Path file = Paths.get("C:\\javastudy\\Simple.txt");
BufferedWriter writer = null;
try {
writer = Files.newBufferedWriter(file); // IOException 발생 가능
writer.write('A'); // IOException 발생 가능
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) // IOException 발생 가능
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}