• 문자열이 의도하지 않는 용도로 사용되는 것을 피하자!

 

 

적절하지 않은 String 활용

  • 문자열은 다른 값 타입을 대신하기에 적합하지 않다.
    • 데이터가 수치형이면 int, float, BigInteger 활용하자
    • 예/아니요 질문의 답이면 boolean이나 열거타입으로 변환하자
    • 적절한 값 타입이 있다면 그걸 사용하자
  • 문자열은 열거 타입을 대신하기에 적합하지 않다
    • 아이템 34에서 언급했다.
  • 문자열은 혼합 타입을 대신하기에 적합하지 않다.
    • 여러 요소가 혼합된 데이터를 하나의 문자열로 표현하는 것은 좋지 않은 생각이다.
//혼합 타입을 문자열로 처리한 부적절한 예
String compoundKey = className + "#" + i.next();

/**
* 두 요소를 구분해주는 문자 #이 두 요소중 하나에서 쓰였다면 혼란스러워진다.
* 각 요소를 개별로 접근하려면 문자열을 파싱해야 해서 느리고 오류 가능성도 커진다.
* String이 제공하는 기능만 사용해야한다(equals, toString 메소드 제공 못함)
* 차라리 전용 클래스를 새로 만드는 것이 낫다.
*/
  • 문자열은 권한을 표현하기에 적합하지 않음
    • 예를 들어 스레드 지역변수 기능을 설계한 경우를 보자
//문자열을 사용해 권한을 구분한 예
public class ThreadLocal {
    private ThreadLocal() { } // 객체 생성 불가

    //현 스레드의 값을 키로 구분해 저장
    public static void set(String key, Object value);

    // (키가 가리키는) 현 스레드의 값을 반환
    public static Object get(String key);
}
  • 문제점
    • 스레드 구분용 문자열 키가 전역 이름공간에서 공유된다는 점
    • 보안도 취약하다
    • 이 API는 문자열 대신 위조할 수 없는 키를 사용하면 해결된다.
    • 이 키를 권한(capacity)이라고도 한다.
//Key 클래스로 권한 구분
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);
}
//위 코드 리팩토링 - Key를 ThreadLocal로 변경

public final class ThreadLocal {
    public ThreadLocal();
    public void set(Object value);
    public Object get();   
}
  • set과 key는 정적 메소드일 이유가 없으니 Key 클래스의 인스턴스 메소드로 바꿨다.
  • 이렇게 하면 Key는 더이상 스레드 지역변수를 구분하기 위한 키가 아니라 그 자체가 스레드 지역변수가 된다.
//매개변수화하여 타입 안정성 확보

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

+ Recent posts