Java 래퍼 메소드
앞서 Wrapper 의 기본형과 Integer 같은 객체 클래스 전환을 알아보았다.
다음으로 Wrapper 관련 메소드를 살펴보도록 한다.
Integer 래퍼클래스로 반환하는 메소드 - valueOf
Integer i1 = Integer.valueOf(100); // 래퍼 객체로 반환
Integer i2 = Integer.valueOf("100"); // 래퍼 객체로 반환
Integer 타입으로 Wrapper 클래스 반환 방법은 Integer.valueOf(int i) 메소드를 사용한다.
Integer 클래스는 이미 자바에서 모듈 지원하기에 바로 사용할 수 있다.
오버로딩 지원으로 Integer.valueOf(String s) 메소드 사용으로 다른 타입으로 반환할 수 있다.
문자열을 기본형으로 반환하는 메소드 - parseInt
int value = Integer.parseInt("10"); // 문자열 전용, 기본형 반환
문자열을 기본형 타입으로 반환하는 방법이다. 많이 사용한다.
비교 메소드 - compareTo
Integer i1 = Integer.valueOf(100);
int result1 = i1.compareTo(100);
int result2 = i1.compareTo(99);
int result3 = i1.compareTo(101);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
0
1
-1
Integer 타입의 변수에서도 compareTo 메소드를 사용 가능하다.
합계 - sum
System.out.println(Integer.sum(100,200));
300
기본형으로 반환되는 sum 함수도 포함되어있다. static 으로 정의되어있다.
최소 값 구하기 - min
System.out.println(Integer.min(100,200));
100
최소 값 찾는 메소드. static 으로 정의되어있다.
최댓값 구하기 - max
System.out.println(Integer.max(100,200));
200
최댓 값 구하는 메소드. static 으로 정의되어있다.
산술 연산자 sum, min, max 특징은 빠른 연산이 필요하여 스태틱으로 정의하여 미리 메모리에 탑재되어있다.
래퍼와 기본형 반환 성능
래퍼 클래스는 Integer 객체에서 기본형보다 많은 기능을 제공하고 있다.
그러나 연산 메소드 같은 경우 반환이 기본 형인 것을 볼 수 있는데 성능 문제가 있어서 그렇다. Wrapper를 사용하게 되면 오토박싱과 오토언박싱으로 인한 성능 문제가 발생되는데. 이러한 문제를 최소화하고 실수를 방지하기 위함이다.
기본형과 래퍼 클래스의 성능 차이를 알아보자
public class Main {
public static void main(String[] args) {
int iter = 100_000_000; // 산술 연산 반복 횟수
long startTime, endTime;
// 기본형 long 연산 처리
long sumPrimitive = 0;
startTime = System.currentTimeMillis();
for(int i = 0; i < iter; i++) {
sumPrimitive += i;
}
endTime = System.currentTimeMillis();
System.out.println("Sum of primitive values is " + sumPrimitive);
System.out.println("Total time spent in iteration " + iter);
System.out.println("long Processing Total time:" + (endTime - startTime) + " ms");
}
}
Sum of primitive values is 4999999950000000
Total time spent in iteration 100000000
long Processing Total time:38 ms
기본형(long) 산술 처리 비용은 38ms 만큼 발생하였다.
다음은 Wrapper로 감싼 Long 객체로 연산하여 비용처리를 알아보자
public class Main {
public static void main(String[] args) {
int iter = 100_000_000; // 산술 연산 반복 횟수
long startTime, endTime;
// Wrapper Long 연산 처리
Long sumWrapper = 0L;
startTime = System.currentTimeMillis();
for(int i = 0; i < iter; i++) {
sumWrapper += i; // 자동으로 오토 박싱이 일어남
}
endTime = System.currentTimeMillis();
System.out.println("Sum of primitive values is " + sumWrapper);
System.out.println("Total time spent in iteration " + iter);
System.out.println("long Processing Total time:" + (endTime - startTime) + " ms");
}
}
Sum of primitive values is 4999999950000000
Total time spent in iteration 100000000
long Processing Total time:478 ms
변수 i형 기본형 연산 처리에 sumWrapper 객체가 오토박싱이 일어나 연산하였다.
오토박싱 처리까지 겸해 478 ms 비교적 높은 비용이 발생으로 성능이 저하된 것을 볼 수 있다.
성능 정리
- 기본형이 래퍼클래스보다 5~15배 성능차이 발생.
- 기본형은 메모리의 단순한 크기만큼 공간 차지, int형은 4바이트 메모리를 사용한다.
- 래퍼 클래스의 인스턴스 내부에 기본형 필드뿐아니라 객체를 다루는데 필요한 메타데이터를 포함하여 많은 메모리 발생. 자바 버전과 시스템 따라 8~16바이트 추가됨
기본형과 래퍼 중 무엇을 사용해야하는가?
단순 연산에는 메모리를 단순하게 사용하는 기본형 타입으로 연산하는 것이 좋지만 그러한 케이스는 얼마 없다.
예를 들어 벡터의 선형 데이터에서 인접한 데이터를 연산해 필터로 생성하는 그래픽 작업이 있었지만 직접 구현하는 것은 드물었고 이미 구현된 라이브러리에서 가져와 사용하는 것이 나았다.
래퍼 클래스는 객체 생성이 필요하고 불변의 특징을 갖고 있다. 연산에는 불리한 요소들이 있지만 유지보수 차원에서 지원하는 메소드가 있고 성능을 포기하더라도 유지보수를 택하는 것이 나을 수 있다.
최근 래퍼 관련 구현한 것 중 게임에서 주인공이 적에게 피해를 주었을 때 몇 경의 수치만큼 적 HP 깍는 것이 있었다. 이 경우 int형과 double형 처리할 경우 오버플로우가 예상되어 문자열 래퍼로 연산 처리하였다. 자원 비용이 매우 커서 이 로직은 Server에서 처리하고 싶지 않았고. 피해를 받았을 경우 Client가 HP 로직을 처리하고 결과를 Server에게 전송하는 것이 있었는데, 나쁜 선택은 아니었다.
유지보수냐 최적화냐..
개발을 진행하면 고려 대상 중 하나로 유지보수로 꼽을 수 있는데, 대도록이면 유지보수가 가능하도록 택한다. 그렇다 보니 성능 이슈가 발생할 수 있는데, 성능 이슈로 인한 문제는 해결된다 하더라도 소비자 또는 사용자에게는 미비할 수 있다.
최적화 정리
- 코드 변경 없이는 성능 최적화가 거의 일어나지 않는다.
- 최적화 작업의 코드 변경으로 인한 단순한 것보다 복잡한 구현을 요구된다.
- 유지보수 대상이 많아진다. 즉, 불분명한 코드 생성이 많아진다.
- 최적화가 된 코드를 추가되어도 실제 소비자나 사용자에게 성능 향상 경험은 미비할 수 있다.
- 백엔드 또는 웹에서 메모리 연산보다 네트워크 호출 지연이 크다.
- 메모리를 몇 억을 연산하는 것보다 네트워크 호출이 오래 걸린다.
- 메모리보다 네트워크 호출을 한번이라도 줄이는 최적화를 진행한다면 성능을 크게 개선할 수 있다.
- 개발 완료한 이후 성능 테스트를 진행하여 정말 문제가 발생되는 병목과 지연이 있는지 확인하여 개선하는 것이 좋다.
최적화 진행한 일례의 사례로,
모니터링에서 지속적으로 100ms 이상의 핑이 발생되는 게임이 있었고 당시 리뷰의 평은 핑이 높아서 불만족을 표하고 있었다. 이것을 본 개발자는 모니터링 표시 핑만 20ms 근처로 변경했을 뿐인데 좋은 리뷰가 달렸다.
표시 값만 변경해도 사용자 경험이 높아지는 사례이다.