자바

[ JAVA ] Scanner nextInt() 와 nextLine() 을 같이썻다가 억장 와르르

@ChoIng 2025. 6. 20. 21:48

쵸오오오오오오오오잉 입니다

발생 배경 & 문제 상황

  • 국비 수업 중 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인데 이는 줄 바꿈 공백 탭 등이 포함된 값임

next()의 입력 처리 과정

  1. Matcher라는 클래스를 통해 Pattern 을 기준으로 토큰을 끊음
  2. delimeter 가 있기 전까지의 위치까지 토큰으로 처리
    • 단 delimeter 자체를 소비하진 않음 버퍼에 남아있음
  3. delimeter 처음 나오는 delimeter는 skip 함
    위와 같은 과정을 반복

문제 상황 분석

  • 문제가 발생한 입력을 string으로 변환해서 생각하면 2\n4
  • next()는 delimeter (기본값인 줄 바꿈 공백 탭) 이 오게 되면 delimeter 가 나오기 바로 전까지의 '토큰'을 반환함
    • 단 deleimeter 토큰 자체를 소모하는 건 아님 버퍼에는 남아있음
  • 2라는 토큰을 반환하고 nextInt()를 통해 정수변환
  • 스캐너 버퍼에는 2를 처리하고 \n4를 처리해야 됨
  • nextLine() 은 \n을 보는 순간 바로 입력 처리함 근데 \n 전에는 아무 값이 없기 때문에 "" 공백을 정수로 변환하지만 예외 발생

해결 방안

    1. 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);  
    }  
}
    1. nextInt() nextLine() 혼용해서 사용하지 않기
      import java.util.*;
      

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);
}
}

````

    1. 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 로 하는 것이 버퍼 사이즈도 더 크고 빠름