Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Item 61-64. 적절한 타입과 문자열 사용 시의 주의 사항 #27

Open
ChoiSeEun opened this issue Dec 26, 2023 · 0 comments
Open
Assignees
Labels

Comments

@ChoiSeEun
Copy link
Contributor

section: 6장

  • 아이템 61. 박싱된 기본 타입보다는 기본 타입을 사용하라
  • 아이템 62. 다른 타입이 적절하다면 문자열 사용을 피하라
  • 아이템 63. 문자열 연결은 느리니 주의하라
  • 아이템 64. 객체는 인터페이스를 사용해 참조하라

🍵 서론

이번 아이템은, 다들 한 번쯤 들어봤을 만한 기본적인 내용을 이야기하고 있다. 아이템별로 핵심 내용만을 빠르게 정리해보자 !

🌒 본론

1️⃣ 기본 타입을 사용해라

💡 기본 타입을 쓸 수 있다면, 기본 타입을 사용하자

  • 기본 타입은 값만 가지지만, 박싱된 기본 타입은 식별성 도 가진다.
  • 기본 타입은 항상 유효한 값을 가지지만, 박싱된 기본 타입은 유효하지 않은 null 값도 가질 수 있다.
  • 기본 타입이 박싱된 기본 타입보다 시간 및 메모리 측면에서 효율적이다.

위의 3가지는, 기본 타입과 박싱된 기본 타입의 차이이다. 오토박싱/언박싱 덕분에 크게 구분없이 기본 타입과 박싱된 기본 타입을 사용할 수 있지만, 예상치 못한 상황에서 문제를 일으키기도 한다.

기본 타입 : int , double , boolean
박싱된 기본 타입 : Integer, Double, Boolean

Case01. == 비교

image
  • (i<j) 에서는 오토언박싱되어 30이라는 값이 비교되지만
  • (i==j) 에서는 오토언박싱이 일어나지 않고 객체의 식별성을 검사한다.

즉, 박싱된 기본 타입에 == 연산자를 사용하면 오류가 발생하게 된다. 이를 해결하기 위해서는 == 연산자에서도 값을 비교할 수 있도록, 기본 타입으로 변환한 뒤에 값을 비교해야 한다.

image

Case02. null 초기화

image
  • Integer 등의 박싱된 기본 타입은, 명시적으로 초기화하지 않을 경우 참조 타입처럼 null 로 초기화가 된다.
  • 또한, 기본 타입과 박싱된 기본 타입을 혼용하면 박싱된 기본 타입의 박싱이 자동으로 풀리게 된다.
  • 따라서, if문에서 변수 i가 오토박싱되어 null 과의 비교가 일어나므로 NUllPointerException 이 발생한다.

Case03. 성능 저하

image

➕ 오토박싱/언박싱에서의 성능 저하

  • Wrapper 클래스에서 값을 비교하려면 equals() 를 사용해야 하고, 이는 객체의 비교이므로 성능 저하 발생
  • 오토 박싱을 사용하는 경우, Wrapper 클래스의 새로운 객체가 생성되므로 메모리 할당이나 가비지 컬렉션 등의 부하가 발생
  • 참고로, 100만건 기준 약 5배의 성능 차이가 발생

❓ 그렇다면 박싱된 기본 타입은 언제 사용하지?

  1. 컬렉션의 원소, 키, 값
  2. 매개변수화 타입이나 매개변수화 메서드의 타입 매개변수
  3. 리플렉션을 통한 메서드 호출

2️⃣ 문자열보다 적절한 다른 타입을 사용해라

💡 문자열은 진짜 문자열을 나타내는 경우에만 사용하자

  • 수치형이라면 int, float,BigInteger 등의 적당한 수치 타입으로 변환
  • 예/아니오 등의 형태라면 적절한 열거 타입이나 boolean 으로 변환
  • 권한은 key 클래스 로 사용
public final class ThreadLocal<T>{
  public ThreadLocal();
  public void set(T value);
  public T get();
}

3️⃣ 문자열 연결을 주의해라

💡 문자열을 연결해야 한다면 StringBuilder를 사용하자

이미 다 알고 있지?

  • String불변 객체
  • 두 문자열을 연결하는 경우, 양쪽 모두를 복사해야하기 때문에 성능 저하가 발생

4️⃣ 객체는 인터페이스로 참조해라

💡 적합한 인터페이스가 있다면 모두 인터페이스로 선언하자

  • 유연한 프로그램을 작성할 수 있음
  • 예로, 구현 클래스 교체가 필요한 경우 새로운 클래스의 생성자만 호출해주면 코드를 변경할 필요가 없음
// 이전 코드 
Set <Son> sonSet = new LinkedHashSet<>();
// 변경 코드
Set <Son> sonSet = new HashSet<>();

// 만약 인터페이스가 아니였다면?
LinkedHashSet<Son> sonSet = new LinkedHashSet<>();

선언문 뿐만 아니라, 기존 타입에서만 제공하는 메서드 등을 사용한 경우 컴파일이 되지 않는 문제가 발생한다.

이때, 구현 클래스를 교체할 때는 해당 클래스만이 제공하는 특별한 기능을 사용하는지를 확인해야 한다.

  • 만약, 위의 코드에서 LinkedHashSet 이 따르는 순서 정책을 사용하고 있었다면?

적합한 인터페이스가 없는 경우

  1. String, BigInteger 등의 값 클래스
  2. 클래스 기반으로 작성된 프레임워크가 제공하는 객체
  3. 인터페이스에는 없는 특별한 메서드를 제공하는 클래스

=> 클래스의 계층 구조 중 필요한 기능을 만족하는 가장 덜 구체적인 클래스를 타입으로 사용해라.

🍃 결론

📌 사용할 수 있다면, 우선적으로 사용해야 할 것들

  • 기본 타입
  • 적절한 데이터 타입
  • StringBuilder
  • 인터페이스

reference

@ChoiSeEun ChoiSeEun self-assigned this Dec 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant