728x90
반응형
String(문자열) - Text를 표현하도록 설계되고, 자바가 잘 지원해주는 타입
하지만 워낙 자바에서 너무 잘 지원해주어서, 원래의 의도대로 사용되지 않는 경향이 있으며,
이럴 때 문자열 사용을 피해야할 사례에 대해서 이야기한다.
# 문자열을 쓰지 않아야할 사례
1. 다른 값 타입을 대신해서 문자열을 사용하는 경우
- 받는 데이터가 수치형 - int, float, BigInteger ... 적당한 수치를 타입으로 변환해서 사용할 것
- Y/N 를 나타낼 수 있다면 적절한 열거 타입 혹은 boolean 타입을 사용할 것
즉 기본 타입이든 참조 타입이든 적절한 값 타입이 있다면 그것을 사용하고, 없다면 새로 하나 작성할 것
2. 열거 타입을 대신하여 문자열을 사용할 경우
- 아이템 34(int 상수 대신 열거 타입을 사용하라) - 상수를 열거할 때는 문자열보다는 열거 타입이 월등히 낫다.
3. 혼합 타입을 대신하여 문자열을 사용할 경우
String compoundKey = className + "#" + i.next(); // -> 부적절한 상황
//if i.next = "#Blank" or className = "ClassA#"
- 단점이 많은 방식
- 위에 작성한 것처럼 혹여 두 요소를 구분해주는 문자 #이 두요소 중 하나에서 쓰이는 경우에는 혼란 야기
- 각 요소를 개별로 접근하여 문자열 파싱처리 -> 느려짐, 귀찮음, 오류 가능성 증가
- 또한 적절한 equals(), toString(), compareTo() 메서드 제공 불가, String의 기능에만 의존
- 따라서 전용 클래스를 새로 만드는 편이 나음 / 이런 클래스는 보통 private 정적 멤버 클래스로 선언(아이템 24)
4. 문자열로 권한을 표현하는 경우
잘못된 예시 (문자열을 통해 권한을 구분한 경우)
public class ThreadLocal {
private ThreadLocal() {} //객체 생성 불가
// 현 스레드의 값을 키로 구분해 저장한다.
public static void set(String key, Object value);
// (키가 가르키는) 현 스레드의 값을 반환한다.
public static Object get(String key);
}
해당 방식의 문제 및 원인은 무엇일까
정답
더보기
1. 스레드 구분용 문자열 키가 static namespace 에서 공유된다는 점
- 의도대로 동작하기 위해서는 각 클라이언트가 고유한 키를 제공해야함
- 하지만, 서로 소통이 불가한 상황에서 같은 키를 쓰기로 결정한다면, 의도치 않게 같은 변수를 공유하게 된다. (두 클라이언트 모두 제대로 기능 동작 X)
2. 보안 취약
- 악의적인 클라이언트라면 의도적으로 같은 키를 사용하여 다른 클라이언트의 값을 가져올 수 있음
- 따라서 해당 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);
}
해당 코드 리팩토링
- set / get 메서드는 정적 메서드일 필요가 없다. → 따라서 Key의 인스턴스 메서드로 변경처리
- Key는 더 이상 스레드 지역변수를 구분하기 위한 키가 아닌 자체적으로 스레드 지역변수가 된다.
- 결과적으로 톱 레벨 클래스(ThreadLocal)는 별달리 하는 일이 없어지기 때문에 중첩 클래스 Key의 이름을 ThreadLocal로 변경
- 추가적으로 타입 안전성을 위해서라면 API get을 통해 Object 형변환을 하지 않아도 되게끔 처리
// Key를 ThreadLocal로 변경
public final class ThreadLocal {
public ThreadLocal();
public void set(Object value);
public Object get();
}
//매개변수화를 통한 타입 안전성 확보
public final class ThreadLocal<T> {
public ThreadLocal();
public void set(T value);
public T get();
}
정리
적하반 데이터 타입이 있거나 새로 작성할 수 있다면 , 문자열보다는 해당 타입을 사용하도록 하자
728x90
반응형
'책 > Effective Java' 카테고리의 다른 글
객체는 인터페이스를 사용해 참조하라 (0) | 2022.05.15 |
---|---|
문자열 연결은 느리니 주의하라 (0) | 2022.05.15 |
박싱된 기본 타입 vs 기본 타입 (0) | 2022.05.14 |
정확한 답과 계산을 해야한다면 float와 double은 피하라 (0) | 2022.05.14 |
메서드 참조 (Method Reference) (0) | 2022.03.20 |