Java 기초부터 마스터까지 — 7화
예외와 try-with-resources로 실패 처리하기
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
파일, 네트워크, 입력 값은 언제든 실패할 수 있다. Java의 예외와 자원 관리 문법은 실패를 전달하고 어떤 경로에서도 자원을 닫기 위해 사용한다.
예외 전달하기
public Settings loadSettings(Path path) throws IOException {
String json = Files.readString(path);
return parser.parse(json);
}
호출자가 복구 방법을 결정해야 한다면 예외를 억지로 내부에서 숨기지 않는다. 문맥을 추가할 때는 원래 예외를 원인으로 보존해야 한다.
try {
settings = loadSettings(path);
} catch (IOException error) {
logger.warn("settings load failed", error);
settings = Settings.defaults();
}
처리할 수 있는 예외만 잡는다. 모든 Exception을 잡고 아무 일도 하지 않으면 실제 버그까지 정상처럼 진행될 수 있다.
try-with-resources
public List<String> readLines(Path path) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(path)) {
return reader.lines().toList();
}
}
AutoCloseable을 구현한 객체를 괄호 안에 만들면 블록이 끝날 때 close가 호출된다. 정상 반환과 예외 경로 모두에서 파일 핸들이 정리된다.
검사 예외와 런타임 예외
검사 예외는 메서드 선언이나 catch로 처리 여부를 드러낸다. IllegalArgumentException 같은 런타임 예외는 잘못된 호출 계약이나 프로그래밍 오류에 자주 사용한다.
둘 중 어느 것이 무조건 좋은 것이 아니라 호출자가 복구할 수 있는 실패인지가 기준이다.
상태를 완성한 뒤 교체하기
Settings loaded = loadSettings(path);
currentSettings = loaded;
새 값을 완전히 만든 뒤 필드에 넣으면 로딩 중 실패해도 기존 설정은 유지된다. 예외 설계는 catch를 많이 만드는 일이 아니라 실패했을 때 자원과 객체 상태가 어떻게 남는지 정하는 일이다.