본문 바로가기
독서 감상문/Effective Java

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

by 프람6 2024. 6. 7.

작성자 : 프람
작성 일시: 2024.06.07

박싱 기본 타입

  • Integer
  • Double
  • Float
  • Boolean
  • Long
  • Byte
  • Short

기본타입

  • int
  • long
  • double
  • float
  • boolean
  • byte
  • short

차이점

1. 식별성

다들 알다시피 Integer 박싱 기본타입은 equals의 구현으로 같은 값이라 할지라도 동등성만 보장하고 동일성은 보장하지 않는다는 사실을 잘 알겁니다.
그럼 여기서 퀴즈

~

🎯QUIZ1.

@Test  
@DisplayName("차이점1-1. 식별성")  
void difference1_1() {  
    int primitiveNumber1 = 10;  
    int primitiveNumber2 = 10;  

    Integer wrappingNumber1 = 10;  
    Integer wrappingNumber2 = 10;  
    assertThat(primitiveNumber1).isEqualTo(primitiveNumber2);  
    assertThat(wrappingNumber1).isEqualTo(wrappingNumber2);  
    assertThat(primitiveNumber1).isSameAs(primitiveNumber2);  
    assertThat(wrappingNumber1).isSameAs(wrappingNumber2);  
}

해당 테스트는 잘 통과할까요??????

✅ Answer1.

AssertionError 없이 잘통과됩니다. 뭔가 이상하지 않으신가요??

이유를 정확하게 맞추시는 분께는 소정의 선물을 드리겠습니다.

 

private static class IntegerCache {  
    static final int low = -128;  
    static final int high;  
    static final Integer[] cache;  
    static Integer[] archivedCache;  

    static {  
        // high value may be configured by property  
        int h = 127;  
        String integerCacheHighPropValue =  
            VM.getSavedProperty("java.lang.Integer.IntegerCache.high");  
        if (integerCacheHighPropValue != null) {  
            try {  
                h = Math.max(parseInt(integerCacheHighPropValue), 127);  
                // Maximum array size is Integer.MAX_VALUE  
                h = Math.min(h, Integer.MAX_VALUE - (-low) -1);  
            } catch( NumberFormatException nfe) {  
                // If the property cannot be parsed into an int, ignore it.  
            }  
        }  
        high = h;  

        // Load IntegerCache.archivedCache from archive, if possible  
        CDS.initializeFromArchive(IntegerCache.class);  
        int size = (high - low) + 1;  

        // Use the archived cache if it exists and is large enough  
        if (archivedCache == null || size > archivedCache.length) {  
            Integer[] c = new Integer[size];  
            int j = low;  
            for(int i = 0; i < c.length; i++) {  
                c[i] = new Integer(j++);  
            }  
            archivedCache = c;  
        }  
        cache = archivedCache;  
        // range [-128, 127] must be interned (JLS7 5.1.7)  
        assert IntegerCache.high >= 127;  
    }  

    private IntegerCache() {}  
}

Integer 내부 코드를 뜯어보니 -128 ~ 127까지는 캐시를 이용해 캐시에서 저장해서 사용하네요~~ 그래서 테스트가 통과한겁니다.

@Test  
@DisplayName("차이점1-2. 식별성")  
void difference1_2() {  
    Integer wrappingNumber1 = 128;  
    Integer wrappingNumber2 = 128;  

    assertThat(wrappingNumber1).isSameAs(wrappingNumber2);  
}

 

이렇듯 설정한 캐시범위를 벗어나면 당연히 동등하지 않으므로 동등성 비교는 실패하게 됩니다.
정~말 유익하죠??

2. Nullable

미션을 진행하면서 지긋지긋하게 들었죠??
원시타입과 래핑타입의 크나큰 차이 중 하는
nullable하냐 아니냐의 차이겠죠??

🎯QUIZ2.

public class Unbelievable {  
    static Integer i;  

    public static void main(String[] args) {  
        if (i == 42) {  
            System.out.println("믿을 수 없군!!");  
        }  
    }  
}

위 코드를 실행 시키면 결과는?

✅ Answer1.

if(i == 42)를 비교하는 과정에서 auto unboxing이 일어나는데 이때 Integer는 nullable하기 때문에 null값을 가지고 있는 상태에서 boxing/unboxing을 할경우 NPE를 발생시킵니다.

메모리/시간 효율성

  1. Wrapping
```java
@Test  
@DisplayName("메모리/시간 효율성-1")  
void difference3_1() {  
    long start = System.currentTimeMillis();  
  
    Integer sum = 0;  
    for (Integer i = 0; i < 1000000; i++) {  
        sum += i;  
    }  
    long end = System.currentTimeMillis();  
  
    System.out.println(end - start);  
}
```

 

대략 10~20ms

    1. Primitive실행 시간
@Test  
@DisplayName("메모리/시간 효율성-2")  
void difference3_2() {  
    long start = System.currentTimeMillis();  
  
    int sum = 0;  
    for (int i = 0; i < 1000000; i++) {  
        sum += i;  
    }  
    long end = System.currentTimeMillis();  
  
    System.out.println(end - start);  
}
대략 2~3ms

엄청난 차이를 보입니다.

마무리/ 결론

책에 예시 코드가 몇가지 더 있긴한데.. 그닥 도움안될거 같아 건너뛸게요~.
프람의 기준
컬렉션과 같이 매개변수화 타입일때와 의도적으로 null값 내부의 의미를 담을 때만 박싱된 기본 타입을 씁시다.