From 77f66ad6abfc1e170ea684354fc71088dc1ee294 Mon Sep 17 00:00:00 2001 From: Jung Seonghun <80201773+seonghun-dev@users.noreply.github.com> Date: Sun, 10 Sep 2023 22:53:01 +0900 Subject: [PATCH] =?UTF-8?q?[Item62]:=20=EB=8B=A4=EB=A5=B8=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=EC=9D=B4=20=EC=A0=81=EC=A0=88=ED=95=98=EB=8B=A4?= =?UTF-8?q?=EB=A9=B4=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9D=84=20=ED=94=BC=ED=95=98=EB=9D=BC(#143)(=EC=84=B1?= =?UTF-8?q?=ED=9B=88)=20(#156)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Item62] 다른 타입이 적절하다면 문자열 사용을 피하라 * [Item67] 최적화는 신중히 하라 --- ...4_\355\224\274\355\225\230\353\235\274.md" | 152 ++++++++++++++++++ ...1\355\236\210_\355\225\230\353\235\274.md" | 58 +++++++ 2 files changed, 210 insertions(+) create mode 100644 "Ch09/item62/\353\213\244\353\245\270_\355\203\200\354\236\205\354\235\264_\354\240\201\354\240\210\355\225\230\353\213\244\353\251\264_\353\254\270\354\236\220\354\227\264_\354\202\254\354\232\251\354\235\204_\355\224\274\355\225\230\353\235\274.md" create mode 100644 "Ch09/item67/\354\265\234\354\240\201\355\231\224\353\212\224_\354\213\240\354\244\221\355\236\210_\355\225\230\353\235\274.md" diff --git "a/Ch09/item62/\353\213\244\353\245\270_\355\203\200\354\236\205\354\235\264_\354\240\201\354\240\210\355\225\230\353\213\244\353\251\264_\353\254\270\354\236\220\354\227\264_\354\202\254\354\232\251\354\235\204_\355\224\274\355\225\230\353\235\274.md" "b/Ch09/item62/\353\213\244\353\245\270_\355\203\200\354\236\205\354\235\264_\354\240\201\354\240\210\355\225\230\353\213\244\353\251\264_\353\254\270\354\236\220\354\227\264_\354\202\254\354\232\251\354\235\204_\355\224\274\355\225\230\353\235\274.md" new file mode 100644 index 0000000..d1f4464 --- /dev/null +++ "b/Ch09/item62/\353\213\244\353\245\270_\355\203\200\354\236\205\354\235\264_\354\240\201\354\240\210\355\225\230\353\213\244\353\251\264_\353\254\270\354\236\220\354\227\264_\354\202\254\354\232\251\354\235\204_\355\224\274\355\225\230\353\235\274.md" @@ -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 itemList = new ArrayList<>(List.of(60,61,62)); + Iterator 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 { + public ThreadLocal(); + + public void set(T value); + + public T get(); +} +``` \ No newline at end of file diff --git "a/Ch09/item67/\354\265\234\354\240\201\355\231\224\353\212\224_\354\213\240\354\244\221\355\236\210_\355\225\230\353\235\274.md" "b/Ch09/item67/\354\265\234\354\240\201\355\231\224\353\212\224_\354\213\240\354\244\221\355\236\210_\355\225\230\353\235\274.md" new file mode 100644 index 0000000..95c0fdf --- /dev/null +++ "b/Ch09/item67/\354\265\234\354\240\201\355\231\224\353\212\224_\354\213\240\354\244\221\355\236\210_\355\225\230\353\235\274.md" @@ -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) \ No newline at end of file