SHUSTORY

[ 백준 ] 10951번 : A + B - 4 _ JAVA 본문

코딩테스트/JAVA

[ 백준 ] 10951번 : A + B - 4 _ JAVA

어서오시우 2023. 12. 1. 14:44
728x90
문제

  • 띠용? 이 문제를 보고 굉장히 당혹스러웠다. 조건이 따로 없어?

입력이 끝날 때까지 A+B를 출력하는 문제. EOF에 대해 알아 보세요.

  • 라는데.. EOF가 먼데요? 그래서 오늘은 EOF에 대해 알아보겠습니다!

 

내 풀이
import java.io.*;

public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

while(true) {
String st = br.readLine();
String[] tokens = st.split(" ");
int sum = Integer.parseInt(tokens[0]) + Integer.parseInt(tokens[1]);
bw.write(sum+"\n");
}
}
}
  • 런타임 에러

 

EOF
  • End Of File
  • 위 문제에서, 파일 종료 조건이 주어지지 않았다.
    즉 입력에서 더 이상 읽을 수 있는 데이터가 존재하지 않을 때 (null) 반복문을 종료한다.
  • 문제에 입력이 끝나는 지점에 조건이 없다.
    파일의 끝에서 입력받을 데이터가 없으면 알아서 종료 시키는 것을 EOF 처리라고 한다.

 

문제풀이 방법
  • 처리하는 방법 
    • BufferedReader
      • StringTokenizer 클래스 사용
        • split( ) 보다 성능면에서 더욱 우월
      • split( ) 메서드 사용
    • Scanner
      • Scanner의 메서드들은 더이상 읽을 데이터가 없으면 NoSuchElementException 을 예외가 발생한다.
        해당 메서드는 두 가지 처리 방법이 있다.
        • try-catch문으로 예외 발생시 반복문을 종료해주도록 처리한다.
        • Scanner의 메서드인 hasNext( )를 통해 처리한다. 

[ BufferedReader ]

  • StringTokenizer 클래스 이용해 분리 / split( ) 메서드 이용
    • readLine( ) 메서드를 이용하여 읽어온 값이 null인지 여부를 판단하여 while문 작성
      • BufferedReader로 빈 값을 읽어들어오면 null로 받기 때문에 어떻게 보면 가장 단순하다고 볼 수 있음
    • charAt( ) 메서드 사용 ( + StringBuilder )
      • charAt( ) 메서드는 String으로 저장된 문자열 중 한 문자만 선택해 해당 문자의 아스키코드 값을 반환하기 때문에 숫자로 받기 위해 -48 또는 -'0'을 해주어야 한다.
  • BufferedReader - readLine( ) 사용 코드
import java.io.*;
import java.util.StringTokenizer;

public class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
while(br.readLine()!=null){
StringTokenizer st = new StringTokenizer(br.readLine()," ");
int sum = Integer.parseInt(st.nextToken()) + Integer.parseInt(st.nextToken());
bw.write(sum+ "\n");
}
bw.flush();
bw.close();
br.close();
}
}
  • 그런데 위와 같이 코드를 작성하면 런타임 에러가 발생하고, 아래와 같이 코드를 작성하면 그렇지 않다.
    그 이유는 무엇일까?
    • 두 번의 readLine( ) 호출은 다음 입력 라인으로 이동하게 만든다.
      첫 번째 호출에서 라인을 읽고, 두 번째 호출에서 다음 라인을 읽는다.
      이로 인해 입력의 홀수 번째 라인이 누락되고, 입력과 출력 간의 불일치가 발생할 수 있다.
    • 아래의 코드는 readLine( ) 을 한 번 호출하고 그 결과를 변수 str에 저장한다.
      이렇게 하면 한 번의 루프 반복에서 동일한 입력 라인을 사용하므로 불일치 문제가 발생하지 않는다.

 

import java.io.*;
import java.util.StringTokenizer;

public class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String str;
while((str = br.readLine()) != null){
StringTokenizer st = new StringTokenizer(str," ");
int sum = Integer.parseInt(st.nextToken()) + Integer.parseInt(st.nextToken());
bw.write(sum+ "\n");
}
bw.flush();
bw.close();
br.close();
}
}

 

  • charAt( ) / StringBuilder 사용 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

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.println(sb);
}
}

 

[ Scanner ]

  • hasNext( )를 사용한 EOF 처리 ( hasNextInt( )를 사용해도 된다 )
    • while문의 조건에 EOF 처리를 위해 Scanner의 메서드 hasNext( )로 처리한다.
    • hasNext( ) 메서드는 Boolean 값을 통해 다음 줄이 없으면 false를 반환하고 EOF의 끝을 알려 준다.
    • hasNext( ) 메서드는 예외를 던지지 않고, 입력이 없으면 false를 반환한다.
      따라서 hasNext( ) 로만은 입력이 없다는 것을 감지하고 예외를 발생시키기 어렵기에,
      Scanner에서의 입력의 끝을 나타내는 EOF를 감지할 수 있는 방법은 다음과 같다.
      다음을 통해 EOF가 입력되면 hasNext( )는 false를 반환하고, 반복문을 종료시킬 수 있다.
      • Windows : Ctrl + Z
      • Unix / Linux : Ctrl + D
    • 정리하자면, Scanner 의 메서드들은 더 이상 읽을 데이터가 없으면 NoSuchElementException 예외가 발생한다.
      하지만 space나 공백의 경우 예외를 반환하지 않기 때문에
      while문에서 hasNext( ) 메서드를 사용하여 EOF일 경우 false 반환, 값이 있는 경우 true 반환해 처리한다.

 

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();
}
}
  • 순간 어라? while문의 조건이 sc.hasNext( ) 인데 어떻게 코드가 돌아가는거지? 처음에 값이 없는데 while문 조건식 자체가 성립이 안되어서 코드가 안돌아가는거 아니야? 라고 생각했는데 내가 잘못 받아들인거였다..ㅋㅋ 지금 머리가 안돌아가나? ㅜㅜ
    • 입력값이 들어올 때까지 while문 내부가 실행되지 않다가, 입력값이 들어오면 조건문이 true를 return한 후에 while 문이 실행되는 것이다.

 

 

  • 오늘은 여러가지 정리한 것이 많다! 복습 필수!!