본문 바로가기
Java

[Java] 취소할 수 있는 스캐너 만들어보기

by teamnova 2021. 11. 28.

안녕하세요 자바 콘솔에서 많이 사용하는 기본 스캐너 대신 취소할 수 있는 스캐너를 만들어 보겠습니다.

 

Scanner 클래스는 java 에서 사용자 입력을 받아올 때 사용하는데요.

 

사용자 입력을 받기 위해서 스캐너의 메소드를 실행하면 코드 흐름이 멈추고 대기하는 것을 볼 수 있습니다.

 

이때 입력을 받지않고 취소하려고 할때 마땅한 방법이 없는데요.

 

그래서 취소기능이 있는 간단한 스캐너를 만들어 보도록 하겠습니다.

 

public class CancelableScanner {

    Callable<String> subCallable = new Callable<String>(){
        @Override
        public String call() throws Exception {
            // InputStreamReader 는 데이터 흐름을 읽는데 도움을 줄만한 메소드가 들어있는 리더 클래스다.
            // InputStreamReader 는 byte 단위로 읽는다.
            // 여기서는 터미널로 입력받은 데이터 흐름(System.in)을 읽는다.
            InputStreamReader inputStreamReader = new InputStreamReader(System.in);

            // bufferedReader 는 버퍼 단위로 데이터를 읽어주는 클래스다.
            // 여기서는 한줄 읽기(readLine()) 을 사용하기 위해서 썼다.
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            System.out.println("값을 입력해주세요 : ");
            // 버퍼 리더의 버퍼가 준비가 안되어 있으면(비어 있으면)
            while (!bufferedReader.ready()) {
                // 쓰레드를 0.2초 재운다.
                Thread.sleep(200);
            }

            // 여기로 왔다는건 버퍼 리더의 버퍼가 준비되었다는 뜻.

            // 리더에 들어있는 값을 한줄 읽어 inputString 에 넣는다.
            String inputString = bufferedReader.readLine();

            // futureTask 객체로 inputString 을 전달한다.
            return inputString;
        }
    };

    // 응답이 왔을때 값을 받을 FutureTask 타입 객체
    FutureTask<String> futureTask;

    public String readLine() throws Exception {

         futureTask = new FutureTask<>(subCallable);
        // 서브 스레드 선언
        Thread subThread = new Thread(futureTask);
        subThread.start();

        String inputString = futureTask.get();
        return inputString;
    }

    public void cancel(){
        futureTask.cancel(true);
    }
}

 

callable 객체에 사용자 입력을 받아오는 로직을 작성하였고, futerTask 객체를 사용해서 결과를 받습니다.

 

CancelableScanner 객체 생성 후 readLine() 메소드를 실행하면 새로운 스레드를 생성해서 동작하도록 구현했습니다.

 

마지막으로 cancel 메소드를 사용하면 readLine 메소드에서 실행한 스레드가 sleep에 들어갈 때 interrept 되게 됩니다.

 

사용법 예제는 아래 코드입니다.

 

public class Main {

    public static void main(String[] args){

        // cancelScanner 선언
        CancelableScanner cancelableScanner = new CancelableScanner();

        // 취소 스레드 선언
        Thread cancelThread = new Thread(){
            @Override
            public void run() {
                try {
                    // 10초동안 취소 스레드를 재운다.
                    sleep(10000);
                    // cancelableScanner 의 입력 받기를 취소함
                    cancelableScanner.cancel();
                } catch (Exception e) {
                    System.out.println("cancelThread 스레드 중단(interrupted) : " +  e);
                }
            }
        };

        // 취소 스레드를 실행
        cancelThread.start();

        try {
            // 10번의 입력을 대기
            for(int i=0; i < 10 ; i++ ){
                System.out.println(" 입력한 값 : " + cancelableScanner.readLine());
            }
        }catch (Exception e){
            System.out.println("취소  : " +  e);
        }
        // 메인 쓰레드가 끝날때 cancelThread 도 중단시킴
        cancelThread.interrupt();
    }
}

 

https://stickode.com/detail.html?no=2633 

 

스틱코드

 

stickode.com

즐겨찾기 하신다음 Main 클래스에서 자동완성으로 cancelableScannerUseClass 를 찾아서 엔터 눌러주신 다음에 CancelableScanner 클래스를 만들고 자동완성으로 cancelabelScanner 를 입력해주세요.

 

사용법은 CancelabelScanner 객체를 만드신 다음 객체가 가지고 있는 readLine() 메소드를 사용하시면 됩니다.

 

터미널 입력 취소는 예외를 일으켜서 이루어지기 때문에 readLine() 이 있는 코드 줄을 try/catch 로 감싸주셔야 합니다.

 

취소하실 때는 만드신 CancelabelScanner 객체의 cancel 메소드를 사용하시면 됩니다.

 

추가로 이 클래스를 이해하는데 도움이 되는 코드도 같이 들어있는 포스팅되어 있으니 다른 자동완성 코드들도 Main 클래스에서 실행해 보시는걸 추천드립니다.

 

 

아래는 실행 영상입니다.