📌 Java의 데이터 타입
- 기본 타입 : int, double, boolean 등
- 참조 타입 : String, Integer, Double, List 등
- 기본 타입은 모두 대응되는 참조타입이 있으며, 이를 박싱된 기본 타입이라 한다.
- Auto Boxing/Unboxing 덕에 두 타입을 구분하지 않고 사용할 수는 있지만, 주의해서 선택해야 한다.
📌 기본 타입 vs 박싱된 기본 타입
final int number1 = 1;
final int number2 = 1;
System.out.println(number1 == number2); // true
final Integer number3 = 1;
final Integer number4 = 1;
System.out.println(number3 == number4); // true
System.out.println(number3.equals(number4)); // true
final Integer number5 = new Integer(1);
final Integer number6 = new Integer(1);
System.out.println(number5 == number6); // false
System.out.println(number5.equals(number6)); // true
int number = null // 에러
Integer number = null; // 가능
- 기본 타입은 값만 가지지만, 박싱된 기본 타입은 값과 식별성(identity)이란 속성을 갖는다
- 기본 타입의 값은 언제나 유효하나, 박싱된 기본 타입은 유효하지 않은 값인 null을 가질 수 있다.
- 기본 타입이 박싱된 기본 타입보다 시간·메모리 측면에서 효율적이다.
📌 박싱된 기본 타입 이슈 3가지
1️⃣ 식별성(identity)
💡 박싱된 기본 타입에 == 연산자를 사용하면 오류가 일어난다.
아래는 Integer 값을 오름차순으로 정렬하는 비교자
Comprator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);
- 위 비교자의 심각한 결함이 궁금하다면, naturalOrder.compare(new Integer(42), new Integer(42))를 출력해보라. (1을 출력한다.)
- i == j 에서 값이 아닌, 두 객체 참조의 식별성을 검사하게 되어 잘못된 결과가 나온다.
Comprator<Integer> naturalOrder = (iBoxed, jBoxed) -> {
int i = iBoxed, j = jBoxed;
return (i < j) ? -1 : (i == j ? 0 : 1);
}
- 지역변수로 Auto Unboxing을 수행하고, 기본 타입 연산을 수행하면 식별성 검사가 이뤄지지 않는다.
- 애초에 equals를 사용하면 되는 부분이기도 하다.
2️⃣ 유효하지 않은 값(null)
💡 기본 타입과 박싱된 기본 타입을 혼용한 연산에서는 박싱된 기본 타입의 박싱이 자동으로 풀린다.
public class Unbelievable {
static Integer i;
public static void main(String[] args) {
if (i == 42)
System.out.println("믿을 수 없군!");
}
}
- 기본 타입인 42와 비교하면 i는 자동으로 Unboxing이 되는데, 초기값을 지정해주지 않아 NullPointerException이 발생한다.
- 초기값을 설정해주거나, Integer를 int로 선언해주었으면 적어도 NPE가 발생하지는 않았을 것이다.
3️⃣ Auto Boxing/Unboxing
public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
System.out.println(sum);
}
- 오류가 발생하진 않지만 auto boxing/unboing이 반복해서 일어나 성능이 현저하게 저하된다. (Item 6. 불필요한 객체 생성을 피하라)
📌 박싱된 기본 타입을 사용하는 경우
- Collection의 원소, 키, 값으로 쓰는 경우 (Collection은 기본 타입을 담을 수 없으므로)
- 매개변수화 타입이나 매개변수화 메서드(5장)의 타입 매개변수인 경우
- 리플렉션(Item 65)을 통해 메서드를 호출하는 경우