빌려온 가나디
코딩 테스트에서 자바 입출력 받기 (BufferedReader, StringTokenizer, java.util.NoSuchElementException) 본문
코딩 테스트에서 자바 입출력 받기 (BufferedReader, StringTokenizer, java.util.NoSuchElementException)
daun_up 2026. 1. 31. 18:16파이썬으로 코딩 테스트를 풀다가 SSAFY 과정 덕에 자바로 언어를 바꾸게 되었다.
어떻게든 쉽게 가고 싶어서 버티다가 져버림...
Scanner
자바에서 입력을 받을 때는
Scanner sc = new Scanner(System.in); 을 사용했었다.
입력을 읽고 공백/줄바꿈 기준으로 쪼개고 int, double, String 으로 자동 변환하는 것을 한 번에 해준다고 한다.
내부적으로는 아래와 같은 과정을 거친다.
- InputStream에서 문자 단위로 읽음
- 정규식(regex)으로 구분자 처리
- 타입 검사 (int인지, double인지)
- 파싱 실패 시 예외 처리
딱 봐도 많은 걸 해주고 있다는 것은 무겁다는 뜻이다! 입력 개수가 많고 시간 제한이 빡빡할 때는 쓰기가 어렵다.
Scanner 를 썼을 때는 10 20 30 40 50 이라는 입력이 주어졌을 때 int a = sc.nextInt(); 로 하나 읽고, 또 다음 b 읽고 문자 단위로 입력을 읽어들인다. '1' → '0' → ' ' → '2' → '0' → ' ' → ... 이렇게 공백 기준으로 한 글자씩 읽는데 기본 구분자 자체가 정규식이고, 토큰 분리 과정에 정규식 매칭을 동반한다.
BufferedReader + StringTokenizer
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
BufferedReader 입력 방식을 사용했을 때는, 한 줄을 통째로 읽어들이기 때문에 StringTokenizer 를 추가로 사용해주어야 한다.
"10 20 30 40 50" 이렇게 한 줄이 입력되어 내부적으로 버퍼(배열)을 사용한다.
해당 줄을 StringTokenizer 가 스캔하고 공백 기준으로 위치를 기억한다. 문자열을 실제로 쪼개는 것이 아니라, 인덱스만 이동한다.
그래서 st.nextToken(); 를 호출하면 포인터가 이동되고, 문자열이 반환된다. 그래서 int, double 등을 입력 받을 때 int a = Integer.parseInt(st.nextToken()); 이렇게 형 변환을 해주어야 한다.
java.util.NoSuchElementException
근데 자꾸 이런 에러가 났다. nextToken()을 호출했는데 더 이상 토큰이 없을 때 나는 에러라고 한다.
즉, 입력 개수 가정이 틀리거나(토큰 부족), 빈 줄이 들어와 토큰이 0개인데 nextToken()을 호출하면 예외가 난다.
근데 난 그런 적이 없다고 생각했다... 그러면 왜 이런 상황이 생기는가? 그 이유는 st 를 재사용했기 때문이다.
5
3.0 2.8 4.0 3.5 3.9
이런 입력을 받을 때 위에 n 도 st 로 받아버리고 싶었다!
int n = Integer.parseInt(br.readLine()); 한 개이기 때문에 이렇게 받아도 되지만 만약 st 로 받고자 한다면?
// 문제가 된 코드!
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
double sum = 0;
for (int i = 0; i < n; i++) {
sum += Double.parseDouble(st.nextToken());
}
java.util.NoSuchElementException 예외가 생긴 코드는 이 코드이다.
- br.readLine()
- 첫 줄 "5"를 읽음
- st = new StringTokenizer("5")
- st 안 토큰: [ "5" ]
- int n = Integer.parseInt(st.nextToken());
- "5" 꺼냄 → n = 5 가 되고, 이제 st는 토큰이 0개이다.
-
sum += Double.parseDouble(st.nextToken());
- for문 시작!! 그 런 데 st에 더 이상 토큰이 없음... 그래서 st.nextToken()에서 바로 예외 발생
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
sum += Double.parseDouble(st.nextToken());
}
그래서 이와 같이 재생성 해주어야 한다. StringTokenizer 는 줄이 바뀌면 다시 만들어줘야 한다!
그리고 추가로 안전 장치를 걸어둘 수도 있다.
hasMoreTokens()
이 메서드로 nextToken 을 호출하기 전에 항상 미리 확인한다.
while (st.hasMoreTokens()) {
int num = Integer.parseInt(st.nextToken());
}'Java' 카테고리의 다른 글
| 올바른 싱글톤을 구현하는 방법 (0) | 2026.02.08 |
|---|