61. 박싱된 기본 타입보다는 기본 타입을 사용하라

2025. 2. 22. 14:17

자바의 데이터 타입

1. 기본형: int, double, boolean 등

2. 참조형: String, List, Integer, Double, Boolean 등

각각의 기본 타입에 대응하는 참조 타입 = 박싱된 기본 타입

 

주된 차이 세 가지

1. 기본 타입은 값만 가지고 있으나, 박싱된 기본 타입은 값 + 식별성을 가지고 있다. 즉 메모리 주소를 할당받는다.

그러므로 박싱된 기본 타입의 두 인스턴스는 값이 같아도 서로 다르다고 식별될 수 있다.

2. 기본 타입의 값은 언제나 유효한 반면 박싱된 기본 타입은 유효하지 않은 값, 즉 null을 가질 수 있다.

3. 기본 타입이 박싱된 기본 타입보다 시간과 메모리 사용면에서 더 효율적이다.

 

문제 1.

박싱된 기본 타입에 == 연산자를 사용하면 예상치 못한 에러가 발생할 수 있다.

Comparator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j) ? 0 : 1;

 

위와 같이 Integer.compare()을 사용하지 않고 직접 구현하면 ==연산자로 인해 주소값을 비교하기 때문에 값이 같아도 1이 나올 수 있다.

 

문제 2.

public class Unbelievable {
    static Integer i;

    public static void main(String[] args) {
        if (i == 42) {
            System.out.println("Unbelievable");
        }
    }
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "general.Unbelievable.i" is null
	at general.Unbelievable.main(Unbelievable.java:7)

i는 현재 null이다. (i == 42) 수행 과정에서 언박싱이 발생하는데 null을 언박싱하면 NPE가 터진다.

왜냐하면 기본 타입과 박싱된 기본 타입을 혼용한 연산에서는 박싱된 기본 타입의 박싱이 거의 예외 없이 자동으로 풀리기 때문이다.

 

문제 3.

public class Main {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        Long sum = 0L;
        for (long i = 0; i < 50_000_000; i++) {
            sum += i;
        }
        long endTime = System.currentTimeMillis();

        System.out.println("Long: " + (endTime - startTime));

        startTime = System.currentTimeMillis();
        long sum2 = 0L;
        for (long i = 0; i < 50_000_000; i++) {
            sum2 += i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("long: " + (endTime - startTime));
    }
}
Long: 336
long: 16

위처럼 박싱/언박싱이 계속 발생하면 속도가 현저히 느려진다.

 

그러면 박싱된 기본 타입은 언제 써야 하는가?

1. 컬렉션의 원소, 키, 값으로 쓴다.

2. 매개변수화 타입이나 매개변수화 메서드의 타입 매개변수로 쓴다.

3. 리플렉션을 통해 메서드를 호출할 때 쓴다.

method.invoke(someObject, Integer.valueOf(25));
public Object invoke(Object obj, Object... args)

즉 리플렉션으로 값을 가져와서 실제로 invoke()로 실행시킬 때는 Object를 받기 때문에 박싱된 기본 타입을 사용하여야 한다.

BELATED ARTICLES

more