본문 바로가기

STUDY REVIEW/이펙티브 자바 독서스터디

[EFFECTIVE JAVA] 이펙티브 자바 독서스터디 - 9장 일반적인 프로그래밍 원칙

9장 일반적인 프로그래밍 원칙
아이템 57. 지역변수의 범위를 최소화하라
아이템 58. 전통적인 for 문보다는 for-each 문을 사용하라
아이템 59. 라이브러리를 익히고 사용하라
아이템 60. 정확한 답이 필요하다면 float와 double은 피하라
아이템 61. 박싱된 기본 타입보다는 기본 타입을 사용하라
아이템 62. 다른 타입이 적절하다면 문자열 사용을 피하라
아이템 63. 문자열 연결은 느리니 주의하라
아이템 64. 객체는 인터페이스를 사용해 참조하라
아이템 65. 리플렉션보다는 인터페이스를 사용하라
아이템 66. 네이티브 메서드는 신중히 사용하라
아이템 67. 최적화는 신중히 하라
아이템 68. 일반적으로 통용되는 명명 규칙을 따르라

 

읽고 느낀 점

이번 목차는 약간의 총정리 느낌이였다.

항상 코드의 최적화는 어렵다.

하지만 앞서 나간 사람들의 지식이 있기 때문에 삽질을 안해도 된다는 점이 후발주자의 이점인 것 같다.

조언을 세기며 내일도 코드를 ... 치러 간다.


아이템 57. 지역변수의 범위를 최소화하라

 

클래스와 멤버의 접근 권한을 최소화하라 = 지역변수의 범위를 최소화하라.

 

지역변수의 범위를 줄이는 가장 강력한 기법은 '가장 처음 쓰일 때 선언하기'이다.

 

모든 지역변수는 선언과 동시에 초기화해야한다.

만약 초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미루자.

 

마지막 팁은 메서드를 작게 유지하고 한 가지 기능에 집중하는 것이다.

단순하게 메서드를 기능별로 쪼개면 된다.


아이템 58. 전통적인 for 문보다는 for-each 문을 사용하라

 

전통적인 for문과 비교하면 for-each문은 명료하고, 유연하고, 버그를 예방해준다.

성능 저하도 없으니 모든 곳에서 for-each문을 사용하자.


아이템 59. 라이브러리를 익히고 사용하라

 

이미 사용하는 코드를 또 개발하지 말고 라이브러리 형태로 구현해놓은 코드를 사용하자.

일반적으로 라이브러리의 코드가 품질이 좋고, 점차 개선될 가능성이 높다.


아이템 60. 정확한 답이 필요하다면 float와 double은 피하라

 

성능 저하를 신경 쓰지 않겠다면, BigDecimal을 사용하자.

만약 성능이 중요하고 소수점을 직접 추적할 수 있고 숫자가 너무 크지 않다면 int, long을 사용하자.

 

  • 숫자를 아홉자리 십진수로 사용한다면 int, 열여덟자리 십진수로 사용한다면 long, 열여덟 자리를 넘어가면 BigDecimal을 사용하자.

아이템 61. 박싱된 기본 타입보다는 기본 타입을 사용하라

 

오토박싱이 박싱된 기본 타입을 사용할 때 번거로움을 줄여주지만, 그 위험까지 없애주지는 않는다. 

같은 연산에서 기본타입과 박싱된 기본타입을 이용하면 언박싱이 이뤄지며, 언박싱 과정에서 NullPointerException을 던질 수 있다.


아이템 62. 다른 타입이 적절하다면 문자열 사용을 피하라

 

더 적합한 데이터 타입이 있다면 문자열을 사용하지 말자.

문자열을 잘못 사용하는 흔한 예로는 기본타입, 열거 타입, 혼합타입이 있다.

 

잘못된 예 - 문자열을 사용하여 권한을 구분

public class ThreadLocal {
    private ThreadLocal() {} //객체 생성 불가
    
    // 현 스레드의 값을 키로 구분해 저장한다.
    public static void set(String key, Object value);
    
    // (키가 가르키는) 현 스레드의 값을 반환한다.
    public static Object get(String key);
}

이 방식의 문제점은 스레드 구분용 문자열 키가 global namespace에서 공유된다는 점이다.
이 방식이 의도대로 동작하려면 각 클라이언트가 고유한 키를 제공해야 한다.
만약 두 클라이언트가 서로 소통하지 못해 같은 키를 쓰기로 결정한다면, 의도치 않게 같은 변수를 공유하게 된다.
따라서 클라이언트는 제대로 작동하지도 않고 보안에도 취약하다.

이런 경우에는 String으로 권한을 구분하는 것이 아니라 별도의 타입을 만들어 해결해야 한다.

public class ThreadLocal {
    private ThreadLocal() {} //객체 생성 불가
    
    public static class Key {
        key() {}
    }
    
    //위조 불가능한 고유 키를 생성한다.
    public static Key getKey() {
		return new Key();
    }
    
    public static void set(Key key, Object value);
    public static Object get(Key key);
}

이 방법은 앞서의 문자열 기반 API의 문제점을 해결해 주지만 개선할 부분이 있다.
set/get 메서드는 이제 static 메서드일 이유가 없다. 따라서 Key의 인스턴스 메서드로 변경하는 것이 좋다.
그렇게 하면 Key는 더 이상 스레드 지역변수를 구분하기 위한 키가 아니라 그 자체가 스레드 지역변수가 된다.

public final class Key {
    public Key();
    public void set(Object value);
    public Object get();
}

이 API는 get으로 얻은 Object를 실제 타입으로 타입 캐스팅 해야 해서 타입안전하지 않다.
하지만 제네릭을 사용한다면 조금 더 타입 안전하게 만들 수 있다.

public final class Key<T> {
    public Key();
    public void set(T value);
    public T get();
}

아이템 63. 문자열 연결은 느리니 주의하라

 

문자열 연결할 때는 +를 피하고, StringBuilder, appent 메서드를 이용하자.

문자열 연결 연산자 + 로 문자열 n개를 잇는 시간은 n²에 비례한다.


아이템 64. 객체는 인터페이스를 사용해 참조하라

 

적합한 인터페이스만 있다면 매개변수뿐 아니라 반환값, 변수, 필드를 전부 인터페이스 타입으로 선언하자.

적합한 인터페이스가 없다면 당연히 클래스로 참조해야 한다.

적합한 인터페이스가 없다면 클래스의 계층구조 중 필요한 기능을 만족하는 가장 덜 구체적인 클래스 타입을 사용하자.


아이템 65. 리플렉션보다는 인터페이스를 사용하라

 

리플랙션은 단점이 많다. 되도록 객체 생성에만 사용하고, 생성한 객체를 이용할 때는 적절한 인터페이스나 컴파일 타임에 알 수 있는 상위 클래스로 형변환해 사용하자.

  • 컴파일 타임 타입 검사가 주는 이점을 하나도 누릴 수 없다.
  • 리플렉션을 이용하면 코드가 더러워진다.
  • 성능이 떨어진다.
  • 아주 제한된 형태로만 사용해야 단점을 피하고 이점을 취할 수 있다.

아이템 66. 네이티브 메서드는 신중히 사용하라

 

네이티브 코드는 최소한만 사용하고 철저하게 테스트하자. 

네이티브 메서드가 성능을 개선해주는일이 많지 않기 때문이다.


아이템 67. 최적화는 신중히 하라

 

빠른 프로그램을 작성하려 안달하지 말자.

충분히 빠르다면 그것으로 끝이다.

문제가 되는 지점이 있다면 알고리즘부터 살펴보고 알고리즘 변경 후에 성능을 측정하자.

그리고 알고리즘을 살펴보는걸 반복해서 성능을 최적화시키자.


아이템 68. 일반적으로 통용되는 명명 규칙을 따르라

 

상식이 이끄는 대로 오랫동안 따라온 규칙을 따르자.