문자열(String)은 텍스트를 표현하도록 설계되었지만, 의도하지 않은 용도로 쓰이는 경향이 있다.
이번 아이템에서는 문자열을 쓰지 않아야 할 사례를 다룸
🍑 본론
문자열을 잘못쓰는 사례
데이터를 입력받을 때, 입력 받을 데이터가 진짜 문자열이 아님에도 문자열로 받고 보는 경우
받는 데이터가 수치형이라면 int, float, BigInteger , 예/아니오 질문의 답이라면 열거 타입이나 boolean과 같은 명확한 타입으로 받는 것이 더 좋다
열거 타입을 문자열로 대신하는 경우
혼합 타입(여러 요소가 혼합된 데이터)을 문자열로 대신하는 경우
혼합 타입을 문자열로 대신 사용하는 예
String compoundKey = className + "#" + i.next();
혹시라도 두 요소를 구분해주는 문자 #이 두 요소 중 하나에서 쓰였다면 혼란스러운 결과를 초래
각 요소를 개별로 접근하려면 문자열을 파싱해야 하는데, 느리고 귀찮고 오류가능성도 커짐
적절한 equals, toString, compareTo 매서드를 제공할 수 없다
=> 차라리 전용 클래스를 새로 만드는 것이 낫다
기본 타입이든, 참조 타입이든 적절한 값 타입이 있다면,그것을 사용하고, 없다면 새로 하나 작성하라
문자열로 권한을 잘못 구분하는 예시
public class ThreadLocal {
private ThreadLocal() {} // 객체 생성 불가
// 현 스레드의 값을 키로 구분해 저장한다.
public static void set(String key, Object value);
// 현 스레드의 값을 반환한다.
public static Object get(String key);
}
스레드 구분용 문자열 키가 전역 이름 공간에서 공유된다는 점이 문제
이 방식이 의도대로 동작하려면 각 클라이언트가 고유한 키를 제공해야 한다.
만약 두 클라이언트가 서로 소통하지 못해 같은 키를 쓰기로 결정한다면, 의도치 않게 같은 변수를 공유하게 됨
결국 두 클라이언트 모두 제대로 기능하지 못함
=> 문자열 대신 위조할 수 없는 키를 사용하면 해결되는데, 이 키를 권한(capacity)이라고 한다.
ThreadLocal?
: Java에서 특정 스레드에만 고유하게 데이터를 저장하고 읽을 수 있도록 지원하는 클래스
: 여러 스레드가 동시에 실행되는 환경에서도 각 스레드마다 독립적인 데이터를 갖게 되어 독립적인 작업 가능
public class ThreadLocalExample {
// ThreadLocal 객체 생성
private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
Runnable task1 = () -> {
threadLocal.set(100); // 각 스레드에 데이터 저장
System.out.println("Task 1: " + threadLocal.get());
};
Runnable task2 = () -> {
threadLocal.set(200); // 각 스레드에 데이터 저장
System.out.println("Task 2: " + threadLocal.get());
};
// 두 개의 스레드를 생성하여 실행
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
}
}
// Task 1: 100
// Task 2: 200
```java
public class ThreadLocalExample {
public static void main(String[] args) {
Runnable task1 = () -> {
// 스레드 1에서 각 키에 값을 저장
ThreadLocal.set("username", "Alice");
ThreadLocal.set("role", "admin");
// 저장된 값을 가져와 출력
System.out.println("Thread 1 - Username: " + ThreadLocal.get("username"));
System.out.println("Thread 1 - Role: " + ThreadLocal.get("role"));
};
Runnable task2 = () -> {
// 스레드 2에서 다른 값을 저장
ThreadLocal.set("username", "Bob");
ThreadLocal.set("role", "user");
// 저장된 값을 가져와 출력
System.out.println("Thread 2 - Username: " + ThreadLocal.get("username"));
System.out.println("Thread 2 - Role: " + ThreadLocal.get("role"));
};
// 두 스레드를 생성하여 실행
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
}
}
Key 클래스로 권한을 구분한 예시
public class ThreadLocal {
private ThreadLocal() {} // 생성자 막기
// 내부 `Key` 클래스를 이용하여 인스턴스에 무관한 키를 생성할 수 있게 만든다.
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);
}
Chapter : 9. 일반적인 프로그래밍 원칙
Item 62. 다른 타입이 적절하다면 문자열 사용을 피하라
Assignee : pyeong114
🍑 서론
문자열(String)은 텍스트를 표현하도록 설계되었지만, 의도하지 않은 용도로 쓰이는 경향이 있다. 이번 아이템에서는 문자열을 쓰지 않아야 할 사례를 다룸
🍑 본론
문자열을 잘못쓰는 사례
int
,float
,BigInteger
, 예/아니오 질문의 답이라면열거 타입
이나boolean
과 같은 명확한 타입으로 받는 것이 더 좋다혼합 타입을 문자열로 대신 사용하는 예
기본 타입이든, 참조 타입이든 적절한 값 타입이 있다면,그것을 사용하고, 없다면 새로 하나 작성하라
문자열로 권한을 잘못 구분하는 예시
} // Task 1: 100 // Task 2: 200
Key 클래스로 권한을 구분한 예시
이 방법을 통해 앞서 문자열 기반의 API 문제를 모두 해결할 수 있다.
🍑 결론
Referenced by