작성자 : 프람
작성 일시: 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를 발생시킵니다.
메모리/시간 효율성
- 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
- 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값 내부의 의미를 담을 때만 박싱된 기본 타입을 씁시다.
'독서 감상문 > Effective Java' 카테고리의 다른 글
Ordinal 인덱싱 대신 EnumMap을 사용하라 (0) | 2024.05.16 |
---|---|
비트 필드 대신 EnumSet을 사용하라 (0) | 2024.05.16 |
배열보다는 리스트를 사용하라 (0) | 2024.05.09 |
비검사 경고를 제거하라 (0) | 2024.05.06 |
로 타입은 사용하지 말라 (0) | 2024.05.06 |