문자열은 다른 값 타입을 대신하기에 적합하지 않다. 입력받을 데이터가 진짜 문자열일 때만 그렇게 하는게 좋다. 데이터가 수피형이라면 int
,float
,BigInteger
등 적당한 수치 타입으로 변환해야 한다. 예/아니오 질문의 답이라면 적절한 열거 타입이나 boolean
으로 변환해야 한다. 일반화해 이야기하자면, 기본 타입이든 참조 타입이든 적절한 값 타입이 있다면 그것을 사용하고, 없다면 새로 하나 작성하라.
String compoundKey = className + "#" + i.next();
위 코드처럼 # 를 이용해 두 요소를 구분하는데 사용한다면 문자열을 파싱해야 해서 느리고, 귀찮고, 오류 가능성도 커진다. 이럴때는 차라리 정적 멤버 클래스로 만들어서 사용하는 것이 낫다.
public class ThreadLocal {
private ThreadLocal() {}
public static void set(String key, Object value);
public static Object get(String key);
}
고유해야 하는 Key를 문자열로 선언했다. 악의적인 클라이언트가 의도적으로 같은 키를 사용하거나 의도치 않게 같은 변수를 공유하게 될수도 있다. 이 API는 문자열 대신 위조할 수 없는 키를 사용하면 해결된다. 다음 코드를 보자.
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는 위 두 가지 문제점을 해결한다. 이렇게 하면 Key는 더 이상 지역변수를 구분하기 위한 키가 아니라, 그 자체가 스레드 지역변수가 된다. ThreadLocal은 별달리 하는 일이 없어진다. 이를 리팩터링 해보자.
public final class ThreadLocal {
public ThreadLocal();
public void set(Object value);
public Object get();
}
위 코드는 get으로 얻은 Object를 실제 타입으로 형변환해서 써야하기 떄문에 타입 안전하지 않다. 이를 제네릭으로 바꿔서 타입안전성을 확보하자.
public final class ThreadLocal<T> {
public ThreadLocal();
public void set(T value);
public T get();
}
자바의 java.lang.ThreadLocal
과 흡사해졌다. 문자열 기반 API의 문제를 해결해주며, 키 기반 API보다 빠르고 우아하다.