꾸준한 스터디

문자열을 쓰지 않아야할 사례

  • 문자열은 다른 값 타입을 대신하기에 적합하지 않다
    • 파일, 네트워크, 키보드 입력으로부터 데이터를 받을 때 주로 문자열을 사용한다.
    • 입력 받을 데이터가 진짜 문자열일 때만 사용하는게 좋다.
    • 받은 데이터가 수치형이라면 int, float, BigInteger등 적당한 수치 타입으로 변환해야 한다.
    • 예/아니오 질문의 답이라면 적절한 열거타입이나 boolean으로 변환해야 한다.
  • 문자열은 열거 타입을 대신하기에 적합하지 않다.
    • 상수를 열거할 때는 문자열보다 열거 타입이 월등히 낫다.
  • 문자열은 혼합 타입을 대신하기에 적합하지 않다.
    • 여러 요소가 혼합된 데이터를 하나의 문자열로 표현하는 것은 대체로 좋지 않은 생각이다.
    • 예시) String compoundKet = className + "#" + i.next();
    • 두 요소를 구분하여 파싱하는 문자 #이 두 요소중 하나에서 쓰였다면 문제가 된다.
    • 각 요소를 개별로 접근하려면 문자열을 파싱해야 해서 느리고, 귀찮고, 오류 가능성도 커진다.
    • 적절한 equals, toString, compareTo 메서드를 제공할수 없으며, String이 제공하는 기능에만 의존해야 한다.
    • 차라리 전용 클래스를 새로 만드는 편이 낫다.
  • 문자열은 권한을 표현하기에 적합하지 않다.
    • 권한을 문자열로 표시하면 의도치 않은 자원 공유가 이루어질 수 있다.

 

 

각 스레드가 자신만의 변수를 갖는 스레드 지역변수 기능을 설계한다고 했을 때 싱글턴 클래스를 만들어 static get, set 메서드로 key, value를 할당, 취득하는 방법으로 설계할 수 있다.

public class ThreadLocal {
    private ThreadLocal() {} // 객체 생성 불가

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

    // (키가 가리키는) 현 스레드의 값을 반환
    public static object get(String key);
}

이 방식의 문제는 스레드 구분용 키가 단순하게 문자열로 되어있어 의도치 않게 같은 키값을 사용하게 되면 이전 value 값이 덮이거나 값이 공유되어 보안에도 취약하다.

문자열 대신 위조할 수 없는 키를 사용하면 해결 된다. 이 키를 권한(capacity)라고도 한다.

 

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는 더이상 스레드 지역변수를 구분하기 위한키가 아니라 그 자체가 스레드 지역변수가 된다.

결과적으로 지금 톱레벨 클래스인 ThreadLocal은 하는일이 없어지므로 중첩클래서 Key클래스의 이름을 ThreadLocalfh 바꾸면

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

확장하여 사용할 수 없도록 final 클래스로 만들고 getKey() 고유키 생성을 생성자 자체로 만든다.

get()메서드는 사용한 곳에서 생성한 ThreadLocal 인스턴스를 반환할 것이다.

이 인스턴스가 key가 되는것

이 API 마지막 문제점은 get() 으로 얻은 Object를 매번 형변환 해야한다는 것인데

 

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

ThreadLocal을 매개변수화 타입으로 선언하면 간단하게 문제가 해결된다.

 

 

핵심정리

더 적합한 데이터 타입이 있거나 새로 작성할 수 있다면 문자열을 쓰고 싶은 유혹을 뿌리쳐라.

문자열은 잘못 사용하면 번거롭고, 덜 유연하고, 느리고, 오류 가능성도 크다.

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

profile

꾸준한 스터디

@StudyRecord

포스팅이 유익하셨다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!