본문 바로가기

독서찰기(讀書札記)/이펙티브 자바

(73)
[아이템 69] 예외는 진짜 예외 상황에만 사용하라 예외는 (그 이름이 말해주듯) 오직 예외 상황에서만 써야 한다. 절대로 일상적인 제어 흐름용으로 쓰여선 안 된다. 표준적이고 쉽게 이해되는 관용구를 사용하고, 성능 개선을 목적으로 과하게 머리를 쓴 기법을 자제하라. 잘 설계된 API라면 클라이언트가 정상적인 제어 흐름으에서 예외를 사용할 일이 없게 해야 한다. 특정 상태에서만 호출할 수 있는 '상태 의존적' 메서드를 제공하는 클래스는 '상태 검사' 메서드도 함께 제공해야 한다. e.g.) Iterator 인터페이스의 next와 hasNext가 각각 상태 의존적 메서드와 상태 검사 메서드에 해당 별도의 상태 검사 메서드 덕분에 다음과 같은 표준 for 관용구를 사용할 수 있다. (for-each도 내부적으로 hasNext를 사용한다) for (Iterat..
[아이템 68] 일반적으로 통용되는 명명 규칙을 따르라 식별자 타입 예 패키지와 모듈 org.junit.jupiter.api, com.google.common.collect 클래스와 인터페이스 Stream, FutureTask, LinkedHashMap, HttpClient 메서드와 필드 remove, groupingBy, getCrc 상수 필드 MIN_VALUE, NEGATIVE_INFINITY 지역변수 i, denom, houseNum 타입 매개변수 T, E, K, V, X, R, U, V, T1, T2 자바 플랫폼은 명명 규칙이 잘 정립되어 있으며, 그중 많은 것이 자바 언어 명세에 기술되어 있다. 자바 명명 규칙은 크게 철자와 문법, 두 범주로 나뉜다. 철자 규칙은 패키지, 클래스, 인터페이스, 메서드, 필드, 타입 변수의 이름을 다룬다. 이 규칙들은..
[아이템 67] 최적화는 신중히 하라 (맹목적인 어리석음을 포함해) 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다 (심지어 효율을 높이지도 못하면서). - 윌리엄 울프[Wulf] (전체의 97% 정도인) 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다. - 도널드 크누스[Knuth] 최적화를 할 때는 다음 두 규칙을 따르라. 첫 번째, 하지 마라. 두 번째, (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지 마라. - M. A. 잭슨[Jackson] [Why] 구현상의 문제는 나중에 최적화해 해결할 수 있지만, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있다. [How] 빠른 프로그램보다는..
[아이템 66] 네이티브 메서드는 신중히 사용하라 자바 네이티브 인터페이스(Java Native Interface, JNI)란? 자바 프로그램이 네이티브 메서드를 호출하는 기술 네이티브 메서드란 C나 C++ 같은 네이티브 프로그래밍 언어로 작성한 메서드 전통적으로 네이티브 메서드의 주요 쓰임은 다음 세 가지다. 첫 번째, 레지스트리 같은 플랫폼 특화 기능을 사용한다. 두 번째, 네이티브 코드로 작성된 기존 라이브러리를 사용한다. e.g.) 레거시 데이터를 사용하는 레거시 라이브러리 세 번째, 성능 개선을 목적으로 성능에 결정적인 영향을 주는 영역만 따로 네이티브 언어로 작성한다. [Why] 성능을 개선할 목적으로 네이티브 메서드를 사용하는 것은 거의 권장하지 않는다. 자바 초기 시절(자바 3 전)이라면 이야기가 다르겠지만, JVM은 그동안 엄청난 속도로..
[아이템 65] 리플렉션보다는 인터페이스를 사용하라 리플렉션이란? 리플렉션 기능(java.lang.reflect)을 이용하면 프로그램에서 임의의 클래스에 접근할 수 있다. Class 객체가 주어지면 그 클래스의 생성자, 메서드, 필드에 해당하는 Constructor, Method, Field 인스턴스를 가져올 수 있다. Constructor, Method, Field 인스턴스들로는 그 클래스의 멤버 이름, 필드 타입, 메서드 시그니처 등을 가져올 수 있다. Constructor, Method, Field 인스턴스를 이용해 각각에 연결된 실제 생성자, 메서드, 필드를 조작할 수도 있다. 단점 컴파일타임 타입 검사가 주는 이점을 하나도 누릴 수 없다. 예외 검사의 이점도 누릴 수 없다. 리플렉션 기능을 써서 존재하지 않는(접근할 수 없는) 메서드를 호출하려 ..
[아이템 64] 객체는 인터페이스를 사용해 참조하라 [Why] 인터페이스를 타입으로 사용하는 습관을 길러두면 프로그램이 훨씬 유연해질 것이다. 나중에 구현 클래스를 교체하고자 한다면 그저 새 클래스의 생성자(혹은 다른 정적 팩터리)를 호출해주기만 하면 된다. 변수를 구현 타입으로 선언하면 자칫 프로그램이 컴파일되지 않을 수도 있다. 클라이언트에서 교체 전 구현 클래스에서만 제공하는 메서드를 사용했거나, 교체 전 구현 클래스를 사용해야 하는 다른 메서드에 그 인스턴스를 넘겼다면 새로운 코드에서는 컴파일되지 않을 것이다. [When] 인터페이스에는 없는 특별한 메서드를 제공하는 클래스는 클래스로 참조해야 한다. e.g.) PriorityQueue 클래스는 Queue 인터페이스에는 없는 comparator 메서드를 제공한다. [How] 적합한 인터페이스만 있다..
[아이템 63] 문자열 연결은 느리니 주의하라 [Why] 문자열 연결 연산자로 문자열 n개를 잇는 시간은 n^2에 비례한다. 문자열은 불변(아이템17)이라서 두 문자열을 연결할 경우 양쪽의 내용을 모두 복사해야하므로 성능 저하는 피할 수 없는 결과다. [How] 성능을 포기하고 싶지 않다면 String 대신 StringBuilder를 사용하자. StringBuilder를 전체 결과를 담기에 충분한 크기로 초기화하면 조금 더 빠르다.
[아이템 62] 다른 타입이 적절하다면 문자열 사용을 피하라 [배경] 문자열은 워낙 흔하고 자바가 또 잘 지원해주어서 원래 의도하지 않은 용도로도 쓰이는 경향이 있다. [Why] 문자열은 다른 값 타입을 대신하기에 적합하지 않다. 많은 사림이 파일, 네트워크, 키보드 입력으로부터 데이터를 받을 때 주로 문자열을 사용한다. 하지만 입력받을 데이터가 진짜 문자열일 때만 그렇게 하는 게 좋다. 문자열은 열거 타입을 대신하기에 적합하지 않다. (아이템34) 문자열은 혼합 타입을 대신하기에 적합하지 않다. String compoundKey = className + "#" + i.next(); 이는 단점이 많은 방식이다. 두 요소를 구분해주는 문자 #이 두 요소 중 하나에서 쓰였다면 혼란스러운 결과를 초래한다. 각 요소를 개별로 접근하려면 문자열을 파싱해야 해서 느리고, 귀..