Skip to content

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

@ChoiSeEun

Description

@ChoiSeEun

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions