본문 바로가기

개발/이펙티브 자바

Effective Java ( 이펙티브 자바 ) - 11장 (동시성) - 아이템 78 공유 중인 가변 데이터는 동기화해 사용하라 synchronized 키워드는 해당 메서드나 블록을 한번에 한 스레드씩 수행하도록 보장한다. 많은 프로그래머가 동기화를 배타적 실행, 막는 용도로만 생각한다. 동기화를 제대로 사용하면 어떤 메서드도 이 객체의 상태가 일관되지 않은 순간을 볼 수 없을 것이다. 맞는 설명이지만, 동기화에는 중요한 기능이 하나 더 있다. 동기화 없이는 한 스레드가 만든 변화를 다른 스레드에서 확인하지 못할 수 있다. 동기화는 일관성이 깨진 상태를 볼 수 없게 하는 것은 물론, 동기화된 메서드나 블록에 들어간 스레드가 같은 락의 보호하에 수행된 모든 이전 수정의 최종 결과를 보게 해준다. 언어 명세상 long과 double 외의 변수를 읽고 쓰는 동작은 원자적이다. 이 말을 듣고 '.. 더보기
Effective Java ( 이펙티브 자바 ) - 아이템 77 예외를 무시하지 말라 API 설계자의 목소리를 흘려버리지말자. 예외를 명시하는 까닭은 적절한 조치를 취해달라고 말하는 것이다. 안타깝게도 예외를 무시하기란 아주 쉽다. 해당 메서드 호출을 try문으로 감싼 후 catch 블록에서 아무일도 하지 않으면 끝이다. catch 블록을 비워두면 예외가 존재할 이유가 없어진다. 그럼에도 불구하고 어쨌든 예외를 무시하기로 했다면(간혹 무시해야 할 때도 있다 - FileInputStream) catch 블록 안에 그렇게 결정한 이유를 주석으로 남기고 예외 변수의 이름도 ignored로 바꿔놓도록 하자. 예외를 적절히 처리하면 오류를 완전히 피할 수도 있다. 무시하지 않고 바깥으로 전파되게만 놔둬도 최소한 디버깅 정보를 남긴 채 프로그램이 신속히 중단되게는 할 수 있다. 더보기
Effective Java ( 이펙티브 자바 ) - 아이템 76 가능한 한 실패 원자적으로 만들라 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다. 이러한 특성을 실패 원자적이라고 한다. 메서드를 실패 원자적으로 만드는 방법은 다양하다. 가장 간단한 방법은 불변 객체로 설계하는 것이다. 흔한 방법은 작업 수행에 앞서 매개변수의 유효성을 검사하는 것이다. 내부 상태 변경 전에 잠재적 예외의 가능성 대부분을 걸러낼 수 있는 방법이다. public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // 다 쓴 참조 해제 return result; } 처음의 if 문에서 size 값.. 더보기
Effective Java ( 이펙티브 자바 ) - 아이템 75 예외의 상세 메시지에 실패 관련 정보를 담으라 예외를 잡지 못해 프로그램이 실패하면 자바 시스템은 그 예외의 스택 추적 정보를 자동으로 출력한다. 스택 추적은 예외 객체의 toString 메서드를 호출해 얻는 문자열이다. 이 정보가 실패 원인을 분석해야 하는 프로그래머 혹은 SRE가 얻을 수 있는 유일한 정보인 경우가 많다. 따라서 toString 메서드에 실패 원인에 관한 정보를 가능한 한 많이 담아 반환하는 일은 아주 중요하다. 사후 분석을 위하여. 실패 순간을 포착하려면 발생한 예외에 관여된 모든 매개변수와 필드의 값을 실패 메시지에 담아야 한다. IndexOutOfBoundsException의 상세 메시지는 범위의 최솟값, 최댓값, 그리고 그 범위를 벗어났다는 인덱스의 값을 담아야 한다. 하지만 .. 더보기
Effective Java ( 이펙티브 자바 ) - 아이템 74 메서드가 던지는 모든 예외를 문서화하라 메서드가 던지는 예외는 그 메서드를 올바로 사용하는 데 아주 중요한 정보다. 따라서 예외 하나하나를 문서화하는 데 충분한 시간을 쏟아야 한다. 검사 예외는 항상 따로따로 선언하고, 각 예외가 발생하는 상황을 자바독의 @throws 태그를 사용하여 정확히 문서화하자. 공통 상위 클래스 하나로 뭉뚱그려 선언하는 일은 삼가자(Exception, Throwable). 이 규칙에 유일한 예외가 있다면 바로 main 메서드다. main은 오직 JVM만이 호출하므로 Exception을 던지도록 선언해도 괜찮다. 자바 언어가 요구하는 것은 아니지만 비검사 예외도 정성껏 문서화해두면 좋다. 일반적으로 프로그래밍 오류를 뜻하는데, 프로그래머가 자연스럽게 해당 오류가 나지 않도록 코딩.. 더보기
Effective Java ( 이펙티브 자바 ) - 아이템 73 추상화 수준에 맞는 예외를 던지라 수행하려는 일과 관련 없어 보이는 예외가 튀어나오면 당황스러울 것이다. 메서드가 저수준 예외를 처리하지 않고 바깥으로 전파해버릴 때 종종 일어나는 일이다. 이는 윗 레벨 API를 오염시킨다. 상위 계층에서는 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꿔 던져야 한다. ( 예외 번역 - Exception Translation ) try { ... // 저수준 추상화를 이용한다. } catch (LowerLevelException e) { // 추상화 수준에 맞게 번역한다. throw new HigherLevelException(...); } 다음은 AbstractSequentialList에서 수행하는 예외 번역의 예다. 이는 List 인터페이스의 골격 구현이다.. 더보기
Effective Java ( 이펙티브 자바 ) - 아이템 72 표준 예외를 사용하라 숙련된 프로그래머는 그렇지 못한 프로그래머보다 더 많은 코드를 재사용한다. 예외도 마찬가지로 재사용하는 것이 좋으며, 자바 라이브러리는 대부분 API에서 쓰기에 충분한 수의 예외를 제공한다. 표준 예외를 재사용하면 얻는 게 많다. 그중 최고는 여러분의 API가 다른 사람이 익히고 사용하기 쉬워진다는 것이다. 예외 클래스 수가 적을수록 메모리 사용량도 줄고 클래스를 적재하는 시간도 적게 걸린다. 가장 많이 재사용되는 예외는 IllegalArgumentException이다. 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외로, 예를 들어 반복 횟수를 지정하는 매개변수에 음수를 건넬 때 쓸 수 있다. IllegalStateException도 자주 재사용된다. 이 예외는 대상 객체의 상태.. 더보기
Effective Java ( 이펙티브 자바 ) - 아이템 71 필요 없는 검사 예외 사용은 피하라 검사 예외를 싫어하는 자바 프로그래머가 많지만 제대로 활용하면 API와 프로그램의 질을 높일 수 있다. 검사 예외는 발생한 문제를 프로그래머가 처리하여 안전성을 높이게끔 해준다. 물론, 검사 예외를 과하게 사용하면 오히려 쓰기 불편한 API가 된다. 어떤 메서드가 검사 예외를 던질 수 있다고 선언되었다면, 이를 호출하는 코드에서는 catch 블록을 두어 그 예외를 붙잡아 처리하거나 더 바깥으로 던져 문제를 전파해야만 한다. 어느 쪽이든 API 사용자에게 부담을 준다. 더구나 검사 예외를 던지는 메서드는 스트림 안에서 직접 사용할 수 없기 때문에 자바 8부터는 부담이 더욱 커졌다. API를 제대로 사용해도 발생할 수 있는 예외이거나, 프로그래머가 의미 있는 조치를 취할 .. 더보기