Integer.valueOf VS Integer.parseInt

728x90

 

들어가기전에


 

int형으로 바꿔주는게 valueOf말고 parseInt가 또 있네??

 

알고리즘 문제를 풀다보면 문자열을 숫자로 바꿔야 하는 일이 정말 많다. 특히 입력 값을 받을 때 숫자로 받아야 하는 일이 대부분인데 나는 보통 Integer.valueOf를 위주로 사용했다. 문자열로 바꿀 때 String.valueOf를 사용했는데 Integer도 똑같이 있는 것을 발견하고 그 이후로는 그대로 valueOf를 사용하면서 문제를 풀었다.

 

하지만 알고리즘 문제를 풀면서 다른사람의 코드를 비교하는데 어떤사람은 Integer.parseInt로 어떤사람은 Integer.valueOf로 사용하고 있다는 것을 발견했다. 문자열을 숫자로 바꾸는 메소드가 2개나 있다는 것이다!

 

왜 둘다 숫자로 바꿔주는 역할은 같은데 메소드가 2개나 있는지 한번 알아보고 이 2개의 메소드의 차이점도 공부해보자.

 

구현 코드를 확인해 보자


Integer.parseInt의 종류

일단 사람들이 많이 사용하는 메소드인 Integer.parseInt를 확인해보자. parseInt의 구현 코드를 보면 다음과 같다.

 

Integer.parseInt의 3가지 종류

 

파라미터에 따라 총 3가지의 종류가 있다는 것을 알 수 있다. 각각의 쓰임새는 다음과 같다.

 

  • parseInt(String s, int radix)
    • s를 radix진수로 변환
  • parseInt(CharSequence ch, int start,int end, int radix)
    • 문자 배열 ch 중 start부터 end까지만 radix진수로 변환
  • parseInt(String s)
    • s를 10진수로 변환

 

가장 많이 쓰이는 것은 10진수로 바꾸는 parseInt(String s) 이기 때문에 해당 메소드를 한번 들어가보자.

 

Integer.parseInt의 구현 코드

 

Integer.parseInt의 구현 메소드는 다음과 같다.

 

    public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
    }

 

10진수로 바꾸는 메소드에 걸맞게 내부적으로 parseInt(String s, int radix)를 호출해 10진수로 바꾸는 것을 알 수 있다. 그럼 이제 parseInt(String s, int radix)를 살펴보자. 코드가 길고 복잡하지만 예외처리를 다 제거하고 간단한 수도코드로 표현하면 다음과 같이 남는다.

 

public static int parseInt(String s, int radix){
     	부호 확인       
        
        while (문자열 처음부터 끝까지) {
            i번째 자리수 계산
          	자리수 높이기
            현재 값에서 자리수 빼기
        }
        return 음수면 그대로, 양수면 양수화;
    }

 

이에따라 paresInt를 요약하면 문자열의 각 자리수에 해당되는 숫자로 바꾸고 이를 int형으로 리턴하는 것을 알 수 있다.

 

Integer.valueOf의 종류

이번엔 Integer.valueOf를 확인해보자. Integer.valueOf의 종류는 다음과 같이 3가지가 있다.

 

Integer.valueOf의 종류

 

각 메소드를 정리하면 다음과 같다.

 

  • valueOf(String s, int radix)
    • rardix진수로 s를 변환
  • valueOf(String s)
    • 10진수로 s를 변환
  • valueOf(int)
    • int를 Integer로 변환

 

우리가 가장 많이 쓰는 것은 Integer.valueOf(String s)이기 때문에 Integer.valueOf(String s)의 구현 코드를 확인해보자.

 

Integer.valueOf의 구현 코드

Integer.parseInt의 구현 코드는 다음과 같다.

 

public static Integer valueOf(String s) throws NumberFormatException {
        return Integer.valueOf(parseInt(s, 10));
    }

 

내부적으로 parseInt를 실행한 뒤 Integer.value(int)를 실행한다는 것을 알 수 있다! Integer.value(int)를 확인해보면 다음과 같다.

 

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

 

내부적으로 Integer.Cache 범위안에 있다면  Integer.Cache의 값을 리턴하는 것을 알 수 있다. Integer.Cache는 Integer의 캐싱기능으로 -128 ~ 127 범위의 값이라면 새로 객체를 만들지 않고 캐싱에 저장되어 있는(배열로 만들어져있는) 객체를 주는 역할을 한다. 

캐싱이 안되어있는 값이라면 그대로 Integer 객체를 생성해서 리턴하는 것을 알 수 있다.

 

Integer.valueOf vs Integer.parseInt

위의 코드를 정리하면 Integer.valueOf와 Integer.parseInt의 차이점은 다음과 같다.

 

Integer.valueOf : Integer 객체 반환
Integer.parseInt : int형 반환

 

Integer.valueOf는 객체를 반환하기 때문에 Integer.parseInt보다 성능은 느릴 수 있으나 객체이기 때문에 여러 메소드를 사용할 수 있다는 장점이 있다. 

 

Auto-unboxing과 Auto-boxing


Integer.valueOf써도 int형으로 받아지던데??

그런데 Integer.valueOf를 쓴다고해서 우리는 Integer a = Integer.valueOf("10")로 굳이 받지 않고 int a = Integer.valueOf("10")으로 해도 똑같이 a에 10이 들어가는 것을 확인할 수 있다. 분명 Integer.valueOf는 Integer 객체를 반환하는데 원시타입인 int로 해도 받아지는 이유는 뭘까??

 

바로 자바 컴파일러가 자동으로 wrapper타입으로 변경(auto-unboxing)해주기 때문이다.

 

자바의 컴파일러는 값을 변수에 저장할 때 받는 원시타입인데 들어오는 입력값이 wrapper타입이라면 자동으로 타입을 변경(unboxing)하여 원시타입으로 변경해서 변수에 저장한다. 이를 auto-unboxing이라고 부른다. 반대로 들어오는 값은 원시타입인데 받는 변수의 형이 wrapper타입이라면 자동으로 타입을 변경(boxing)하는 것을 auto-boxing이라고 부른다.

 

오토언박싱과 오토박싱에 관련된 글은 oracle 공식문서에서 확인할 수 있다. 자세한 내용은 하단의 문서를 보는 것을 추천한다. 

https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

 

Autoboxing and Unboxing (The Java™ Tutorials > Learning the Java Language > Numbers and Strings)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

자바 컴파일러가 자동으로 형변환해주는 타입들은 총 8개로 다음과 같다.

 

원시 타입(Primitive type) Wrapper 타입
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double double

 

 

Integer.valueOf와 Intager.parseInt의 오토 언박싱 성능 비교


한번 오토 언박싱이 일어나면 성능차이가 얼마나 나는지 확인해보자. 실험에 사용한 코드는 다음과 같다.

 

public class Main {
    public static void main(String[] args) throws Exception {
        String s = "10000";
        int max = Integer.MAX_VALUE;

        long paresIntStart = System.nanoTime();

        int a = 0;

        for(int i=0;i<max;i++){
            a += Integer.parseInt(s);
        }

        long paresIntEnd = System.nanoTime();

        long valueOfStart = System.nanoTime();

        a = 0;

        for(int i=0;i<max;i++){
            a = Integer.valueOf(s);
        }

        long valueOfEnd = System.nanoTime();

        System.out.println("parseInt의 연산 시간 : "+(paresIntEnd - paresIntStart)/1000/1000+"ms");
        System.out.println("valueOf 연산 시간 : "+(valueOfEnd - valueOfStart)/1000/1000+"ms");
    }
}

 

문자열 100000을 Integer의 최대 값인 2^31-1번 만큼 Integer.valueOf와 Integer.parseInt를 실행시켰다. 그 결과는 다음과 같다.

 

parseInt vs valueOf 속도 차이

 

Integer.paresInt를 실행시간이 11,489ms만큼 걸렸고 Integer.valueOf는 11,810ms 시간이 걸렸다. 약 0.3초의 시간만큼 차이가나 오토언박싱으로 인해 Integer.valueOf가 Integer.paresInt보다 실행 속도가 느린 것을 확인하였다. 

 

마지막으로 Integer.valueOf가 Integer.paresInt의 차이점에 대하여 결론을 내리면 다음과 같다.

 

int형을 가지고 싶다면 -> Integer.parseInt
Integer형을 가지고 싶다면 -> Integer.valueOf

마무리


최종적으로 int를 원하면 parseInt를 Integer를 원하면 valueOf를 쓰는것이 좋으면 내부적으로 valueOf도 paresInt를 사용하기 때문에 효율을 중시하기 위해선 parseInt를 사용한는 것이 더 좋다는 것을 알게 되었다. 만약 코드의 효율을 올리고 싶다면 오토언박싱&박싱이 일어나는지를 확인하는 것도 좋을 것 같다.