Language/Java

Integer.parseInt()란 무엇인가?

사과만쥬 2024. 9. 8. 10:51

백준에서 자바로 문제를 풀 때 가장 많이 쓰는 것 중 하나가 아닐까 싶다.

import java.util.*;
import java.io.*;

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int t = Integer.parseInt(br.readLine());

기본적으로 위의 저 5줄은 박고 시작하는 편이다.

 

br.readLine()으로 입력을 받고 나서, 그 입력받은 String을 Integer로 변환해주는 수단임은 쉽게 유추할 수 있다. 

그럼 이것은 어떻게 작동할까?

인텔리제이를 이용해서 내부 구조를 하나씩 까본다.

 

 

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

 

일단 여기를 보면, String를 보면 parseInt를 실행한다는 것은 알겠다. 그러면 정수가 나오겠지.

여기까지는 쉽게 판단이 가능하다.

 

조금 더 들어가보도록 하자.

 

    public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        /*
         * WARNING: This method may be invoked early during VM initialization
         * before IntegerCache is initialized. Care must be taken to not use
         * the valueOf method.
         */

        if (s == null) {
            throw new NumberFormatException("Cannot parse null string");
        }

        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " greater than Character.MAX_RADIX");
        }

        boolean negative = false;
        int i = 0, len = s.length();
        int limit = -Integer.MAX_VALUE;

        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+') {
                    throw NumberFormatException.forInputString(s, radix);
                }

                if (len == 1) { // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s, radix);
                }
                i++;
            }
            int multmin = limit / radix;
            int result = 0;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                int digit = Character.digit(s.charAt(i++), radix);
                if (digit < 0 || result < multmin) {
                    throw NumberFormatException.forInputString(s, radix);
                }
                result *= radix;
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s, radix);
                }
                result -= digit;
            }
            return negative ? result : -result;
        } else {
            throw NumberFormatException.forInputString(s, radix);
        }
    }

 

        if (s == null) {
            throw new NumberFormatException("Cannot parse null string");
        }

 

일단 null이면 당연히 exception을 반환해줘야 하는 것이고.

 

        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " greater than Character.MAX_RADIX");
        }

 

radix 이 친구는 도대체 뭐지?

자바로 코테를 푼지 고작 두달 좀 넘긴 응애 자바러는(처음 백준 자바계정으로 문제 푼 날이 6월 30일..) radix가 뭔지 모른다. 그래서 찾아봤다.

 

 

 

자바 공식 문서에서 구글링을 해 보니 위와 같다고 한다.

해석해 보면

문자열과의 변환에 사용할 수 있는 최대 기수입니다.

 

이거는 MAX_RADIX이고

 

문자열과의 변환에 사용할 수 있는 최소 기수입니다.

이거는 MIN_RADIX이다.

 

 

radix를 영어로 해석하면 기수인데, 우리가 보통 말하는 2진수 16진수 할 때 그 진수이다.

 

그래서 우리가 사용할 수 있는 진수의 범위 안에 있는지 검사하는 것이었다.

진수값은 2부터 36진수까지 있으므로 해당 범위 안에 있는지 확인한다.

 

 

boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;

 

negative 이 변수는 음수인지 양수인지 판단해 주는 것이다.

하단에서 본다면

 

if (firstChar == '-') {
    negative = true;
    limit = Integer.MIN_VALUE;
}

 

음수인 경우(시작이 '-'인 경우) negative를 true로 바꿔주는 역할을 한다.

또한 음수인 경우 한도를 바꿔준다.

 

int multmin = limit / radix;
int result = 0;
while (i < len) {
    // Accumulating negatively avoids surprises near MAX_VALUE
    int digit = Character.digit(s.charAt(i++), radix);
    if (digit < 0 || result < multmin) {
        throw NumberFormatException.forInputString(s, radix);
    }
    result *= radix;
    if (result < limit + digit) {
        throw NumberFormatException.forInputString(s, radix);
    }
    result -= digit;
}
return negative ? result : -result;

 

아래를 하나씩 까보도록 하자.

 

Accumulating negatively avoids surprises near MAX_VALUE

위의 주석을 해석하면 아래와 같다.

마이너스로 누적하면 MAX_VALUE에 가까운 예상치 못한 상황을 방지할 수 있습니다.

 

 

i가 len보다 작을 때, 

int digit = Character.digit(s.charAt(i++), radix);

 

 

Character 클래스의 digit(char ch, int radix) 을 참조한다.

이걸 조금 더 파고들어가면

public static int digit(int codePoint, int radix) {
    return CharacterData.of(codePoint).digit(codePoint, radix);
}

위와 같은 코드가 나오는데, 

 

Character.digit()

이 메서드는 유니코드 문자를 주어진 진법으로 변환할 때 유용한 수단이다.

codePoint는 특정 문자의 유니코드 값을 나타낼 때 사용하며, radix는 진법을 나타낸다.

 

digit는 문자를 특정 문자로 변환할 때 사용하는 자바 내장 함수라고 볼 수 있다.

 

 

result *= radix;

10진법이면 현재 나온 결과값에 10을 곱하는 식으로 작동되는 것으로 보인다.

result -= digit;

변환이 끝났으면 변환 횟수를 줄이는 것으로 보인다.

 

왜냐면, 중간에

if (digit < 0 || result < multmin) {
    throw NumberFormatException.forInputString(s, radix);
}

digit가 음수이면 예외를 반환하도록 되어 있기 때문에.

 

 

 

일련의 과정이 끝나면, 

return negative ? result : -result;

삼항 연산자를 이용하여 result나 -result를 반환한다.