API 설계자가 메서드 선언에 예외를 명시하는 까닭은, 그 메서드를 사용할 때 적절한 조치를 취해달라고 말하는 것입니다. API 설계자의 목소리를 흘려버리지 맙시다. 안타깝게도 예외를 무시하기란 아주 쉽습니다. 해당 메서드 호출을 try 문으로 감싼 후 catch 블록에서 아무 일도 하지 않으면 끝입니다. // catch 블록을 비워두면 예외가 무시된다. try { ... } catch (SomeException e) { } 예외는 문제 상황에 잘 대처하기 위해 존재하는데 catch 블록을 비워두면 예외가 존재할 이유가 없어집니다. 비유하자면 화재경보를 무시하는 수준을 넘어 아예 꺼버려, 다른 누구도 화재가 발생했음을 알지 못하게 하는 것과 같습니다. 운이 좋아 별 탈이 없으면 다행이지만 끔찍한 참사로 ..
작업 도중 예외가 발생해도 그 객체는 여전히 정상적으로 사용할 수 있는 상태라면 멋지지 않습니까? CheckedException를 던진 경우라면 호출자가 오류 상태를 복구할 수 있을 테니 특히 더 유용할 것입니다. 일반화해 이야기하면, 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 합니다. 이러한 특성을 실패 원자적(failure-atomic)이라고 합니다. 메서드를 실패 원자적으로 만드는 방법은 다양합니다. 가장 간단한 방법은 불변 객체(아이템 17)로 설계하는 것입니다. 불변 객체는 태생적으로 실패 원자적입니다. 메서드가 실패하면 새로운 객체가 만들어지지는 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일은 결코 없습니다. 불변 객체의 상태는 생성 시점에 고정되어 절대..
예외를 잡지 못해 프로그램이 실패하면 자바 시스템은 그 예외의 스택 추적 정보를 자동으로 출력합니다. 스택 추적은 예외 객체의 toString 메서드를 호출해 얻는 문자열로, 보통은 예외의 클래스 이름 뒤에 상세 메시지가 붙는 형태입니다. 이 정보가 실패 원인을 분석해야 하는 프로그래머 혹은 사이트 신뢰성 엔지니어(SRE)가 얻을 수 있는 유일한 정보인 경우가 많습니다. 더구나 그 실패를 재현하기 어렵다면 더 자세한 정보를 얻기가 어렵거나 불가능합니다. 따라서 예외의 toString 메서드에 실패 원인에 관한 정보를 가능한 한 많이 담아 반환하는 일은 아주 중요합니다. 달리 말하면, 사후 분석을 위해 실패 순간의 상황을 정확히 포착해 예외의 상세 메시지에 담아야 합니다. 실패 순간을 포착하려면 발생한 예..
메서드가 던지는 예외는 그 메서드를 올바로 사용하는 데 아주 중요한 정보입니다. 따라서 각 메서드가 던지는 예외 하나하나를 문서화하는 데 충분한 시간을 쏟아야 합니다. (아이템 56) 검사 예외는 항상 따로따로 선언하고, 각 예외가 발생하는 상황을 자바독의 @throws 태그를 사용하여 정확히 문서화합시다. 공통 상위 클래스 하나로 뭉뚱그려 선언하는 일은 삼갑시다. 극단적인 예로 메서드가 Exception이나 Throwable을 던진다고 선언해서는 안 됩니다. 메서드 사용자에게 각 예외에 대처할 수 있는 힌트를 주지 못할뿐더러, 같은 맥락에서 발생할 여지가 있는 다른 예외들까지 삼켜버릴 수 있어 API 사용성을 크게 떨어뜨립니다. 이 규칙에 유일한 예외가 있다면 바로 main 메서드입니다. main은 오..
수행하려는 일과 관련 없어 보이는 예외가 튀어나오면 당황스러울 것입니다. 메서드가 저수준 예외를 처리하지 않고 바깥으로 전파해버릴 때 종종 일어나는 일입니다. 사실 이는 단순히 프로그래머를 당황시키는 데 그치지 않고, 내부 구현 방식을 드러내어 윗 레벨 API를 오염시킵니다. 다음 릴리스에서 구현 방식을 바꾸면 다른 예외가 튀어나와 기존 클라이언트 프로그램을 깨지게 할 수도 있는 것입니다. 이 문제를 피하려면 상위 계층에서는 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꿔 던져야 합니다. 이를 예외 번역(exception translation)이라 합니다. try { ... // 저수준 추상화를 이용한다. } catch (LowerLevelException e) { // 추상화 수준에 맞게 번..
숙련된 프로그래머는 그렇지 못한 프로그래머보다 더 많은 코드를 재사용합니다. 예외도 마찬가지로 재사용하는 것이 좋으며, 자바 라이브러리는 대부분 API에서 쓰기에 충분한 수의 예외를 제공합니다. 표준 예외를 재사용하면 얻는 게 많습니다. 그 중 최고는 여러분의 API가 다른 사람이 익히고 사용하기 쉬워진다는 것이죠. 많은 프로그래머에게 이미 익숙해진 규약을 그대로 따르기 때문입니다. 여러분의 API의 사용한 프로그램도 낯선 예외를 사용하지 않게 되어 읽기 쉽게 된다는 장점도 큽니다. 마지막으로, 예외 클래스 수가 적을수록 메모리 사용량도 줄고 클래스를 적재하는 시간도 적게 걸립니다. 가장 많이 재사용되는 예외는 IllegalArgumentException입니다. (아이템 49) 호출자가 인수로 부적절한 ..
CheckedException를 싫어하는 자바 프로그래머가 많지만 제대로 활용하면 API와 프로그램의 질을 높일 수 있습니다. 결과를 코드로 반환하거나 UnCheckedException를 던지는 것과 달리, CheckedException는 발생한 문제를 프로그래머가 처리하여 안전성을 높이게끔 해줍니다. 물론, CheckedException를 과하게 사용하면 오히려 쓰기 불편한 API가 됩니다. 어떤 메서드가 CheckedException를 던질 수 있다고 선언됐다면, 이를 호출하는 코드에서는 catch 블록을 두어 그 예외를 붙잡아 처리하거나 더 바깥으로 던져 문제를 전파해야만 합니다. 어느 쪽이든 API 사용자에게 부담을 줍니다. 더구나 CheckedException를 던지는 메서드는 스트림 안에서 직..
운이 없다면 언젠가 다음과 같은 코드와 마주칠지도 모릅니다. try { int i = 0; while(true) range[i++].climb(); } catch (ArrayIndexOutOfBoundsException e) {} 무슨 일을 하는 코드인지 모를 정도로 직관적이지 않습니다. (아이템 67) 이 코드는 배열의 원소를 순회하는데, 아주 끔찍한 방식으로 하고 있습니다. 무한루프를 돌다가 배열의 끝에 도달해 ArrayIndexOutOfBoundsException이 발생하면 끝을 내는 것이죠. 이 코드를 다음과 같이 표준적인 관용구대로 작성했다면 모든 자바 프로그래머가 곧바로 이해했을 겁니다. for (Mountain m : range) m.climb(); 🤔 그런데 예외를 써서 루프를 종료한 이유..
- Total
- Today
- Yesterday
- 이팩티브 자바
- 백준
- Spring
- kkoon9
- Kotlin
- 프로그래머스
- 객체지향
- Olympiad
- 테라폼
- Java
- 정규표현식
- 디자인 패턴
- Effective Java
- BAEKJOON
- Spring Boot
- 알고리즘
- 코테
- C++
- AWS
- 클린 코드
- 이펙티브 자바
- JPA
- node.js
- kotest
- 클린 아키텍처
- programmers
- BOJ
- 디자인패턴
- Algorithm
- MSA
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |