티스토리 뷰

예외란?
- 예외(Exception)는 프로그램 실행 중에 발생할 수 있는 예기치 않은 상황을 의미
- 사용자가 입력한 값이 예상치 못한 경우이거나, 파일이 존재하지 않는 경우 등이 있음
- 자바에서는 이러한 예외 상황을 처리하여 프로그램이 비정상적으로 종료되지 않도록 함
예외의 종류
체크 예외(Checked Exception)
- 컴파일 타임에 확인되며, 반드시 처리해야 하는 예외
- IOException: 파일 작업 중 오류 발생
- SQLException: 데이터베이스 작업 중 오류 발생
- ClassNotFoundException: 클래스를 찾을 수 없을 때 발생
언체크 예외(Unchecked Exception)
- 런타임에 발생하며, 처리하지 않아도 컴파일은 가능하지만 프로그램이 비정상 종료될 수 있음
- NullPointerException: 객체가 null인데 메서드나 필드에 접근하려고 할 때 발생
- ArrayIndexOutOfBoundsException: 배열의 잘못된 인덱스를 참조할 때 발생
- IllegalArgumentException: 메서드에 부적절한 인자를 전달할 때 발생
Error
- 시스템 레벨에서 발생하는 심각한 오류로 복구가 불가능함
- OutOfMemoryError: JVM 메모리가 부족할 때 발생
- StackOverflowError: 무한 재귀 호출로 스택이 초과될 때 발생
- VirtualMachineError: 가상 머신의 심각한 문제
예외 처리 방법
- 자바에서는 try-catch-finally 블록을 사용하여 예외를 처리
기본 구조
try {
// 예외가 발생할 가능성이 있는 코드
} catch (ExceptionType e) {
// 예외 처리 코드
} finally {
// 예외 발생 여부와 관계없이 항상 실행되는 코드 (선택적)
}
예제 코드
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class ExceptionExample {
public static void main(String[] args) {
try {
File file = new File("nonexistent.txt");
Scanner scanner = new Scanner(file);
} catch (FileNotFoundException e) {
System.out.println("파일을 찾을 수 없습니다: " + e.getMessage());
} finally {
System.out.println("프로그램이 종료됩니다.");
}
}
}
try-with-resources
- Java 7에서 도입된 기능으로, AutoCloseable 인터페이스를 구현한 객체를 자동으로 닫아주는 기능을 제공
- 이를 통해 리소스를 명시적으로 닫아주는 코드를 작성할 필요가 없으며, 코드 가독성과 안정성을 높일 수 있음
장점
- 코드 간결성
- 리소스를 명시적으로 닫는 finally 블록 작성 불필요
- 안정성
- 리소스를 닫지 않아 발생할 수 있는 문제 예방
- 가독성
- 코드가 더 읽기 쉬워지고 유지보수가 용이
내부 동작 원리
1. AutoCloseable 인터페이스
- try-with-resources에 사용되는 객체는 반드시 AutoCloseable 인터페이스를 구현해야 함
- 이 인터페이스는 close() 메서드를 정의하며, 리소스를 해제하는 역할
- 기존의 Closeable에 부모 인터페이스 AutoCloseable을 추가한 것
- 먼저 만들어진 인터페이스를 자식 클래스나 인터페이스에 사용하는 것이 일반적일 것이지만, Java 개발자들은 먼저 만들어진 Cloesable 인터페이스에 부모 인터페이스인 AutoCloesable을 추가함으로써 하위 호환성을 100% 달성함과 동시에 변경 작업에 대한 수고를 덜었다.
- 만약 Cloesable을 부모로 만들었다면 기존에 만들어준 클래스들이 모두 Cloesable이 아닌 AutoCloesable를 구현(implements) 하도록 수정이 필요했을 것이지만, 이러한 구조 덕분에 기존에 구현된 자원 클래스들 모두 try-with-resources가 사용가능해짐

public interface Closeable extends AutoCloseable {
public void close() throws IOException;
}
public interface AutoCloseable {
void close() throws Exception;
}
2. 컴파일러 변환
try-with-resources로 작성된 코드는 컴파일 시에 일반적인 try-finally 구조로 변환됨
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line = br.readLine();
System.out.println(line);
}
위 코드는 컴파일 후 다음과 같이 변환
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("file.txt"));
String line = br.readLine();
System.out.println(line);
} finally {
if (br != null) {
br.close(); // AutoCloseable의 close() 호출
}
}
3. 예외 처리
- 리소스를 닫는 과정에서 예외가 발생하더라도, try 블록에서 발생한 예외가 우선적으로 전달
- 닫는 과정에서 발생한 예외는 suppressed exception으로 저장되며, Throwable 객체의 getSuppressed() 메서드로 확인할 수 있음
try (MyResource resource = new MyResource()) {
throw new RuntimeException("Primary Exception");
}
만약 close() 메서드에서 예외가 발생했다면
- RuntimeException("Primary Exception")이 호출 스택에 남음
- close() 메서드에서 발생한 예외는 suppressed exception으로 추가
예외가 억제되는 구조
- Throwable.addSuppressed() 메서드를 통해 억제된 예외가 관리됩니다. 이로 인해 예외가 손실되지 않고 추적이 가능
사용 예
try-with-resources는 파일, 네트워크 소켓, 데이터베이스 연결 등 다양한 리소스 관리에 유용
파일 읽기
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
JDBC 연결
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM table")) {
while (rs.next()) {
System.out.println(rs.getString("column_name"));
}
} catch (SQLException e) {
e.printStackTrace();
}
주의사항
- AutoCloseable을 구현하지 않은 객체는 try-with-resources에 사용할 수 없음
- 리소스를 여러 개 선언할 경우, 선언 순서와 닫는 순서가 반대임을 유의하세요. 가장 마지막에 선언된 리소스부터 닫음
사용자 정의 예외
- 자바에서는 사용자가 필요에 따라 새로운 예외 클래스를 정의할 수 있음
사용자 정의 예외 코드
class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
public class CustomExceptionExample {
public static void main(String[] args) {
try {
validateAge(15);
} catch (CustomException e) {
System.out.println("예외 발생: " + e.getMessage());
}
}
public static void validateAge(int age) throws CustomException {
if (age < 18) {
throw new CustomException("나이는 18세 이상이어야 합니다.");
}
}
}
throw와 throws 키워드
throw
- 특정 예외를 발생시킬 때 사용
- 예) throw new IllegalArgumentException("잘못된 값입니다.");
throws
- 메서드가 어떤 예외를 던질 수 있는지 선언
public void readFile() throws IOException { File file = new File("test.txt"); Scanner scanner = new Scanner(file); }
심화 개념
멀티 캐치 블록
- 하나의 catch 블록에서 여러 예외를 처리할 수 있음
try {
// 예외 발생 가능 코드
} catch (IOException | NullPointerException e) {
System.out.println("예외 처리: " + e.getMessage());
}
예외의 체인(Cause)
- 예외는 다른 예외를 원인으로 가질 수 있음
try {
throw new IllegalArgumentException("잘못된 값", new NullPointerException("Null 발생"));
} catch (Exception e) {
System.out.println("예외 원인: " + e.getCause());
}
public class ExceptionChaining {
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println("최종 예외 처리: " + e.getMessage());
}
}
public static void methodA() throws Exception {
try {
methodB();
} catch (Exception e) {
throw new Exception("MethodA에서 예외 발생", e);
}
}
public static void methodB() throws Exception {
throw new Exception("MethodB에서 예외 발생");
}
}
면접 대비 질문
Q1. 자바의 예외 처리란 무엇이며, 왜 필요한가요?
모범 답안:
예외 처리란 프로그램 실행 중에 발생할 수 있는 예외 상황을 감지하고 적절히 대응하여 프로그램이 비정상적으로 종료되지 않도록 하는 메커니즘입니다. 자바에서는 try-catch 블록, throws 키워드 등을 통해 예외를 처리합니다. 예외 처리는 시스템의 안정성을 높이고, 사용자에게 의미 있는 피드백을 제공하며, 비정상 종료를 방지하는 데 중요합니다
Q2. Checked Exception과 Unchecked Exception의 차이점은 무엇인가요?
모범 답안:
- Checked Exception은 컴파일러가 예외 처리를 강제하는 예외로, 파일 작업(IOException), 데이터베이스 연결(SQLException) 등과 같이 예측 가능한 예외 상황에서 발생합니다. 반드시 try-catch로 처리하거나 throws로 명시해야 합니다.
- Unchecked Exception은 RuntimeException을 상속받는 예외로, 런타임 시 발생하며 컴파일러가 처리 여부를 확인하지 않습니다. 주로 프로그래밍 오류(예: NullPointerException, ArrayIndexOutOfBoundsException)와 관련됩니다.
Q3. 자바에서 finally 블록은 언제 사용하며, 특징은 무엇인가요?
모범 답안:
finally 블록은 예외 발생 여부와 상관없이 항상 실행되는 코드 블록입니다. 주로 파일, 네트워크, 데이터베이스 리소스와 같은 외부 자원의 정리를 위해 사용됩니다.
- finally는 예외가 발생하거나 return이 호출되더라도 실행됩니다.
- 단, JVM이 종료되거나 System.exit()가 호출되면 실행되지 않을 수 있습니다.
Q4. 커스텀 예외(Custom Exception)를 만들어야 하는 경우와 방법은?
모범 답안:
커스텀 예외는 표준 예외로 처리하기 어렵거나 특정 도메인 로직에 맞는 의미 있는 예외를 만들고 싶을 때 사용합니다. 예를 들어, 사용자 인증 실패와 같은 특정 상황을 처리하기 위해 커스텀 예외를 작성할 수 있습니다.
public class UserNotFoundException extends Exception {
public UserNotFoundException(String message) {
super(message);
}
}
사용 예시
if (user == null) {
throw new UserNotFoundException("User not found in the system");
}
Q5. 자바에서 예외 체이닝(Exception Chaining)이란 무엇인가요?
모범 답안:
예외 체이닝은 한 예외가 다른 예외의 원인이 될 때 이를 연결하는 기법입니다. 자바에서는 Throwable 클래스의 생성자를 사용하여 예외를 체인으로 연결할 수 있습니다.
이 기법은 로그에서 원인을 추적하거나, 원래 예외를 캡슐화하여 사용자에게 상세 정보를 숨길 때 유용합니다.
예시
try {
someMethod();
} catch (IOException e) {
throw new RuntimeException("An error occurred while processing", e);
}
Q6. Checked Exception이 없으면 안 되는 이유를 설명해보세요.
모범 답안:
Checked Exception은 개발자에게 컴파일 시점에 예외 처리 의무를 부여하여 중요한 예외 상황을 간과하지 않도록 강제합니다. 예를 들어, 파일 작업에서 발생할 수 있는 IOException을 처리하지 않으면 데이터 손실이나 시스템 오류가 발생할 수 있습니다. 이러한 강제성은 시스템의 안정성과 신뢰성을 높이는 데 기여합니다.
Q7. try-catch-finally 블록에서 finally 블록의 코드가 항상 실행되지 않는 경우가 있나요?
모범 답안:
finally 블록은 거의 항상 실행되지만, 예외적인 경우도 있습니다. 예를 들어,
- System.exit(0)이 호출된 경우.
- JVM이 종료된 경우.
- finally 블록 내부에서 무한 루프 또는 심각한 오류가 발생한 경우.
예시
try {
System.exit(0); // finally 블록 실행되지 않음
} finally {
System.out.println("This won't be printed");
}
Q8. catch 블록에서 또 다른 예외가 발생하면 어떻게 되는지 설명하세요.
모범 답안:
catch 블록에서 예외가 발생하면 기존 예외는 무시되고 새로 발생한 예외가 처리되지 않은 채로 던져집니다. 이런 상황은 디버깅을 어렵게 만들 수 있으므로, catch 블록 내에서 예외 처리를 신중하게 해야 합니다.
예시
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
throw new NullPointerException("New exception in catch block");
}
Q9. 예외 처리를 남발하면 성능에 어떤 영향을 미칠 수 있나요?
모범 답안:
예외는 일반적인 코드 흐름을 벗어나기 때문에 예외를 자주 발생시키거나, 성능이 중요한 코드에서 남용하면 성능 저하를 유발할 수 있습니다. 특히 스택 추적 정보를 생성하는 데 비용이 많이 들기 때문에, 빈번한 예외 발생은 성능 병목을 일으킬 수 있습니다. 따라서 예외는 예외적인 상황에서만 사용해야 하며, 정상적인 로직을 처리하기 위해 사용하면 안 됩니다.
Q10. try-with-resources와 기존 finally 블록의 차이점을 설명해보세요.
모범 답안:
try-with-resources는 자바 7에서 도입된 기능으로, AutoCloseable 인터페이스를 구현한 리소스(예: 파일, 데이터베이스 연결)를 자동으로 닫아줍니다.
- 기존 finally 블록은 개발자가 명시적으로 리소스를 닫아야 했지만, try-with-resources는 리소스의 수명 주기를 더 간결하고 안전하게 관리합니다.
- 예외가 발생해도 리소스를 자동으로 해제하여 메모리 누수를 방지합니다.
예시
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
Q11. throw와 throws의 차이점은 무엇인가요?
모범 답안:
- throw는 특정 예외를 발생시키기 위해 사용되는 키워드입니다.
예: throw new IOException("File not found"); - throws는 메서드 선언부에서 해당 메서드가 던질 수 있는 예외를 선언할 때 사용됩니다.
예: public void readFile() throws IOException { ... }
Q12. 예외 처리를 너무 많이 사용하면 코드 품질에 어떤 영향을 미칠 수 있나요?
모범 답안:
예외를 남용하면 코드 가독성과 유지보수성이 떨어질 수 있습니다.
- 너무 많은 try-catch 블록이 코드의 핵심 로직을 가리게 되어 읽기 어렵게 만듭니다.
- 로직과 예외 처리를 분리하지 않으면 복잡성이 증가합니다.
- 예외를 정상적인 흐름 제어로 사용하는 것은 성능 저하와 비효율을 초래합니다.
따라서 적절한 범위와 수준에서 예외 처리를 적용하고, 정상적인 로직은 조건문 등으로 처리하는 것이 좋습니다.
Q13. Checked Exception 대신 Unchecked Exception을 사용하는 것이 더 좋은 경우는 언제인가요?
모범 답안:
Unchecked Exception은 주로 프로그래밍 오류를 나타낼 때 사용됩니다. 예를 들어:
- 입력값 검증 실패(IllegalArgumentException)
- 객체가 null인 상태에서 메서드를 호출하려는 시도(NullPointerException)
이런 상황은 프로그래머의 실수로 발생하며, 호출자가 이를 반드시 처리하도록 강제하지 않아도 됩니다.
반대로, Checked Exception은 예상 가능한 외부 리소스 오류(예: 파일 또는 네트워크 작업)와 같이 반드시 처리해야 할 경우에 적합합니다.
Q14. 리소스 해제를 위해 try-with-resources를 사용하는 것이 기존 finally 블록보다 나은 이유는?
모범 답안:
try-with-resources는 코드 가독성을 높이고, 리소스 해제의 안전성을 보장합니다.
- 자동 리소스 해제: AutoCloseable 인터페이스를 구현한 객체를 자동으로 닫아줍니다.
- 예외 누수 방지: finally 블록에서 예외가 발생할 경우 원래의 예외가 숨겨질 수 있는 문제를 방지합니다.
- 가독성: 코드가 간결하고 직관적입니다.
예시
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
Q15. Java 7에서 추가된 try-with-resources 개선 사항은 무엇인가요?
모범 답안:
Java 7에서는 try-with-resources에 개선 사항이 도입되어, 기존에 선언된 리소스를 다시 사용할 수 있습니다. final 또는 effectively final 변수라면 리소스를 새로 선언하지 않고도 사용할 수 있습니다.
예시
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
try (br) {
System.out.println(br.readLine());
}
이로 인해 코드 중복이 줄어들고 간결해졌습니다.
Q16. 예외가 발생한 상황에서 시스템 상태를 일관성 있게 유지하려면 어떻게 해야 하나요?
모범 답안:
예외가 발생하더라도 시스템 상태를 일관성 있게 유지하려면 아래 전략을 사용할 수 있습니다:
- 트랜잭션 롤백: 데이터베이스 작업에서는 예외 발생 시 트랜잭션을 롤백하여 변경 사항을 취소합니다.
- 리소스 정리: 파일, 네트워크, 메모리와 같은 자원을 반드시 해제합니다(try-with-resources 사용).
- 상태 복구: 예외 처리 후 시스템을 이전의 안정적인 상태로 복원합니다.
- 불변 객체 사용: 변경 가능한 상태를 최소화하여 예외가 발생하더라도 영향을 줄이는 설계를 합니다.
Q17. catch 블록이 비어 있는 코드의 문제점을 설명하고 개선 방안을 제안해 보세요.
모범 답안:
catch 블록이 비어 있으면 예외가 발생했음을 알리지 않으므로 문제를 디버깅하거나 시스템의 비정상 동작을 감지하기 어렵습니다.
예시
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
// 아무것도 하지 않음
}
이 문제를 해결하려면
- 예외를 로깅하여 발생 원인을 추적할 수 있도록 합니다.
- 필요하다면 적절히 복구하거나 호출자에게 재전달(throw)합니다.
- 예외를 처리할 수 없다면 최소한 로그를 남깁니다.
Q18. 다중 catch 블록을 사용할 때 주의할 점은 무엇인가요?
모범 답안:
다중 catch 블록을 사용할 때는 아래 사항에 유의해야 합니다:
- 구체적인 예외부터 처리: 특정 예외를 먼저 처리하고, 더 일반적인 예외를 나중에 처리해야 합니다.
예: NullPointerException → RuntimeException 순서로 작성. - 코드 중복 방지: 동일한 처리가 필요한 경우 공통 로직을 한 곳에 통합.
- Java 7 이상의 멀티 캐치 사용: 여러 예외를 하나의 catch 블록에서 처리할 수 있습니다.
try { // 코드 } catch (IOException | SQLException e) { e.printStackTrace(); }
Q19. 만약 팀원이 모든 예외를 한 곳에서 처리하기 위해 catch (Exception e)를 사용한다면 어떻게 설득하시겠습니까?
모범 답안:
catch (Exception e)는 모든 예외를 무작위로 잡기 때문에:
- 특정 예외의 의미를 모호하게 만들어 디버깅이 어려워질 수 있습니다.
- 필요하지 않은 예외까지 잡아 버려 예외 상황을 놓칠 위험이 있습니다.
- 재사용성과 유지보수성이 떨어집니다.
해결 방안:
- 구체적인 예외를 개별적으로 처리하여 각 상황에 적합한 대응을 하도록 제안합니다.
- 로깅과 같은 공통 처리가 필요하면 별도의 예외 처리 유틸리티를 작성할 것을 권장합니다.
Q20. 성능을 고려할 때, try-catch 블록을 어디에 배치하는 것이 좋은가요?
모범 답안:
try-catch 블록은 예외가 자주 발생하는 코드 주변에 최소한으로 배치해야 합니다.
- 예외가 발생하지 않을 코드까지 포함하면 불필요한 오버헤드가 증가할 수 있습니다.
- 따라서 정확히 예외가 발생할 가능성이 있는 부분만 감싸도록 설계합니다.
예시
try {
int result = 10 / 0; // 예외 발생 가능
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
}
// 예외가 발생하지 않을 코드
System.out.println("This runs normally.");
Reference
https://mangkyu.tistory.com/217 [MangKyu's Diary:티스토리]
'Language > Java' 카테고리의 다른 글
| [JAVA] Generics에 대하여 (0) | 2025.01.14 |
|---|---|
| [JAVA] 람다와 함수형 인터페이스 (2) | 2025.01.13 |
| [JAVA] Iteration과 Stream API 그리고 정렬 (0) | 2025.01.09 |
| [JAVA] Collection에 대하여 (0) | 2025.01.09 |
| [JAVA] JVM에 대하여 (1) | 2025.01.08 |
- Total
- Today
- Yesterday
- i/o모델
- restful api
- k8
- 자바
- 분할 정복
- 우아한 테크코스
- MSA
- 그리디 알고리즘
- CPU 스케줄링
- 알고리즘
- HTTP
- TRIE
- 데이터베이스
- 프리코스
- B+Tree
- 운영체제
- 백트래킹
- Spring Boot
- Java
- 우테코
- 자료구조
- 해시 테이블
- Spring
- devops
- 스프링
- 우선순위 큐
- CS
- 탐색 알고리즘
- 동적 프로그래밍
- db
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |