Skip to content

Commit

Permalink
[Item62]: 다른 타입이 적절하다면 문자열 사용을 피하라(#143)(성훈) (#156)
Browse files Browse the repository at this point in the history
* [Item62] 다른 타입이 적절하다면 문자열 사용을 피하라

* [Item67] 최적화는 신중히 하라
  • Loading branch information
seonghun-dev authored Sep 10, 2023
1 parent 99bdc4c commit 77f66ad
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@

### 문자열은 다른 타입을 대신하기 부적절

- 입력받을 데이터가 진짜 문자열인 경우에만 사용하는것이 좋다.
- 적절한 타입이 있다면 그것을 사용하고 없다면 새로운 타입을 하나 만들어서 사용하자.
- 되도록이면, 문자열 사용을 피하자.
- 문자열은 실수의 가능성이 있음. (오타가 있어도 컴파일러가 확인할 방법이 없음)

```java
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;
```

- 타입의 안전성을 보장할 수 없으며 접두어를 사용하여 이름 충돌을 방지
- 프로그램이 깨지기 쉽다.
- 평범한 상수를 나열한 것뿐이라 컴파일하면 그 값이 클라이언트(API가 적용된 클래스: 코드, 프로그램) 파일에 그대로 새겨진다.
- 즉, API의 상수 값이 바뀌면 클라이언트도 재컴파일을 해야만 한다.
- 정수 상수는 문자열로 출력하기 까다롭다
- 상수의 의미를 출력하는 것은 좋지만 이를 하드 코딩 해야한다는 점

### 열거 타입 사용하기

```java
public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
public enum Orange { NAVEL, TEMPLE, BLOOD }
```

## 문자열은 혼합 타입을 대신하기에 적합하지 않다.

```java
String compoundKey = className + "#" + i.next();
```

- className, i.next() 에서 "#" 이 쓰이면 혼란스러울 것
- String과 String을 더하는 행위는 메모리 할당과 해제를 발생시키며, 매번 파싱해야 하는 문제(문자열 연결은 느리니 주의하라), 또한 equals, toString, CompareTo 를 사용할 수 없고, String Class 가 제공하는 메서드만 사용해야 한다.
- 차라리 두 요소를 병합해서 관리하는 클래스를 만드는 것이 낫다.

```java
public class studyInfo {
private String team;
private int itemNum;
private static class compoundKey{
private String team;
private int itemNum;

public compoundKey(String team, int itemNum) {
this.team = team;
this.itemNum = itemNum;
}
public studyInfo compound(){
return new studyInfo(this);
}
}
private studyInfo(compoundKey compoundKey){
team = compoundKey.team;
itemNum = compoundKey.itemNum;
}

public static void main(String[] args) {
ArrayList<Integer> itemList = new ArrayList<>(List.of(60,61,62));
Iterator<Integer> i = itemList.iterator();

studyInfo student1 = new studyInfo.compoundKey("B팀",i.next()).compound();
studyInfo student2 = new studyInfo.compoundKey("A팀",i.next()).compound();
studyInfo student3 = new studyInfo.compoundKey("B팀",i.next()).compound();

System.out.println("student1: " + student1.team + " 아이템 " + student1.itemNum);
System.out.println("student2: " + student1.team + " 아이템 " + student2.itemNum);
System.out.println("student3: " + student1.team + " 아이템 " + student3.itemNum);
}
}
```

### 문자열은 권한을 표시하기에 적합하지 않다.

#### ThreadLocal이란?

- 일반 변수의 경우 : 수명이 코드 블록 내에서만 가능하다
- 스레드 지역 변수 설계 : 각 스레드가 자신만의 변수를 갖게 해주는 기능
- 자바2 이전에는 이를 개발자가 직접 설계했고, 클라이언트가 제공한 문자열 키로 지역변수를 식별하기까지 했다.

```java
public class ThreadLocal {
private ThreadLocal() { }

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

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

- 스레드 구분용 문자열 키가 전역 이름 공간에서 공유된다는 문제점
- 두 클라이언트가 서로 소통하지 못해 같은 키를 쓰기로 결정했다면, 의도하지 않게 같은 변수를 공유하게 된다


- 악의적인 클라이언트라면 의도적으로 같은 키를 사용하여 다른 클라이언트의 값을 획득할 수도 있다.
- 이런 경우에는 String으로 권한을 구분하는 것이 아니라 별도의 타입을 만들어 해결해야 한다.

```java
public class ThreadLocal {
private ThreadLocal() {
}

public static class Key {
Key() {
}
}

public staatic getKey() {
return Key;
}

public static void set(Key key, Object value);

public static Object get(Key key);
}
```

- set, get메서드는 정적 메서드일 이유가 없으니 Key 클래스의 인스턴스 메서드로 옮긴다.
- Key는 더 이상 스레드 지역변수를 구분하기 위한 키가 아니라, 그 자체가 스레드 지역변수가 된다.
- 결과적으로 지금 톱레벨 클래스인 ThreadLocal은 별달리 하는 일이 없어지므로 치워버리고, 중첩 클래스 Key의 이름을 ThreadLocal로 바꾼다.

```java
// Key -> ThreadLocal
public final class ThreadLocal {
public ThreadLocal() {
}

public void set(Object value);

public Object get();
}
```

- API에서는 get으로 얻은 Object를 실제 타입으로 형변환해 써야 해서 타입 안전하지 않다.
- ThreadLocal을 매개변수화 타입으로 선언하여 문제를 해결한다.
- java.lang.ThreadLocal처럼 구성하여 문자열 기반 API의 문제를 해결

```java
public final class ThreadLocal<T> {
public ThreadLocal();

public void set(T value);

public T get();
}
```
58 changes: 58 additions & 0 deletions Ch09/item67/최적화는_신중히_하라.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# 최적화는 신중히 하라


### 빠른 프로그램보다는 좋은 프로그램를 작성하라

- 성능보다는 구캡슐화가 잘 된, 다른 모듈과 결합성이 낮은 아키텍처를 설계할 것
- 성능같은 구현 상의 문제는 나중에 최적화해서 해결할 수 있지만, 아키텍처의 결함은 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있습니다
### 설계 단계에서 성능을 염두해야한다.

- 완성후 가장 변경하기 힘든거는 컴포넌트, 외부 시스템과 소통 방식,API, 네트워크 프로토콜, 영구 저장 데이터 포맷 (인터페이스)
- 시스템 성능저하 가져올 수 있음
### API를 설계할 때 성능에 주는 영향을 고려하라.
- 퍼블릭 타입을 변경가능하게 만드는 것은 불필요한 방어적 복사(defensive copying)을 요구한다.
- 합성이 적절해 보이는 설계에 상속을 사용하는 것은 슈퍼 클래스와 서브 클래스의 결합도를 상승한다. (성능을 물려받음)
- 구체적인 구현 타입 보다는 인터페이스를 사용 - 구현체에 종속 방지


#### java.awt.Component Class

```java
public abstract class Component implements ImageObserver, MenuContainer, Serializable
{
public Dimension getSize() {
return size();
}

@Deprecated
public Dimension size() {
return new Dimension(width, height);
}
}
```

### 좋은 API 설계가 좋은 성능
- 성능을 올리기 위해서 API를 변형하지 말 것
- 추상화 격차가 크기 때문에 코드를 최적화 한다고 해서 성능이 개선될 수 있을지 모른다.
- 자바는 C와 C++보다 최적화의 영향을 측정하는 것이 중요
- 알고리즘을 잘 고르는 것만으로도 큰 성능이 개선
- 성능을 최적화 하면 프로파일링 도구를 활용해서 측정해보아야 한다.
- 프로파일링 도구(소스 레벨의 분석을 위한 툴)로 JMH, JProbe, ej-technologies, JProfiler를 활용할 수 있음
- Intellj의 프로파일링 도구 https://madplay.github.io/post/intellij-idea-profiling-tools

### Intellij IDEA Ultimate Profiling

사용방법 : https://blog.jetbrains.com/idea/2020/03/profiling-tools-and-intellij-idea-ultimate/

사용방법2 : https://blog.jetbrains.com/idea/2022/01/fixing-the-parrot-party/

- 애플리케이션의 실행 방식과 메모리, CPU 리소스가 할당되는 방식에 대한 분석을 제공하는 Async Profiler

- 애플리케이션이 실행되는 동안 JVM에서 발생한 이벤트에 대한 정보를 수집하는 모니터링 도구인 Java Flight Recorder
![](https://blog.kakaocdn.net/dn/chVn1t/btrSvc1ttAL/jO7FVSPwdJDeJKZbsOqTM1/img.png)

- 애플리케이션의 특정 시점의 스냅샷으로 메모리를 분석하거나 Analyze memory snapshots![analyze-memory-snapshot](https://madplay.github.io/img/post/2022-02-04-intellij-idea-profiling-tools_analyze-memory-snapshot.png)


- 애플리케이션이 실행되는 도중에도 CPU와 메모리 현황을 실시간으로 확인할 수 있는 기능 CPU and memory live charts
- ![cpu-and-memory-live-charts](https://madplay.github.io/img/post/2022-02-04-intellij-idea-profiling-tools_cpu-and-memory-live-charts.png)

0 comments on commit 77f66ad

Please sign in to comment.