핵심 요약 멀리 스레드 환경에서 가변 데이터를 공유할 때는 데이터의 일관성과 안정성을 위해 동기화를 사용하라. 데이터를 동기화하지 않으면 에측할 수 없는 결과나 안전 실패(safe failure)가 발생할 수 있다. 최적의 성능과 안정성을 위해 가변 데이터는 가능한 한 단일 스레드 내에서만 사용하거나, 필요한 부분만 동기화하라. 동기화의 기능 배타적 실행 (Exclusive Execution) synchronized 키워드는 해당 메소드나 블록을 한 번에 하나의 스레드만 실행할 수 있도록 보장한다. 동기화된 메소드를 사용하면, 한 스레드가 객체의 상태를 변경하는 도중에 다른 스레드가 해당 객체의 상태를 읽거나 변경하는 것을 방지할 수 있다. 즉, 동기화를 통해 객체의 상태가 항상 일관된 상태를 유지하도록..
이번 절의 내용은 검사와 비검사 예외에 똑같이 적용된다. ✍ catch 블록을 비워두지 말자. 메소드에서 발생하는 예외를 무시하면, 그 메소드가 의도한대로 동작하지 않을 수 있고, 이로 인한 잠재적인 문제가 발생할 수 있다. 예시 1 - FileInputStream close 메소드 : 예외를 무시해도 되는 경우 FileInputStream은 파일에서 데이터를 읽기 위한 입력 전용 스트림이다. 즉, 파일의 상태를 변경시키지 않는다. 따라서 이 스트림을 닫는 도중 예외가 발생해도 파일에 대한 복구 작업은 필요하지 않다. @Slf4j public class Main { public void readFile() { File file = new File("a.txt"); try (FileInputStream f..
핵심 요약 실패 원자성은 메소드 호출이 실패하더라도 해당 객체의 상태를 변경하지 않아야 함을 나타낸다. 실패 원자성을 달성하기 위해 불변 객체 사용, 유효성 검사, 임시 구조 사용, 복구 코드 사용 등을 이용하자. 실패 원자성을 항상 보장하기는 어렵지만, 그렇지 않을 경우 API 문서에 명시해야 한다. 실패 원자성(Failure Atomicity) ✍ 호출된 메소드가 실패하더라도 해당 객체는 메소드 호출 전 상태를 유지해야 한다. 위와 같은 특성을 실패 원자성이라고 한다. 실패 원자성은 시스템의 안정성, 성능, 신뢰성을 향상시키는 데 필수적이다. 메소드를 실패 원자적으로 만드는 방법 방법 1 | 불변 객체 사용 : 불변 객체로 설계한다. (item 17) 불변 객체는 생성 이후 절대 변하지 않으므로 자연..
핵심 요약 스택 추적은 예외 발생 시점의 메소두 호출 정보를 제공하여 디버깅을 돕는다. 예외 메시지에는 관련 매개변수와 필드 정보를 포함하여 구체적인 실패 원인을 알 수 있게 해야 한다. 예외 클래스를 확장하고, 필요한 상세 정보를 얻기 위한 접근자 메소드를 제공하는 것이 좋다. 스택 추적(Stack Trace) 프로그램이 실행되면서 메소드 호출이 일어날 때마다 해당 메소드의 정보가 스택에 쌓인다. 이때, 프로그램에서 예외가 발생하면 그 시점의 호출 스택을 표시하는 정보를 "스택 추적"이라고 한다. ex. 예외가 발생한 순간의 메소드 호출 순서, 위치 정보, 관련 파일명 등 예외가 발생하고 해당 예외를 잡아내지 못하면, JVM은 그 예외의 스택 추적 정보를 자동으로 콘솔에 출력한다. 예외 객체의 toSt..
핵심 요약 검사 예외는 반드시 문서화해야 한다 자바독의 @throws 태그와 메소드 선언의 throws를 선언하자. 비검사 예외도 웬만하면 문서화하자. 자바독의 @throws 태그만 사용하면 된다. 검사 예외 : 검사 예외는 반드시 문서화해야 한다. 메소드가 던지는 검사 예외 각각은 @throws 태그를 사용하여 문서화해야 한다. 상위 예외 클래스(ex. Exception, Throwable)로 선언하지 말자. 어떤 구체적인 예외 상황이 발생할 수 있는지 파악하기 어려워진다. 또한, 예상치 못한 다른 예외들까지 포괄적으로 처리할 수 있다. 따라서 예외 처리가 모호해지며, 이로 인해 발생하는 버그나 문제를 찾기 어려워진다. main 메소드는 예외이다. main 메소드 내에서 Exception을 던지도록 선..
핵심 요약 아래 계층의 예외를 예방하거나 스스로 처리할 수 없고, 그 예외를 상위 게층에 그대로 노출하기 어렵다면 예외 번역을 사용하라. 이때 예외 연쇄를 이용하면 상위 계층에는 맥락에 어울리는 고수준 예외를 던지면서 근본 원인도 함께 알려주어 오류를 분석하기 좋다. 예외 처리와 내부 구현 세부사항의 노출 문제 API나 애플리케이션의 상위 레벨에서 예외를 처리할 때, 그 예외가 내부 구현의 세부 사항에 대한 정보를 드러내는 것은 좋지 않다. 그 이유는 내부 구현의 세부 사항은 변경될 수 있고, 그 변경이 고수준의 API 사용자에게 영향을 미칠 수 있기 때문이다. 예시 1 Repository에서 JPA 특정 예외(ex. EntityNotFoundException)가 발생하면, 이를 Service나 Cont..
표준 예외의 장점 개발자가 작성한 API를 다른 사람이 익히고 사용하기 쉬워진다. 가독성이 향상되어 프로그램이 읽기 쉬워진다. 예외 클래스 수가 적을수록 메모리 사용량도 줄고 클래스를 적재하는 시간도 적게 걸린다. 많이 사용하는 예외 종류 IllegalArgumentException(item 49) : 허용하지 않는 값이 인수로 건네졌을 때 ex. 반복 횟수를 지정하는 매개변수에 음수를 건넬 때 특수한 경우 null 값을 허용하지 않는 메소드에 null을 건네면 NPE 어떤 시퀀스의 허용 범위를 넘는 값을 건네면 IndexOutOfBoundsException IllegalStateException : 객체가 메소드를 수행하기에 적절하지 않은 상태일 때 ex. 제대로 초기화되지 않은 객체를 사용하려 할 때..
핵심 요약 검사 예외는 API의 안전성을 향상시키는 도구로, 제대로 사용하면 유용하다. 그러나 남용 시 API 사용의 복잡성을 증가시킨다. 예외 상황에서 복구가 불가능하면 비검사 예외를 사용하고, 복구가 가능한 상황이면 옵셔널을 고려하자. 옵셔널로 충분한 정보를 제공할 수 없을 때에만 검사 예외를 사용해야 한다. 검사 예외의 단점 API 사용자는 검사 예외 상황에 대해 대응할 수 있게 되어 프로그램의 안정성과 품질을 높일 수 있다. 그러나 API 사용자는 검사 예외를 반드시 처리해야 한다. 이는 코드의 복잡성을 증가시킨다. 또한, 스트림 연산 중간에서 검사 예외를 던지는 연산은 직접 사용할 수 없다. ex. map, filter같은 중간 연산에서 검사 예외를 던지는 메소드를 사용할 수 없다. 이로 인해,..