nextInt(), nextInt(), nextInt()...
이거는 문제가 없다.

nextLine(), nextLine(), nextLine()...
이거 역시 문제가 없다.

nxetInt(), nextLine(), next...
여기서 nextInt() 바로 다음의 nextLine()은 씹혀버린다.

 

사실 정확히 말하면 내 명령이 씹힌게 아니다.

우선 다음을 머릿속에 집어넣고 아래를 보자.

nextInt() -> System.in으로 입력 받은 시스템 값 중 Int값만 뽑아내 return 전까지 반환한다. (nextInt()를 사용하는 변수가 Int기 때문에 문자열이 들어오면 에러남.)
next() -> System.in으로 입력 받은 시스템 값 중 연속된 문자열값만 뽑아내 공백 전까지 반환한다. ('20주년'으로 입력할 경우 20주년 모두 문자열로 들어옴.)
nextLine() -> System.in으로 입력 받은 시스템 값 중 문자열 모두를 return을 포함해 반환한다.

 

nextInt()에 50을 입력했다고 하자.
그러면 Scanner(System.in)은 시스템으로부터 '5 + 0 + return' 이라는 3단계의 입력을 받는다.
nextInt()는 return 전까지 입력된 Int값을 반환하기 때문에 '5 + 0'만 반환하고, returnSystem.in에 그냥 남아있는다.

그 다음 nextInt()를 또 호출하고 20을 입력하면
Scanner(System.in)은 시스템으로부터 'return + + + return' 으로 앞에 남은 'return찌꺼기에 '+ + return' 3단계 입력까지 총 4단계 입력을 받는다.
nextInt()는 return 전까지 입력된 Int값을 반환하기 때문에 '2 + 0'만 반환하고, return System.in에 그냥 남아있는다.

하지만 다음에는 nextLine()이 호출되고 "Hello"를 입력하면
Scanner(System.in)은 시스템으로부터 'return + H + e + l + l + o + return' 으로 앞에 남은 'return찌꺼기에 'H + e + l + l + o + return' 6단계 입력까지 총 7단계의 입력을 받는다.
nextLine()은 return을 포함해 입력된 String값을 반환하기 때문에 'return'만 반환하고, '+ e + l + l + o + return'은 System.in에 그냥 남아있는다.

 

즉, 내 명령이 씹힌게 아니라 System.in의 잔류 찌꺼기와 문제로 인해 발생한다.

 

따라서, nextInt()다음의 nextLine() 뿐 아니라
next() 다음의 next() 또는
next() 다음의 nextLine() 역시 마찬가지의 문제를 겪게된다.

1 ) next() 다음의 next() 의 경우

import java.util.Scanner;

public class ScannerTest {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.println("알파 입력.");
		String Alpha = s.next();
		System.out.println("베타 입력.");
		String Beta = s.next();
		
		
		System.out.println("\n\n\n입력된 알파와 베타는 다음과 같다.");
		
		System.out.println("알파 : " + Alpha);
		System.out.println("베타 : " + Beta);
	}

}

결과 : 

알파 입력.
학교 종이 땡땡땡
베타 입력.



입력된 알파와 베타는 다음과 같다. 
알파 : 학교
베타 : 종이		// 찌꺼기 ' 종이 땡땡땡 + return' 중 '종이'만 문자열로 Beta에 들어간다.

2 ) next() 다음의 nextLine() 의 경우

import java.util.Scanner;

public class ScannerTest {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.println("알파 입력.");
		String Alpha = s.next();
		System.out.println("베타 입력.");
		String Beta = s.nextLine();
		
		
		System.out.println("\n\n\n입력된 알파와 베타는 다음과 같다.");
		
		System.out.println("알파 : " + Alpha);
		System.out.println("베타 : " + Beta);
	}

}

결과 : 

알파 입력.
학교 종이 땡땡땡
베타 입력.



입력된 알파와 베타는 다음과 같다. 
알파 : 학교
베타 :  종이 땡땡땡	// 찌꺼기 ' 종이 땡땡땡 + return'이 앞에 공백(스페이스바)부터 종이 땡땡땡과 return을 모두 포함해 모두 문자열로 Beta에 들어간다.

 

 

그래서 해결법은요??

방법 1 ) s.nextInt()나 s.next() 다음에는 s.nextLine()을 넣어 찌꺼기를 소거하기.

Scanner s = new Scanner(System.in);

System.out.println("원하는 기능을 선택하세요. 1) 입금, 2) 출금, 3) 종료");
int selectMenu = s.nextInt();
s.nextLine();		// 찌꺼기 return 소거용.

System.out.println("짧은 메모를 남겨주세요.");
String shortMemo = s.nextLine();

 

방법 2 ) s.nextInt()와 s.nextLine() 스캐너를 각각 만들어주기. (s.next() s.next() 또는 s.next() s.nextLine()은 방법 2로는 해결 불가능.)

Scanner sInt = new Scanner(System.in);
Scanner sLine = new Scanner(System.in);

System.out.println("원하는 기능을 선택하세요. 1) 입금, 2) 출금, 3) 종료");
int selectMenu = sInt.nextInt();

System.out.println("짧은 메모를 남겨주세요.");
String shortMemo = sLine.nextLine();

 

방법 3 ) 그냥 전부 s.nextLine()으로 받아서 문자열 형태의 숫자만 들어온 경우(e.g. "2020") Integer.parseInt()로 형변환하기. (s.next() s.next() 또는 s.next() s.nextLine()은 방법 3에는 해당하지 않음.)

Scanner s = new Scanner(System.in);

System.out.println("원하는 기능을 선택하세요. 1) 입금, 2) 출금, 3) 종료");
String selectMenu = s.nextLine();
int selectMenuInt = Integer.parseInt(selectMenu);

System.out.println("짧은 메모를 남겨주세요.");
String shortMemo = s.nextLine();

 

s.next()의 찌꺼기는 방법 1로만 해결 가능하다.
s.nextInt()의 찌꺼기는 입력이 적을 때는 방법 1이 괜찮고, 입력이 많을 때는 방법 2가 괜찮고, 숫자가 문자열 형태로 들어올 위험이 있을 때는 방법 3이 괜찮을 것 같다.

 

 

nextInt() 문자 입력시 예외처리

저는 현재 nextInt()의 'return'소거용으로 매번 다음 라인에 nextLin()을 넣어주고 있습니다.

nextInt()에 문자가 들어올 경우 try ~ catch로 오류에 대한 예외처리를 하고 넘어가는게 가능합니다.

하지만 문제점이!! 반드시 true값이 나와야 하도록 선택해야 하는 구문이라 try~catch에 반복문을 씌울 경우 무한루프에 빠지게 됩니다...

이유는 System.in에 들어갔으나 nextInt()에 들어갈 수 없어 남아있던 찌꺼기로 인한 것인데요, try ~ catch로 예외처리 될 경우 nextInt()바로 아래 소거용으로 넣어둔 nextLine()를 타지 않고 바로 try ~ catch 밖으로 나오기 때문입니다. 따라서 그 밖에 다시 한 번 nextInt()를 넣어 찌꺼기를 소거시켜줘야합니다.

해당 문제 외에도 break; 위치를 정확히 잡아줘야하는 것에 대한 내용도 있기 때문에 자세한 것은 아래 링크 내의 코드 블럭을 참조하세요.

링크 : 해당 글의 2.2 Player의 Sub클래스들에 있는 소서러스, 바바리안의 스킬 메소드 구현 부분의 try ~ catch 구문 참조.

 

따라서 가급적 계산이 아닌 선택의 문제일 경우 처음부터 nextLine()으로 받아서 .equals("1") 를 이용하는 방법을 사용하는게 좋음!

만약 계산이 필요한 경우 역시 처음부터 nextLine()으로 받아서 Integer.parseInt() 로 형변환하는 방법을 사용하는게 좋음!

+ Recent posts