문제에 입력이 끝나는 지점/조건이 없기 때문에 파일의 끝에서 입력받을 데이터가 없으면 종료시키는 EOF 처리가 필요
🔎 EOF (End of File)
입력에서 더 이상 읽을 수 있는 데이터가 없는 경우, 파일의 끝(EOF)이라고 한다. 입력을 하지 않았다는 뜻과 같으므로 null을 뜻한다.
🔎 더 이상 입력할 값이 없을 경우 프로그램을 종료하는 방법
→ 윈도우 ( ctrl + z ) 입력
→ 맥, 리눅스 ( ctrl + d ) 입력
🔎 입력의 종류에 따른 EOF 처리 방법
1. Scanner
Scanner의 경우 더 이상 읽을 데이터가 없으면 NoSuchElementException을 던지게 된다. 던져진 예외의 경우 hasNext() 메서드를 사용해서 처리해주면 된다. EOF일 경우 False, 입력 값이 있을 경우 True를 반환한다.Scanner sc = new Scanner(System.in); while(sc.hasNext()){ ... }
2. BufferedReader
BufferedReader의 경우 더 이상 읽을 데이터가 없으면 null을 반환한다.
br.readLine() != null 을 사용해서 처리해주면 된다.
EOF일 경우 False, 입력 값이 있을 경우 True를 반환한다.BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while( (변수=br.readLine()) != null){ ... }
import java.util.Scanner;
public class Main {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
while(sc.hasNextInt()){
int A = sc.nextInt();
int B = sc.nextInt();
System.out.println(A+B);
}
sc.close();
}
}
- hasNext() → 다음에 가져올 값이 있으면 True, 없으면 False 반환
- hasNextInt() → 입력값이 정수일 경우 True, 입력값이 없거나 정수 외의 값이 들어올 경우 False 반환
🔎 br.readLine()을 통해 한줄씩 입력값을 계속 받고, 변수 str에 저장된 데이터가 null일 경우(=입력값이 없을 경우), while 반복문을 종료하는 방식
① StringTokenizer() 이용 (공백을 기준으로 문자열 분리)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class Main {
public static void main(String args[]) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
String str;
while( (str=br.readLine()) != null){
StringTokenizer st = new StringTokenizer(str, " ");
int A = Integer.parseInt(st.nextToken());
int B = Integer.parseInt(st.nextToken());
sb.append(A+B).append("\n");
}
System.out.print(sb);
}
}
🔎 해당 코드에서 런타임 에러(NullPointer)가 발생하는 이유
- NullPointer : null 값을 가진 객체를 참조하려고 할 때 발생하는 오류
사용할 객체의 인스턴스를 생성(초기화)하지 않은 상태에서 참조할 경우 발생 (존재하지 않는 주소를 가리키려하므로)BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while(br.readLine() != null){ StringTokenizer st = new StringTokenizer(br.readLine(), " "); ... }
- while 루프 내에서 br.readLine()을 두 번 호출
첫 번째 호출은 루프의 조건에서 사용되고, 두 번째 호출은 실제로 입력을 읽음
이때 첫 번째 호출로 읽은 값이 null이 아닐 때 두 번째 호출에서는 새로운 입력을 받아들이게 되는데, 사용자가 아무런 입력을 하지 않았을 때 두 번째 호출에서 null을 반환하므로 NullPointerException이 발생하게 됨
🔎 해당 코드에서 메모리 초과가 발생하는 이유
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str = br.readLine(); while(str != null){ StringTokenizer st = new StringTokenizer(str, " ");
- 반복문 안에서 br.readLine()을 한 번만 호출하여 한 번의 입력을 처리하고 있음 → 입력이 끝나지 않고 계속해서 입력을 받으려고 시도하므로 메모리를 초과하게 됨
② String.charAt() 이용
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String args[]) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
String str;
while( (str=br.readLine()) != null ){
int A = str.charAt(0) - 48;
int B = str.charAt(2) - 48;
sb.append(A+B).append("\n");
}
System.out.print(sb);
}
}
🔎 반복문의 조건문에 입력값의 배열인 input의 인덱스 끝까지를 조건으로 명시
const input = require('fs').readFileSync('/dev/stdin').toString().trim().split("\n");
let i = 0;
while(i < input.length){
let [A, B] = input[i].split(" ").map(Number);
console.log(A + B);
i++;
}
const input = require('fs').readFileSync('/dev/stdin').toString().trim().split("\n");
for(let i=0; i<input.length; i++){
let [A, B] = input[i].split(" ").map(Number);
console.log(A + B);
}
while True:
try:
A, B = map(int, input().split())
print(A + B)
except: #try에 대한 에러가 발생한 경우
break # while문을 종료
🔎 while문을 활용하면 정수 이외의 다른 입력값이 들어올 시 error가 발생하여 except문의 break가 활성화되며 반복문이 종료됨
import sys
for i in sys.stdin :
A, B = map(int, i.split())
print(A + B)
🔎 sys.stdin은 (ctrl + z) 또는 (ctrl + d) 값이 입력되기 전까지 개행 문자와 함께 계속하여 입력값을 받음