Search

아이템61 : 박싱된 기본 타입보다는 기본 타입을 사용하라

 자바의 데이터 타입 : 기본 타입과 참조 타입

기본 타입 : int, double, boolean, ...
박싱된 기본 타입 : 각 기본 타입에 대응하는 참조 타입을 의미한다. (Integer, Double, Boolean, ...)
참조 타입 : String, List, ...

 기본 타입과 박싱된 기본 타입

 이 둘의 차이점은 명확하게 알고 있자

“오토박싱과 오토언박싱으로 인해 두 타입을 크게 구분하지 않고 사용할 수 있다. 그러나 이 둘의 차이가 없어지는 것은 아니므로, 차이에 대해 명확하게 알고 있어야 한다.”
1.
기본 타입은 값만 가지고 있고, 박싱된 기본 타입은 값과 식별성(identity)이란 속성을 갖는다.
이로 인해 값이 같아도 다르다고 식별할 수 있다.
2.
기본 타입의 값은 언제나 유효하고, 박싱된 기본 타입은 유효하지 않은 값인 null을 가질 수 있다.
3.
기본 타입이 시간과 메모리 사용면에서 더 효율적이다.

 주의하지 않았을 때 발생할 수 있는 사례

== 연산자 주의할 점
Comparator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1); //0이 아닌 1을 출력한다 naturalOrder.compare(new Integer(42), new Integer(42)); /* * (i == j)는 두 객체의 참조의 식별성을 검사하기 때문에 첫 번째 Integer가 더 크다고 판단한다 * 따라서 박싱된 기본 타입에 == 연산자를 사용하면 오류가 발생할 수 있다. */
Java
null로 인한 문제
public class Unbelievable { static Integer i; public static void main(String[] args) { if (i == 42) //NPE가 발생할 수 있다 (타입이 Integer, i의 초깃값은 null) System.out.println("믿을 수 없군!"); } }
Java
성능 저하 문제
public static void main(String[] args) { Long sum = 0L; //박싱된 기본 타입 for (long i = 0; i <= Integer.MAX_VALUE; i++) { sum += i; //박싱과 언방싱이 반복해서 일어나 성능이 느려진다 } System.out.println(sum); }
Java

 언제 박싱된 기본 타입을 써야 할까?

컬렉션의 원소, 키, 값으로 사용할 때
즉, 매개변수화 타입이나 매개변수화 메서드의 타입 매개변수로는 박싱된 기본 타입을 써야 한다.
ThreadLocal<int>는 불가능하며, ThreadLocal<Integer>를 써야 한다.
리플렉션을 통해 메서드를 호출할 때 박싱된 기본 타입을 사용해야 한다.

 번외 : 기본 타입을 다루는 비교자가 필요한 경우

Comparator.naturalOrder()를 사용하자.
비교자를 직접 만들면 비교자 생성 메서드나 기본 타입을 받는 정적 compare 메서드를 사용하라.

 핵심 정리

기본 타입과 박싱된 기본 타입을 선택한다면 가능하면 기본 타입!
빠르고 간단하다.
박싱된 기본 타입은 주의하여 사용하자.
오토박싱이 번거러움을 줄여주긴 하지만 위험을 없애주지는 않는다.
== 연산자는 나의 의도를 고려하자.
같은 연산에서 기본 타입과 박싱된 기본 타입을 혼용하면 언박싱이 이루어진다.
이 과정에서 NPE를 조심하자.
기본 타입을 박싱하는 작업은 필요 없는 객체를 생성하는 꼴이 될 수 있다.