티스토리 뷰

APS/이론

[APS] 입출력 : Scanner / StringBuilder

개발자 김챠챠 2024. 12. 28. 16:17

 

지난번에 알아봤던 System의 표준 입력 메서드인 System.in.read()는 여러모로 사용하기 불편했다. 따라서 Java에서는 쉽게 입력 받을 수 있는 방법인 Scanner를 추가적으로 제공한다.

이 외에도, 대량의 문자열을 모아서 빠르게 출력하기 위한 표준 방법인 StringBuilder도 함께 소개한다.


입력 : Scanner

Scanner Java5부터 제공된 표준 입력 클래스로, Java.util 패키지에 존재한다. Scanner는 내부적으로 정규표현식(regex)를 사용하여 읽은 문자를 토큰화시키고, 메서드에 따라 타입을 변환하여 입력받을 수 있다.

nextInt() 입력된 값 중 정수 토큰을 반환한다.
nextDouble() 입력된 값 중 실수 토큰을 반환한다.
next() 입력된 값 중 띄어쓰기(space) 으로 구분된 1개의 토큰을 반환한다.
nextLine() 입력된 값 중 개행(enter)으로 구분된 전체 줄을 반환한다.

 

참고로 nextXX() 메서드엔 char을 제외한 모든 기본타입이 다 올 수 있다.  nextFloat(), nextLong()도 당연히 가능하다. 아무튼 Scanner는 이렇게 간편하면서도 강력한 메서드를 제공하여 초보자라도 굉장히 쉽게 입력 시스템을 구현할 수 있도록 한다. 

import java.util.Scanner; // 스캐너 임포트

public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in); // Scanner 선언
        System.out.println("정수를 입력해주세요.");
        int A = sc.nextInt();
        System.out.println("실수를 입력해주세요.");
        double B = sc.nextDouble();
        System.out.println("문자열을 입력해주세요.");
        String C = sc.next();

        System.out.println("정수:"+A+", 실수:"+B+", 문자열:"+C);
    }
}

 

결과

 

이전에 설명했던 System은 java.lang 패키지에 있기 때문에 import없이도 자동으로 사용 가능하지만, Scanner는 반드시 util 패키지를 import하는 것을 잊지 말자. 다만 Scanner는 선언만 하면 위처럼 사용하기도 간편하고, 다른 입력방법과는 달리 예외(IOException)처리를 안해줘도 되어서 타이핑할 거리가 줄어드는 것이 장점이다.

 

참고로 타입을 정해서 받을 때, 구분자를 제외한 전혀 다른 타입의 입력값이 있을 경우 예외(InputMismatchException) 를 발생시킬 수 있으니 주의하자. 아래 예시는 nextInt() 를 통해 정수를 입력받아야 하는 곳에 실수값을 입력한 경우다. 

 

 

Scanner는 뛰어난 편의성을 제공한다 - 예를 들어, APS에서 자주 나오는 입력값인 '띄어쓰기 혹은 엔터 구분된 숫자'의 경우, 하나씩 nextInt()로 가져와서 쓰면 된다. nextLine()을 제외한 모든 nextXX() 메서드들은, 입력받아야 하는 값 주위의 구분자들은 싸그리 무시한 채, 알짜값(토큰)만 가져온다.

※ 스트림 내부엔 남아있으며 다음 메서드로 새로운 토큰을 입력받을 때 적절히 처리해서 없애버린다.

 

다만 문제는 nextLine()이다. 이 메서드는 개행을 포함하여 스트림에 남아있는 모든 입력값을 가져온다. 이 때문에 아래의 예시처럼 예기치 못한 입력값이 발생할 수 있다.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in); // Scanner 선언
        System.out.println("정수를 입력해주세요.");
        int A = sc.nextInt();
        System.out.println("실수를 입력해주세요.");
        double B = sc.nextDouble();
        System.out.println("문자열을 입력해주세요.");
        String C = sc.nextLine();

        System.out.println("정수:"+A+", 실수:"+B+", 문자열:"+C);
    }
}

 

결과

 

위 예시는 맨 위의 예시의 next()메서드를 nextLine() 메서드로 변경한 것이다. 아까와는 달리 nextDouble()을 처리한 후에도 여전히 스트림 내엔 개행문자가 남아있기 때문에, nextLine()을 하면 별다른 추가 입력 필요없이 개행 문자를 가져오는 것이다. System.in.read()에서도 비슷한 문제 때문에 개행 처리용으로 한번 더불렀던 것처럼, nextLine()을 다른 메서드와 혼용할 땐 개행처리용 nextLine()을 한번 더 호출해줘야 한다.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in); // Scanner 선언
        System.out.println("정수를 입력해주세요.");
        int A = sc.nextInt();
        System.out.println("실수를 입력해주세요.");
        double B = sc.nextDouble();
        sc.nextLine(); // 개행문자 처리용
        System.out.println("문자열을 입력해주세요.");
        String C = sc.nextLine();

        System.out.println("정수:"+A+", 실수:"+B+", 문자열:"+C);
    }
}

 

결과

 

 

정리하자면, Scanner는 nextLine()을 혼용할 때와 같이 사소한 예외처리만 주의 한다면, 강력한 타입검사와 편리한 사용법 때문에 많은 코딩테스트나 APS 플랫폼( SWEA  등)에서 표준 입력장치로 많이 쓰이고 있으며, 실제로도 대부분의 문제들은 Scanner을 사용하여도 제한시간 내에 풀리게끔 설계되어 있다. 

 

다만, Scanner는 정규표현식을 사용하여 입력값을 토큰화시키고 타입을 변환시키는 과정에서 큰 오버헤드가 발생하기 때문에, 다른 입력 방법보다 시간이 확연하게 느려진다는 단점이 있다. 따라서 "빠른 입출력"이 요구되는 몇가지 문제들에 한해서는 이후에 설명할 BufferedReader 를 사용하거나, 본인만의 fastI/O 메서드를 구현해서 사용해야 한다. 


출력 : StringBuilder

이전에도 설명했 듯, 출력은 System.out.print 시리즈만으로 웬만하면 다 해결된다. 굳이 따지자면 PrintWriter 같은 것도 있지만 APS에서는 어차피 콘솔창에 전송된 값만 검사하기 때문에 번거롭게 PrintWriter를 선언할 필요까지는 없다.

 

만약 출력을 여러번 해야하는 경우에는 어떨까? 예를 들어 100000번에 걸쳐 "안녕하세요"를 출력하는 문제가 있다고 가정해보자. 반복문을 돌려 100000번 System.out.print를 하게할 수 있지만, 매번 출력스트림에 간섭해야 하므로 I/O에 드는 오버헤드가 커질 수 있으며, 실제로 문제를 풀 때 이런 이유 때문에 시간초과가 나는 경우도 많다.

 

이를 해결하는 방법은 출력할만큼의 문자열을 미리 합쳐서 하나의 문자열을 만든 뒤 한번에 출력하는 것이다. Java는 String을 매번 선언해서 + 연산자 등으로 더해버리면 메모리가 터져버릴 수 있으니 이러한 작업에 최적화된 StringBuilder 클래스를 사용하는게 일반적이다.

※ String이 불변객체이기 때문이다. 자세한 설명은 추후에 작성될 글(String)을 참고하자.

public class Main {
    public static void main(String[] args) {

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < 100000; i++) {
            sb.append("안녕하세요\n");
        }

        System.out.println(sb);
    }
}

 

StringBuilder는 append() 메서드를 사용해서 문자열을 합칠 수 있으며, 메서드 체이닝이 가능하기 때문에 다양한 문자열을 만들 수 있다. 만약 출력이 너무 잦은 것 같다면 반드시 StringBuilder를 사용해보도록 하자.

※위의 예시에선 10만개의 문장을 합쳐서 1번 println하기 vs  10만번 println하기를 측정했을 때 약 3배정도의 속도 차이가 났다.


 

'APS > 이론' 카테고리의 다른 글

[APS] 02 : 자료구조 - 배열  (0) 2025.03.19
[APS] 01 : 자료구조 개론  (0) 2025.03.19
투포인터 - 1  (0) 2025.02.17
[APS] 입출력 : Buffered 시리즈  (6) 2024.12.29
[APS] 입출력 : System 입출력 메서드  (9) 2024.12.28
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함