All of My Records

[Java] 콘솔 입력, Input과 에러의 종류 :: System.in.read(), BufferedReader, Scanner

by 캐떠린

이전 포스트에서 콘솔 입출력중 출력에 대해 알아봤었다.

 

[Java] 콘솔 출력, Output

콘솔 출력을 알아보기에 앞서 먼저 콘솔 입출력에 대해 알아보자. 콘솔 입출력, Console Input Output 기본 입력 장치: 키보드 기본 출력 장치: 모니터 콘솔 출력을 위해서 자바에서는 아래 3가지 메서

pigsnowworld.tistory.com

 

오늘은 입력에 대해 알아보자!

콘솔 입력은 키보드로 이루어진다.

자바에서 키보드로 입력 받기 위한 3가지 방법이 있다.

  1. System.in.read() → 불편하다.
  2. BufferedReader 클래스
  3. Scanner 클래스

1번을 쓰기 편하게 하기 위해 만들어진게 2,3번 방법이다.

 

1. System.in.read()

아래의 요구사항 예시를 풀어보며 1번 System.in.read()를 사용하는 입력에 대해 알아보자.

 

요구사항: 사용자에게 문자 1개를 입력 받아 화면에 출력하시오.

 

위 요구사항을 만족하기 위해서 우리는

1. 안내 메세지 출력: 사용자에게 문자 1개를 입력하라는 안내 메세지를 출력해야 한다.
2. 키 입력: 사용자로부터 키를 입력 받아야 한다.
3. 키를 화면에 출력: 사용자로부터 입력 받은 키를 화면에 출력해야 한다.

 

1번부터 해보자. → 1. 안내 메세지 출력

System.out.println("문자 입력: ");

 

2. 키 입력

입력 대기 상태 → 블럭이 걸렸다. → 사용자의 키 입력을 기다리고 있는 중인 상태

콘솔에서 사용자가 키를 입력하면 엔터를 입력한다.

 

read() 메서드 1회 사용은 문자 1개를 입력한다는 말과 같다.

int code = System.in.read(); //이와 같이 입력 버퍼가 비어져있으면 입력 대기상태이다.

System.in.read() 명령어는 자기 할일을 다하고 사용자 입력어를 남기고 사라진다.

주의해야 할 점은 int code에 문자를 저장한다는 것은 문자 코드를 저장한다는 것이다.

 

※ 주의 ※

System.in.read()를 사용할 경우 메인 메서드에 예외 처리를 해줘야 하므로 아래와 같이 입력한다.

public static void main(String[] args) throws Exception {

}

throws Exception 처리를 해줘야 System.in.read()로 인한 에러가 사라진다. 자세한 이유는 추후 예외 관련 정리 포스트에서 후술할 예정!

 

3. 키를 화면에 출력

System.out.println("출력: " + code);

단, 위와 같이 출력하면 오류가 있다.  위에서 code 변수에는 문자 코드값이 저장되어있다고했다.

문자 코드값을 그대로 출력하면 안되고, 문자코드를 character로 변환하여 출력해야 하므로 아래의 과정을 추가해주자.

//a -> 97 -> 소문자 a의 문자코드 값이 97
//A -> 65 -> 대문자 A의 문자코드 값이 65
System.out.printf("출력: %c\n", code); //%c를 활용하여 문자코드를 character로 변환하여 출력
System.out.println("프로그램 종료");

 

위의 과정을 통해 아래와 같이 정리할 수 있다.

System.in.read(); 명령어는

  • 사용자로부터 입력한 키보드 값을 가져오는 역할을 한다.
  • 여기서 read 메서드가 하는 일은 키보드에 입력된 내용을 프로그램에서 바로 가져오는게 아니라, 입력 버퍼에 있는것을 읽어오는 개념이다. 한번 읽은 글자는 이미 소비가 끝나서 버퍼에서 삭제가 된다.
  • 또한 read는 1바이트 단위씩 읽기를 한다. Java에서는 한 글자를 표현하는데 2바이트를 사용한다. 16진수 중 영어/특수문자는 앞의 ‘0000 0000’은 고정, 뒤의 8자리만 바뀌는데 반해 한글은 앞의 8자리까지 다 사용한다. 그러나 read는 1byte(8bit)만 읽기 때문에 read 메서드로 한글을 받으면 다 깨진다.

 

참고
- \r: Carriage Return의 문자 코드 = 13
- \n: New Line의 문자 코드 = 10

 

2. BufferedReader 클래스

import 단축키: (Eclipse 기준) Ctrl + Shift + O(알파벳 ‘O’)
//자료형(BufferedReader) 변수이름(reader)
BufferedReader reader = new BufferedReader(new InputStremReader(System.in));

클래스는 자료형 중 하나이다. 대부분의 클래스는 바로 사용할 수 없고, ‘이 클래스를 제가 사용하겠습니다.’ 라고 선언해줘야한다. → 이게 바로 package 밑에 적는 import 구문의 역할이다. (import할 때는 어느 패키지 안에 들어있는지까지 같이 써줘야 한다.)

 

BufferedReader 또한 System.in.read()와 마찬가지로 예외 처리를 해줘야 하므로 아래와 같이 입력한다.

public static void main(String[] args) throws Exception {

}

 

BufferedReader를 사용하여 사용자로부터 입력을 받고 출력해보자.

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

System.out.println("문자 입력: ");
int code = reader.read();
System.out.println(code);
System.out.printf("%c\n", code);

 

위에서 볼 수 있듯이 BufferedReader 클래스의 reader라는 객체를 생성하여 read()메서드를 통해 사용자로부터 값을 입력받았다. (클래스와 객체에 대해선 자세하게 이후의 포스트에서 후술할 예정!)

 

BufferedReader 클래스도 위에서 언급한 System.in.read()와 마찬가지로 사용자로부터 입력된 데이터를 바로 전달하는 것이 아닌, 버퍼에 저장해두었다가 전달하는 방법이다.

 

여기서 read() 메서드는 글자를 입력 받고 입력 버퍼에서 글자 하나를 읽어와 문자 코드 값을 반환하는데, 위에서 System.in.read()를 사용할 때와 마찬가지로 형식 문자를 통해 character형태로 변환해서 출력해주면 입력한 문자 ‘a’를 확인할 수 있다.

 

단, BufferedReader의 read()메서드와 System.in.read()의 가장 큰 차이점은 BufferedReader에서는 한글 입력이 가능하다는 것이다.

 

아래 예시와 같이 문자 여러개를 입력하더라도 버퍼에서 글자 하나를 읽어오기 때문에 ‘ㄱ'을 버퍼에서 읽고 삭제한다. 

 

BufferedReader 클래스에는 read()메서드 뿐만 아니라 readLine()이라는 메서드도 존재한다. 아래의 예시를 봐보자.

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

System.out.println("문자 입력: ");
int code = reader.read();
System.out.println(code);
System.out.printf("%c\n", code);

String line = reader.readLine();
System.out.println(line);

int code = 97, 문자로 변환하면 입력한 a 가 그대로 출력되었고 String line = “sdlfksjdfjskdf” 값이 출력되었다.

 

System.out.println("문자 입력: ");

출력 코드를 통해 콘솔창에는 문자 입력: 이라는 문구가 출력되었다.

그리고 그 다음줄인 아래 코드를 통해 입력 대기상태가 되어 우리는 asdlfksjdfjskdf 를 입력했다.

int code = reader.read();

이로써 위에서 입력한 asdlfksjdfjskdf 문자는 버퍼에 저장되었고 reader.read()는 버퍼에서 첫글자인 ‘a’를 가져와서 변수 code에 대입 후 버퍼에서 사라졌다.
따라서 버퍼에는 a가 제외된 sdlfksjdfjskdf만 남은 상태이다.
reader.readLine()은 한 줄(개행 기준)을 읽는다. 여러줄을 한 번에 읽지 않는다! 따라서 우리가 처음 문자 입력 후 엔터를 입력하여 개행 하기 전인 sdlfksjdfjskdf를 출력한다.
또한 readLine()은 입력 버퍼에서 처음부터 엔터(\r\n)를 만나기 전까지 모두 읽어온 후, 엔터는 자동으로 삭제한다.
read()와 readLine()의 차이점은 read()는 int를 반환하고, readLine()은 String을 반환한다는 점이다.
따라서 readLine()의 반환값으로 숫자 연산 등을 하기 위해서는 Integer.parseInt() 또는 Double.parseDouble()을 사용하여 아래와 같이 자료형 변환이 필요하다.

System.out.println("숫자 입력: ");
String num = reader.readLine();

int num2 = Integer.parseInt(num); //"100" > int 100으로 형변환하여 값을 반환한다.
double num3 = Double.parseDouble(num); //"100" > double 100으로 형변환하여 값을 반환한다.

 

아래의 요구사항을 풀어보자.

요구사항: 숫자 2개를 입력하여 더하기 연산을 한 후, 연산 과정과 결과를 모두 출력하라.

  • 숫자1: 5
  • 숫자2: 3
  • 결과 출력: 5 + 3 = 8
System.out.print("첫번째 숫자: ");
int input1 = Integer.parseInt(reader.readLine());

System.out.print("두번째 숫자: ");
int input2 = Integer.parseInt(reader.readLine());

System.out.printf("%d + %d = %d\n", input1, input2, input1 + input2);

 

※주의※

피제수(나눠진 수) / 제수(나뉜수)

나누기 연산 시, 제수는 0이 될 수 없다. 제수가 0이 될 경우 아래와 같이 산술 연산 에러가 발생한다.

java.lang.ArithmeticException: / by zero

System.out.print("숫자: ");
String input = reader.readLine();

int num = Integer.parseInt(input);
System.out.println(100 / num);

 

3. Scanner 클래스

Scanner scan = new Scanner(System.in);
  • java.util 패키지에 존재하는 Scanner 클래스
  • 다양한 생성자가 있으나, 주로 사용하는 생성자는 Scanner(InputStream source) 입력스트림을 읽어오는 생성자이다.
  • 입력받은 숫자, 문자를 변수에 담을 때는 아래와 같이 사용한다.
String str = scan.nextLine();
int num1 = scan.nextInt();
double num2 = scan.nextDouble();

 

※주의 사항※ nextInt() 사용 후, nextLine() 사용 시 유의 사항
nextInt() 메서드는 사용자의 입력값의 마지막 개행 문자를 제거하지 않는다. 개행 문자 전 까지의 정수형 데이터를 입력 받고, 개행 문자는 다음 nextLine()메서드의 입력 값으로 처리가 되기 때문에 nextInt() 사용 후 개행 문자를 지우는 작업을 하거나, scan.nextLine() 을 사용하여 개행 문자를 처리 후, scan.nextLine()을 사용 시, 원하는 값을 입력 값으로 처리할 수 있다.

 

참고

Wrapper Class(Utility Class)

원시형 데이터를 도와주는 기능을 제공하는 클래스

  • byte → Byte 클래스
  • short → Short 클래스
  • int → Integer 클래스
  • long → Long 클래스
  • float → Float 클래스
  • double → Double 클래스
  • boolean → Boolean 클래스
  • char → Character 클래스

 

에러, 오류(Error)

에러에는 크게 아래와 같이 3가지 종류가 있다.

  1. 컴파일 에러
    • 컴파일 작업 중에 발생하는 에러
    • 컴파일러가 컴파일 에러를 발견하면 컴파일 작업이 중단되며 프로그램 생성이 불가하다. 따라서 반드시 해결해줘야 한다.
    • 이클립스에서는 빨간색 밑줄로 표기된다.
    • 에러중에서도 가장 난이도가 낮은 에러이다. 발견이 쉽기 때문에 고치기도 쉽다.
    • 오타가 있을 경우 자주 발생하는 에러이다.
  2. 런타임 에러
    • 런타임(Runtime) → 프로그램 실행 중 발생하는 에러
    • 컴파일 작업 중에는 에러가 없으나, 실행 중에 발생하는 에러이다.
    • 문법에는 오류가 없는데 다른 원인으로 발생하는 에러
    • 예외(Exception)
    • 중간 난이도의 에러이다. → 발견이 될 수도 발견이 안 될 수도 있기 때문이다. ⇒ 따라서 잠재적인 에러이다.
    • 충분히 사전에 테스트를 통해 찾을 수 있다. (시간, 비용을 투자하여 많은 사람들이 다양한 작업을 하면서 테스트를 진행한다.)
    • 게임을 출시할 때 클로즈드 알파, 클로즈드 베타, 오픈 알파, 오픈 베타 테스트가 런타임 에러를 잡기 위한 사전 테스트에 해당한다.
  3. 논리 에러
    • 컴파일도 성공하고, 실행도 성공했으나 결과가 이상하게 나오는 에러이다. → 최종 결과가 원하는 결과가 아닌 경우
    • 에러 중 가장 최상의 난이도이다. 발견하기도 어렵고 수정하기도 어렵다.

 

*글 작성에 참고한 내용: 학원 쌤의 열정적인 수업

블로그의 정보

All of My Records

캐떠린

활동하기