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

신명철·2022년 3월 24일
0

Effective Java

목록 보기
59/80

문자열은 다른 값 타입을 대신하기에 적합하지 않다. 입력받을 데이터가 진짜 문자열일 때만 그렇게 하는게 좋다. 데이터가 수피형이라면 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는 문자열 대신 위조할 수 없는 키를 사용하면 해결된다. 다음 코드를 보자.

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);
}

이 API는 위 두 가지 문제점을 해결한다. 이렇게 하면 Key는 더 이상 지역변수를 구분하기 위한 키가 아니라, 그 자체가 스레드 지역변수가 된다. ThreadLocal은 별달리 하는 일이 없어진다. 이를 리팩터링 해보자.

리팩터링하여 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보다 빠르고 우아하다.

profile
내 머릿속 지우개

0개의 댓글