Integer.parseInt()란 무엇인가?
백준에서 자바로 문제를 풀 때 가장 많이 쓰는 것 중 하나가 아닐까 싶다.
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를 반환한다.