Home > Java > Java > ☕️[Java] 래퍼 클래스 - 주요 메서드와 성능

☕️[Java] 래퍼 클래스 - 주요 메서드와 성능
Java Programming Language Backend

☕️[Java] 래퍼 클래스 - 주요 메서드와 성능.

1️⃣ 주요 메서드.

  • 래퍼 클래스가 제공하는 주요 메서드를 알아봅시다.
public class WrapperUtilsMain {
    public static void main(String[] args) {
        Integer i1 = Integer.valueOf(10); // 숫자를 래퍼 객체로 변환.
        Integer i2 = Integer.valueOf("10");// 문자열을 래퍼 객체로 변환.
        int intValue = Integer.parseInt("10");// 문자열 전용 기능, 기본형으로 변환.

        // 비교
        int compareResult = i1.compareTo(20);
        System.out.println("compareResult = " + compareResult);

        // 산술 연산
        System.out.println("sum: " + Integer.sum(10, 20));
        System.out.println("min: " + Integer.min(10, 20));
        System.out.println("max: " + Integer.max(10, 20));
    }
}

실행 결과

compareResult = -1
sum: 30
min: 10
max: 20
  • valueOf() : 래퍼 타입을 반환합니다. 숫자, 문자열을 모두 지원합니다.
  • parseInt() : 문자열을 기본형으로 변환합니다.
  • compareTo() : 내 값과 인수로 넘어온 값을 비교합니다. 내 값이 크면 1, 같으면 0, 내 값이 작으면 -1을 반환합니다.
  • Integer.sum(), Integer.min(), Integer.max() : static 메서드입니다. 간단한 덧셈, 작은 값, 큰 값 연산을 수행합니다.

parseInt()와 valueOf()

  • 언제 parseInt()를 사용하고 valueOf()를 사용해야 할까요?
    • 원하는 타입에 맞는 메서드를 사용하면 됩니다.
  • valueOf("10") 는 래퍼 타입을 반환합니다.
  • parseInt("10") 는 기본형을 반환합니다.
    • Long.parseLong() 처럼 각 타입에 parseXxx() 가 존재합니다.

2️⃣ 래퍼 클래스와 성능.

  • 래퍼 클래스는 객체이기 때문에 기본형보다 다양한 기능을 제공합니다.
    • 그렇다면 더 좋은 래퍼 클래스만 제공하면 되지 기본형을 제공하는 이유는 무엇일까요?
    • 다음 코드를 실행해서 기본형과, 래퍼 클래스의 성능 차이를 비교해봅시다.
      public class WrapperVsPrimitive {
        public static void main(String[] args) {
        int iterations = 1_000_000_000; // 반복 횟수 설정, 10억
        long startTime, endTime;
      
        // 기본형 long 사용
        long sumPrimitive = 0;
        startTime = System.currentTimeMillis();
        for (int i = 0; i < iterations; i++) {
            sumPrimitive += i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("sumPrimitive = " + sumPrimitive);
        System.out.println("기본 자료형 long 실행 시간: " + (endTime - startTime) + "ms");
      
        // 래퍼 클래스 Long 사용
        Long sumWrapper = 0L;
        startTime = System.currentTimeMillis();
        for (int i = 0; i < iterations; i++) {
            sumWrapper += i; // 오토 박싱 발생
        }
        endTime = System.currentTimeMillis();
        System.out.println("sumWrapper = " + sumWrapper);
        System.out.println("기본 자료형 Long 실행 시간: " + (endTime - startTime) + "ms");
        }
      }
      

실행 결과 - M1 맥북 기준

sumPrimitive = 499999999500000000
기본 자료형 long 실행 시간: 346ms
sumWrapper = 499999999500000000
기본 자료형 Long 실행 시간: 1555ms
  • 기본형 연산이 클래스보다 대략 5배 정도 빠른 것을 확인할 수 있습니다.
    • 참고로 계산 결과는 시스템 마다 다릅니다.
  • 기본형은 메모리에서 단순히 그 크기만큼의 공간을 차지합니다.
    • 예를 들어 int는 보통 4바이트의 메모리를 사용합니다.
  • 래퍼 클래스의 인스턴스는 내부에 필드로 가지고 있는 기본형의 값 뿐만 아니라 자바에서 객체 자체를 다루는데 필요한 객체 메타데이터를 포함하므로 더 많은 메모리를 사용합니다.
    • 자바 버전과 시스템마다 다르지만 대략 8~16바이트의 메모리를 추가로 사용합니다.

기본형, 래퍼 클래스 어떤 것을 사용해야 할까?

  • 이 연산은 10억 번의 연산을 수행했을 때 0.3초와 1.5초의 차이입니다.
  • 기본형이든 래퍼 클래스든 이것을 1회로 환산하면 둘 다 매우 빠르게 연산이 수행됩니다.
    • 0.3초 나누기 10억, 1.5초 나누기 10억입니다.
  • 일반적인 애플리케이션을 만드는 관점에서 보면 이런 부분을 최적화해도 사막의 모래알 하나 정도의 차이가 날 뿐입니다.
  • CPU 연산을 아주 많이 수행하는 특수한 경우이거나, 수만 ~ 수십만 이상 연속해서 연산을 수행해야 하는 경우라면 기본형을 사용해서 최적화를 고려해야합니다.
    • 그렇지 않은 일반적인 경우라면 코드를 유지보수하기 더 나은 것을 선택하면 됩니다.

유지보수 vs 최적화.

  • 유지보수 vs 최적화를 고려해야 하는 상황이라면 유지보수하기 좋은 코드를 먼저 고민해야 합니다.
  • 특히 최신 컴퓨터는 매우 빠르기 때문에 메모리 상에서 발생하는 연산을 몇 번 줄인다고해도 실질적인 도움이 되지 않는 경우가 많습니다.
  • 코드 변경 없이 최적화를 하면 가장 좋겠지만, 성능 최적화는 대부분 단순함 보다는 복잡함을 요구하고, 더 많은 코드들을 추가로 만들어야 합니다.
    • 최적화를 위해 유지보수 해야 하는 코드가 더 늘어나는 것입니다.
    • 그런데 진짜 문제는 최적화를 한다고 했지만 전체 애플리케이션의 성능 관점에서 보면 불필요한 최적화를 할 가능성이 있습니다.
  • 특히 웹 애플리케이션의 경우 메모리 안에서 발생하는 연산 하나보다 네트워크 호출 한 번이 많게는 수십만배 더 오래 걸립니다.
    • 자바 메모리 내부에서 연산을 수천번에서 한 번으로 줄이는 것 보다, 네트워크 호출 한 번을 더 줄이는 것이 더 효과적인 경우가 많습니다.
  • 권장하는 방법은 개발 이후에 성능 테스트를 해보고 정말 문제가 되는 부분을 찾아서 최적화 하는 것입니다.