쵸오오오오오오오오잉 입니다
발생 배경 & 문제 상황
- 국비 수업 중 scanner로 입력을 받을 때 nextInt()와 nextLine()을 연달아서 입력했더니 nextLine() 이 무시되고 오류가 발생
- 줄 바꿈이 버퍼에 남아 이런 오류가 발생했고 nextLine() 하고 정수변환을 하는 것으로 결론이 났지만 왜 버퍼에 남아있을지 의문이 생겨 Scanner 내부를 분석해 봄
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt(); // 아무 숫자나 입력하고 엔터를 치는 순간 NumberFormatException 발생
int b = Integer.parseInt(sc.nextLine());
System.out.println(a);
System.out.println(b);
}
}
```bash
2
4
위 와 같은 정수 2개를 입력하려 했으나 엔터를 치는 순간 NumberFormatException: For Input String :"" 발생

원인 분석
이런 현상이 발생하는 이유는 next()
- nextInt()는 내부적으로 next()를 호출하고 입력받은 값에 정수로 변환해 주는 함수
- next() 함수는 자바 스캐너에 선언된 구분자(delimeter) 기준으로 토큰을 구분
- delimeter의 기본값은 javaWhiteSpace인데 이는 줄 바꿈 공백 탭 등이 포함된 값임

- delimeter의 기본값은 javaWhiteSpace인데 이는 줄 바꿈 공백 탭 등이 포함된 값임
next()의 입력 처리 과정
Matcher라는클래스를 통해Pattern을 기준으로 토큰을 끊음- delimeter 가 있기 전까지의 위치까지 토큰으로 처리
- 단 delimeter 자체를 소비하진 않음 버퍼에 남아있음
- delimeter 처음 나오는 delimeter는 skip 함
위와 같은 과정을 반복
문제 상황 분석
- 문제가 발생한 입력을 string으로 변환해서 생각하면
2\n4임 - next()는 delimeter (기본값인 줄 바꿈 공백 탭) 이 오게 되면 delimeter 가 나오기 바로 전까지의 '토큰'을 반환함
- 단 deleimeter 토큰 자체를 소모하는 건 아님 버퍼에는 남아있음
- 2라는 토큰을 반환하고 nextInt()를 통해 정수변환
- 스캐너 버퍼에는 2를 처리하고 \n4를 처리해야 됨
- nextLine() 은 \n을 보는 순간 바로 입력 처리함 근데 \n 전에는 아무 값이 없기 때문에 "" 공백을 정수로 변환하지만 예외 발생
해결 방안
-
- nextLine()으로 \n 소모
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
sc.nextLine();
int b = Integer.parseInt(sc.nextLine());
System.out.println(a);
System.out.println(b);
}
}
-
- nextInt() nextLine() 혼용해서 사용하지 않기
import java.util.*;
- nextInt() nextLine() 혼용해서 사용하지 않기
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = Integer.parseInt(sc.nextLine());
int b = Integer.parseInt(sc.nextLine());
System.out.println(a);
System.out.println(b);
}
}
````
-
2 3\n이렇게 공백을 기준으로 입력받기 (nextLine()에서 trim() 처리해야 됨)
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = Integer.parseInt(sc.nextLine().trim());
// "2 4\n" 일경우 2는 a 변수에 할당되고 " 4" 가 nextLine() 에 들어가기때문에 공백처리
System.out.println(a);
System.out.println(b);
}
}
결론
Scanner의 next() 계열(nextInt(), nextDouble() 등)은 입력에서 delimiter 기준으로 토큰만 읽고, delimiter는 버퍼에 남긴다.- 그래서
nextInt()다음에 곧바로nextLine()을 쓰면,nextInt()호출 뒤에 남아 있던 줄 바꿈 문자(\n)만 읽고 끝나버려서 빈 문자열을 반환한다. - 이때 빈 문자열을
Integer.parseInt()하면 NumberFormatException 발생! - 입력을 깔끔하게 다루려면 BufferedReader + StringTokenizer 로 하는 것이 버퍼 사이즈도 더 크고 빠름