예외(Exception)이란?
- 사용자의 잘못된 조작 또는 개발자의 코딩으로 인해 발생하는 프로그램 오류
예외 처리가 필요한 이유?
int result = 10 / 0;
System.out.println("계산 결과: " + result); // ❌ 절대 안 나옴
- 0으로 나누는 순간 에러가 나고 프로그램이 멈춰버린다.
- 그 뒤에 코드들은 아예 실행조차 안된다.
- 따라서 에러가 나더라도 프로그램이 죽지 않도록 try-catch라는 도구를 써서 예외를 안전하게 처리해야한다.
try-catch?
try {
// 문제가 생길 수 있는 코드
int result = 10 / 0;
System.out.println("결과: " + result); // ❌ 여긴 실행 안 됨
} catch (ArithmeticException e) {
// 문제가 생겼을 때 실행되는 부분
System.out.println("⚠️ 에러 발생: 0으로 나눌 수 없어요!");
}
이렇게 하면 에러가 나도 프로그램이 멈추지 않고 원하는 메시지를 출력하게 된다.
다중 try-catch
package db.dbEx2;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class StringTest {
static Connection conn = null;
static String id = "scott";
static String pw = "tiger";
static String url = "jdbc:oracle:thin:@localhost:1521/xe";
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.OracleDriver");
conn = DriverManager.getConnection(url, id, pw);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
출처: https://yat-ong.tistory.com/entry/Java다중-Try-Catch [주관적인 블로그:티스토리]
package db.dbEx2;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class StringTest {
static Connection conn = null;
static String id = "scott";
static String pw = "tiger";
static String url = "jdbc:oracle:thin:@localhost:1521/xe";
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.OracleDriver");
conn = DriverManager.getConnection(url, id, pw);
}
catch (SQLException | ClassNotFoundException e ) {
e.printStackTrace();
}
catch(Exception e) {
}
}
}
출처: https://yat-ong.tistory.com/entry/Java다중-Try-Catch [주관적인 블로그:티스토리]
- 예외 처리를 하다보면 수많은 try-catch 절을 만나게 된다.
- 하지만 이걸 또 각각 try-catch 절로 묶어버리면 코드가 쓸 데 없이 지저분해보이고 길어지게 된다.
- 이럴 때 중복되는 구절을 최대한 없애며 코드는 최대한 간결하며 명시적으로 작성할 수 있다.
- 유의할 점으로는 상위 예외 클래스가 catch절 상단에 와서는 안된다.
- 상위 예외 클래스일수록 하단에 위치해야하고 하위 클래스 예외는 상단으로 와야한다.
- 만약 상위 예외 클래스가 상단에 위치하면 Unreachable catch block for SQLException. It is already by the catch block for Exception 오류가 발생
- Java 7 이상부터는 하나의 catch 절에 |연산자를 사용해서 하나의 Catch 절에 2개의 Exception을 기재할 수 있다.
Checked 예외 vs Unchecked 예외
Checked Exception (컴파일러가 검사)
FileReader fr = new FileReader("없는파일.txt");
try {
FileReader fr = new FileReader("없는파일.txt");
} catch (FileNotFoundException e) {
System.out.println("파일이 없어요!");
}
- 예외 처리를 안 하면 컴파일 에러
무조건 try-catch 해야한다.
- 파일이 없을 수도 있으니까 Java가 꼭 예외 처리하라고 강요.
- 예 : 파일 읽기, 네트워크
(IOException, SQLException)
Checked Exception 예시
일반 예외 |
발생 이유 |
ClassNotFoundException |
존재하지 않는 클래스를 사용하려고 할 때 발생 |
InterruptedException |
인터럽트 됐을 때 발생 |
NoSuchFieldException |
클래스가 명시한 필드를 포함하지 않을 때 발생 |
NoSuchMethodException |
클래스가 명시한 메서드를 포함하지 않을 때 발생 |
IOException |
데이터 읽기 같은 입출력 문제가 있을 때 발생 |
Unchecked Exception (컴파일러가 검사 안 함)
int num = 10 / 0; // ArithmeticException
String s = null;
s.length(); // NullPointerException
- 코드 쓸 땐 문제 없어 보여도, 실행할 때 문제 생김
- 이런 건 꼭 try-catch 안 해도 컴파일은 된다.
하지만 실행하면 프로그램은 끝난다.
- 예 : 0으로 나누기, null 접근
(NullPointerException, ArrayIndexOutOfBoundsException)
Unchecked Exception 예시
실행 예외 |
발생 이유 |
ArithmeticException |
0으로 나누기와 같은 부적절한 산술 연산을 수행할 때 발생 |
IllegalArgumentException |
메서드에 부적절한 인수를 전달할 때 발생 |
IndexOutOfBoundsException |
배열, 벡터 등에서 범위를 벗어난 인덱스를 사용할 때 발생 |
NoSuchElementException |
요구한 원소가 없을 때 발생 |
NullPointerException |
null 값을 가진 참조 변수에 접근할 때 발생 |
NumberFormatException |
숫자로 바꿀 수 없는 문자열을 숫자로 변환하려 할 때 발생 |
try-catch-finally의 흐름
try {
System.out.println("파일을 엽니다!");
// 파일 읽는 코드
throw new Exception("읽는 도중 오류 발생!");
} catch (Exception e) {
System.out.println("🚨 오류: " + e.getMessage());
} finally {
System.out.println("🧹 파일을 닫습니다!");
}
파일을 엽니다!
🚨 오류: 읽는 도중 오류 발생!
🧹 파일을 닫습니다!
- finally : 예외가 나든 안 나든 무조건 마지막에 실행되는 블록
정리(clean-up) 용도로 아주 유용하다.
예외 직접 만들기
예시 상황 : 나이 입력 받는 프로그램인데, 0살 이하나 200살 이상을 입력하면 안 되게 하기
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message); // 예외 메시지 전달
}
}
public class AgeValidator {
public static void checkAge(int age) throws InvalidAgeException {
if (age <= 0 || age > 200) {
throw new InvalidAgeException("❌ 나이 범위가 올바르지 않아요!");
} else {
System.out.println("✅ 나이 확인 완료: " + age + "세");
}
}
public static void main(String[] args) {
try {
checkAge(250); // ❗ 잘못된 나이
} catch (InvalidAgeException e) {
System.out.println("에러 발생: " + e.getMessage());
}
}
}
에러 발생: ❌ 나이 범위가 올바르지 않아요!
throws vs throw
throw
throw new IllegalArgumentException("잘못된 값!");
- 직접 예외를 발생시킬 때 쓴다.
- 예외를 던진다.
- 코드 안에서 사용한다.
throws
public void readFile() throws IOException {
// 파일 읽는 코드
}
- 이걸 사용하는 쪽에서는 꼭 try-catch 하거나 다시 throws 해야한다.
- 함수 옆에 서서, 이 함수 쓸 땐 예외 처리 해달라고 말하는 것
- 메서드 옆에서 사용한다.