Comparator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);
public class Main {
public static void main(String[] args) {
Comparator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);
System.out.println(naturalOrder.compare(new Integer(42), new Integer(42)));
}
}
1
을 반환한다.public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
equals 의 경우에는 value 값 끼리 비교를 하도록 되어 있지만,
(i == j)
false
를 반환1
을 반환하게 된다.Comparator.naturalOrder()
를 사용하라.이해가 되지 않는 점.
Comparator.naturalOrder()
말고도 스트림API 에서의 String 등에서 sorted() 로도 동일한 결과를 출력한다명시적으로
naturalOrder()
를 사용해야할 이유가 있는지 솔직히 의문임.
Comparator<Integer> naturalOrder = (iBoxed, jBoxed) -> {
int i = iBoxed, j = jBoxed; // 언박싱
return i < j ? -1 : (i == j ? 0 : 1);
};
public class Main {
static Integer i;
public static void main(String[] args) {
if (i == 42)
System.out.println("믿을 수 없군!");
}
}
//Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "아이템61.Main.i" is null
null
로 초기화 된다.근데.. 엔티티나 VO 에서는 보통 래퍼타입을 사용하는 경우가 많다
- 그 이유는 JPA 같은 경우 엔티티 필드를 매핑하는 경우 객체 타입을 선호하는 경우가 많다고 한다
- 이유
- DB 의 NULLABLE 컬럼을 표현할 수 있으며
- 객체 지향적인 설계
- JPA 는 객체지향적 패러다임을 DB 에 매핑하는 것이 목표라고 한다
- Java 의 객체지향적 특성을 더 잘 활용할 수 있기에, 엔티티에는 래퍼타입을 좀 더 선호한다고 한다
- 물론 NULL 값이 들어가지 않는 경우는 기본타입을 두는 게 더 나을 수 있다고 생각한다.
count
같은 값은 기본적으로 0 부터 시작하는 경우가 있다.- 타입의 안정성
- 제네릭과 함께 사용하는 경우 타입 안정성을 부여가능하다
- 리플렉션 활용
JPA 의 경우 내부적으로 리플렉션을 많이 사용한다고 한다.
엔티티 자체에 변수가 private 으로 선언된 경우가 많기에, getter/setter 없이 필드값을 읽고 쓰기 위해 → 리플렉션을 자체적으로 사용한다고 함.
// 엔티티 클래스의 모든 필드를 가져옴 Field[] fields = User.class.getDeclaredFields();
- 이런식으로 모든 필드를 가져와서
- 컬럼 어노테이션이 존재하는지, 필드 값을 읽고 필드 타입을 확인하는 등의 절차를 거친다고함.
기본타입보다는 래퍼타입이 리플렉션 API 와 더 친하다고 한다.
public class Main {
public static void main(String[] args) {
// 래퍼 클래스 Long 사용
long startTime1 = System.currentTimeMillis();
Long sumObject = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sumObject += i;
}
long endTime1 = System.currentTimeMillis();
System.out.println("Long 결과: " + sumObject);
System.out.println("Long 실행 시간: " + (endTime1 - startTime1) + "ms");
// 기본 타입 long 사용
long startTime2 = System.currentTimeMillis();
long sumPrimitive = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sumPrimitive += i;
}
long endTime2 = System.currentTimeMillis();
System.out.println("long 결과: " + sumPrimitive);
System.out.println("long 실행 시간: " + (endTime2 - startTime2) + "ms");
}
}
Long 결과: 2305843008139952128
Long 실행 시간: 4184ms
long 결과: 2305843008139952128
long 실행 시간: 459ms
박싱과 언박싱의 과정을 매 연산마다 수행
Long
으로 박싱을 수행 후객체 생성 오버헤드 발생
Long.valueOf(1L);
는
@IntrinsicCandidate
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
Long
값을 반환하겠지만,new Long
을 통해 매번 객체를 생성하게 된다.메모리 사용
컬렉션의 원소, 키 ,값으로 사용
매개변수화 타입이나 매개변수화 메서드의 타입 매개변수로 사용
매개변수화 메서드?
- Parameterized Method
- 이라고 함.
- 제네릭 메서드에 타입 인자를 넣어서 구체화한 메서드를 말한다.
- ex
<T> void printArr(T[] array)
- 책에서는
ThreadLocal<T>
의 케이스를 예시로 들었는데- ThreadLocal 의 경우도 제네릭클래스이기에 기본 타입을 사용불가능하다..
- 그래서 걍 해당 예시를 든거같다.
리플렉션을 통한 메서드 호출의 경우