[JAVA] 사용자 입력받기

SUN·2023년 1월 15일
0

JAVA

목록 보기
2/2

오랜만에 포스팅이다.
오늘은 자바에 대해서 공부해보고자 한다.
이번에 취업에 성공했는데, 회사에서 자바를 주로 사용하기 때문에..
나는 자바를 많이 사용해보지 않았기 때문에 공부하려고 한다.


자바에서 사용자에게 입력을 받는 방법은 두가지가 있다고 한다.

  1. Scanner
  2. BufferedReader

파이썬에서는 그냥 input()만 하면 되는데.. 대체 왜 나눠져있고 차이는 뭔지 궁금해서 정리해보고자 한다.

BufferedReader VS Scanner

한눈에 보면 이런 차이점을 가지고 있다.

특히 가장 큰 차이점은 속도라고 한다.
BufferedReader가 버퍼를 사용하기 때문에 더 빠르다.
반면에 Scanner는 사용하기가 편리하다.

이제 하나씩 조금 더 자세히 살펴보자.

BufferedReader

BufferedReader에 대해 소개하기 전에 InputStreamReader에 대해서 알면좋다.
InputStreamReader는 문자열을 Character 단위(한 글자 단위)로 읽어 들인다.
그래서 길이가 긴 문자열을 읽을 때는 비효율적이다.
이를 보완하고자 BufferedReader가 존재한다.

즉, BufferedReader는 InputStreamReader에 버퍼링 기능이 추가된 Class이다.

버퍼란?
데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 해당 데이터를 보관하는 임시 메모리 영역이다. 주로 입출력 속도 향상을 위해 버퍼를 사용한다. 자바에서는 버퍼를 BufferedReader와 BufferedWriter라는 클래스를 제공한다.

이렇게 사용자가 요청할 때마다 데이터를 읽어 오는 것이 아니라 일정한 크기의 데이터를 한번에 읽어와서
버퍼에 보관 한 후, 사용자의 요청이 있을 때 버퍼에서 데이터를 읽어오는 방식으로 동작한다.
그렇기 때문에 속도가 빠르다는 장점이 있다.
자세히는 8KB 크기의 버퍼를 가져서 buffer에 입력을 저장했다 한번에 전송한다.

그리고 입력을 라인 단위로 받기 때문에 공백도 스트링으로 인식하며,
입력 받은 데이터 타입이 String타입이기 때문에 다른 타입의 데이터라면 형변환이 필요하다.

그리고 BufferedReader를 사용하기 위해선 예외처리가 필수적이기 때문에
try, catch문을 이용하던가 메인문 중괄호 시작 전 throws IOException 으로 처리해야만 한다.

특징

  • java.io 패키지에 속한다. (import java.io.BufferedReader)
  • 데이터를 파싱하지 않고 String으로만 읽고 가져온다.
  • 버퍼의 사이즈가 8192byte(8KB)이다.
  • Checked Exception으로 반드시 예외 처리를 명시해야한다.(I/O Exception을 throw하거나 try/catch 해야한다.)
  • Thread safe 성질을 지니기에 멀티스레드 환경에서도 안전하다.
  • 버퍼가 가득차거나 개행문자가 나타나면 버퍼의 내용을 한번에 프로그램으로 전달하기에 Scanner보다 소요되는 시간을 절약할 수 있다.

BufferedWriter

참고로 출력할 때도 버퍼를 사용하는 게 있어 함께 소개한다.
한번에 모았다가 출력이 가능하기 때문에 많은 양의 출력을 할 때 유리하다.

버퍼를 정의해줬기 때문에 반드시 flush()/close()를 호출해 뒤처리를 해줘야한다.
System.out.println() 처럼 자동개행 기능이 없기 때문에 개행이 필요한 경우 \n 을 통해 따로 처리해 주어야한다.

메소드

읽어올 때는 대부분 readLine()을 사용한다. 앞서 생성한 객체를 이용해 readLine() 메소드에 접근해 String 변수에 저장하면 된다.

쓸 때는 주로 write()을 이용하는데, 줄바꿈이 포함되어있지 않으므로, 한 줄을 내리고 싶다면 newLine()을 호출해야 한다.

주의할 점

  • BufferedReader의 read()와 readLine()은 리턴타입이 다르기 때문에 구분해서 사용해야 한다. read()는 문자를 읽어 그에 해당하는 ASCII 10진수 정수를 반환하기 때문에, 숫자를 바로 입력받을 수 있다고 생각하면 안된다. 예를 들어 첫 문자가 0-9까지의 숫자라면 그에 상응하는 ASCII 10진수 int값인 48-57이 반환된다.

  • BufferedWriter 객체는 반드시 flush() 또는 close()를 해서 스트림을 끝내야 한다.

  • BufferedReader와 BufferedWriter 클래스의 메소드들은 입출력에러가 발생할 경우 자체적으로 IOException을 던지도록 정의되어있다. 그러므로 이 메소드들을 사용할 때 반드시 예외처리를 해주어야 한다. 메인함수를 작성할 때 throws IOException으로 처리해주면 편리하다.

사용법

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Input {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String input = br.readLine();
    }
}

반복해서 입력받기

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class UserInput {
    public static void main(String[] args) throws IOException {
 
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 
        // 반복해서 입력 데이터 읽기
        String str;
        while ((str = reader.readLine()) != null) {
            System.out.println(str);
        }
    }
}

다량의 데이터 입력받기

split 아니면 StringTokenizer를 사용하면 된다.

split은 입력 받는 동시에 별다른 처리 없이 배열로 데이터를 받아올 수 있다.
StringTokenizer의 경우 토큰화 된 문자열을 다시 처리해주어야 한다.

split은 정규식을 기반으로 문자열을 자르는 로직으로 동작하기 때문에 좀 느리고
StringTokenizer가는 공백 자리를 당겨서 채우기 때문에 더 빠르다.

StringTokenizer의 구분자의 default는 띄어쓰기이다.
다른 구분자를 사용할 경우 아래처럼 명시해주면 된다.

StringTokenizer st = new StringTokenizer(문자열, 구분자); 

split, StringTokenizer 사용예시

import java.io.*; //BufferedReader 사용
import java.util.*; //StringTokenizer 사용

public class BufferEx {
	public static void main(String[] args) throws IOException { // 예외처리 필수
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 선언
		
		String s = br.readLine(); 
		System.out.println("String : " + s);
		
		int i = Integer.parseInt(br.readLine()); // readLine()으로 받은 String 값을 int로 형변환
		System.out.println("Int : " + i);
		
       	 	//여러 개의 데이터 입력받기
        	String s2[] = br.readLine().split(" "); //split을 이용해 다량의 데이터 입력 받기
        
		StringTokenizer st = new StringTokenizer(br.readLine());
		int arr[] = new int[st.countTokens()];
		int count=0;
		while(st.hasMoreTokens()) {
			arr[count] = Integer.parseInt(st.nextToken());
			System.out.println(arr[count++]);
       		//countTokens() : 총 토큰의 개수를 리턴
		//hasMoreTokens() : 토큰이 남아있다면 true, 없으면 false 리턴
		}
	}
}

Scanner


Java1.5 부터 java.util 패키지 내에 포함된 Class이다.
공란과 줄바꿈을 모두 입력값의 경계로 인식하기 때문에 쉽게 데이터를 입력받을 수 있다.
데이터 타입이 입력받는 시점에 결정되기 때문에 별도 캐스팅이 필요하지 않다.
그리고 사용자가 직접 예외 처리를 구현할 필요가 없다.

전체적으로 속도를 포기하고 편리성을 얻었다고 생각하면 되겠다.

특징

  • java.util 패키지에 속한다. (java.util.Scanner)
  • 공백(띄어쓰기) 및 개행(줄 바꿈)을 기준으로 읽는다.(' ', '\t', '\r', '\n' 등)
  • 원하는 타입으로 읽을 수 있다.
  • 버퍼의 사이즈가 1024byte(1KB) 이다.
  • UnChecked(Runtime) Exception으로 별도로 예외 처리를 명시할 필요가 없다.
  • Thread unsafe 성질을 지니기에 멀티스레드 환경에서 문제가 발생할 수 있다.
  • 데이터를 입력받을 경우 즉시 사용자에게 전송되며 입력받을 때마다 전송되어야 하기에 많은 시간이 소요된다.

메소드

사용법

import java.util.Scanner;

public class Input {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        String input = sc.nextLine();
    }
}

System.in이란?
사용자로부터 입력을 받기 위한 입력 스트림이다.
Scanner 클래스뿐 아니라 다른 입력 클래스들도 System.in을 통해 사용자 입력을 받아야 한다.

자료형에 맞춰 입력받기

import java.util.Scanner;
 
public class ScannerInput {
    public static void main(String[] args) {
 
        // scanner 선언
        Scanner scanner = new Scanner(System.in);
 
        // 사용자 입력
        System.out.println("문자열을 입력하세요 : ");
        String str = scanner.nextLine();
 
        System.out.println("정수를 입력하세요 : ");
        int number = scanner.nextInt();
 
        System.out.println("실수를 입력하세요 : ");
        float floatNumber = scanner.nextFloat();
 
        System.out.println("true/false를 입력하세요 : ");
        boolean bool = scanner.nextBoolean();
 
        // 결과 출력
        System.out.println(str);
        System.out.println(number);
        System.out.println(floatNumber);
        System.out.println(bool);
 
        // close scanner
        scanner.close();
    }
}

scanner.close(); 를 하는 이유는
키보드에서는 딱히 상관없지만 파일 입출력을 할 때 파일을 열고나서
닫지 않는다면 파일이 손상될 수 있다고 한다.
그래서 close하는 습관을 들이는 게 좋다고 한다.

반복해서 입력받기

import java.util.Scanner;
 
public class ScannerLoop {
    public static void main(String[] args) {
        
        // Scanner 선언
        Scanner scanner = new Scanner(System.in);
 
        while (scanner.hasNextLine()) {
            String str = scanner.nextLine();
            System.out.println(str);
        }
 
        scanner.close();
    }
}

한마디로 편하고 싶으면 스캐너를,
빠르게 안정적으로 하고 싶으면 버퍼를 사용하면 된다.

참고자료

https://lasbe.tistory.com/48
https://velog.io/@langoustine/Scanner-VS-BufferedReader

profile
개발자

0개의 댓글