首页 > 解决方案 > 终端中的数据循环打印可由用户输入终止

问题描述

我的任务是在终端打印货币汇率表,每分钟打印一次有延迟的表。在用户输入时,我将结束循环并返回海关终端菜单。如何做到这一点?

一般来说,我有一个问题要弄清楚如何获得无缝的用户体验。如果没有用户操作,我需要在终端中进行用户输入,并且仍然每分钟打印一次数据。最终,如果用户决定终止打印,如何完全终止整个数据打印循环?-> 运行标志 = ????;

它实际上是正确的方法吗?

我尝试了几种方法,不幸的是没有工作。

有谁能够帮我?

到目前为止,我只有以下代码。在循环中打印汇率的自定义方法:

private void printExchangeRateTable(final Map<String, Integer> storedExchangeRates){

    boolean runFlag = true;
    do {

        printExchangeRates(storedExchangeRates);

        println("Hit any key to stop loop");

        Thread threadDelayer = new Thread(new Delayer());
        Thread threadListeningUserInput = new Thread(new UserInputListener());

        threadDelayer.start();
        threadListeningUserInput.start();

        runFlag = ????;

    } while (runFlag);
}

延迟器对象

final class Delayer implements Runnable {

    public static final long MILISECONDS = 1000L;

    @Override
    public void run(){
        try {
            Thread.sleep(60 * MILISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

用户输入监听器

class UserInputListener implements Runnable {

    @Override
    public void run()  {
        Scanner scanner = new Scanner(System.in);
        val userInput = scanner.nextLine();
        if(userInput != null) {
            Thread.currentThread().interrupt();
        }
    }
}

标签: javaconcurrencyterminal

解决方案


您可以使用 设置重复任务ScheduledExecutorService,但在这里,将用户输入的读数发送到后台任务中要容易得多

public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    CompletableFuture<String> userInput = CompletableFuture.supplyAsync(s::nextLine);
    while(!userInput.isDone()) {
        printData();
        try {
            userInput.get(1, TimeUnit.MINUTES);
        }
        catch(ExecutionException|InterruptedException ex) {} // handled after the loop
        catch(TimeoutException ex) {
            continue;
        }
    }
    String input = userInput.join();
    // handle input
}

private static void printData() {
    System.out.println("data");
}

CompletableFuture.supplyAsync(s::nextLine)将提交执行s.nextLine()到后台任务。然后,循环将一直运行,直到后台任务完成,printData()每分钟执行一次。这是通过which 来实现的,如果在指定时间后没有可用的结果userInput.get(1, TimeUnit.MINUTES),则会抛出一个。TimeoutException这里continue没有必要,因为循环无论如何都会继续,但我明确表示了。

其他可能的异常是在本质上处理的。中断不应该发生,但是通过进入下一次迭代,它可以用作甚至在时间之前刷新打印数据的信号。当一个发生时,当我们在循环之后的语句ExecutionException中获得实际的用户输入时,将报告错误状态。join()

这个循环也可以合并到一个更大的循环中

Scanner s = new Scanner(System.in);
for(boolean quit = false; !quit; ) {
    CompletableFuture<String> userInput = CompletableFuture.supplyAsync(s::nextLine);
    while(!userInput.isDone()) {
        printData();
        try {
            userInput.get(1, TimeUnit.MINUTES);
        }
        catch(ExecutionException|InterruptedException ex) {} // handled implicitly
        catch(TimeoutException ex) {
            continue;
        }
    }
    String input = userInput.join();
    // handle input
    if(input.equals("exit")) quit = true;
}

推荐阅读