You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scanner.hasNext()导致需重复输入done/exit的问题求助

问题描述

作业要求实现程序完成以下功能:创建树、输出前/中/后序遍历结果并保存至文件。但输入环节存在异常:输入节点值后,必须输入两次done或exit才能触发对应操作(done继续执行,exit关闭程序),而节点值无需重复输入即可正常创建。相关输入逻辑代码如下:

//gets input from console until "exit" or "done" is typed
response = scanner.next();
while(scanner.hasNext() && !response.equals("exit") && !response.equals("done")) {
    fileWriter.write(response + " ");
    response = scanner.next();
}

移除scanner.hasNext()后程序可正常运行,但会丢失作业要求的EOF检测功能。

问题原因

原逻辑的核心问题在于循环判断顺序:

  1. 先读取一个response,进入循环时首先执行scanner.hasNext()——该方法会阻塞等待下一个输入,哪怕当前的response已经是done或exit。
  2. 只有再次输入内容后,scanner.hasNext()返回true,才会继续判断response是否为终止词,此时才会退出循环,导致需要两次输入终止指令。
解决方案

调整循环逻辑,先检测是否有下一个输入(保留EOF检测),再读取内容,读取后立即判断是否为终止词,这样既保留EOF检测能力,又无需重复输入终止指令。修改后的逻辑如下:

//gets input from console until "exit" or "done" is typed or EOF is reached
while (scanner.hasNext()) {
    response = scanner.next();
    if (response.equals("exit") || response.equals("done")) {
        break;
    }
    fileWriter.write(response + " ");
}

修改说明

  • 先通过scanner.hasNext()检测是否还有输入(包含EOF检测),避免不必要的阻塞。
  • 读取输入后立即判断是否为终止词,若是则直接跳出循环,无需等待下一次输入。
  • 仅当输入不是终止词时才写入文件,逻辑更清晰直观。
修改后的完整代码

P0类

/**
 * Sources for this class:
 * https://www.w3schools.com/java/java_regex.asp
 * https://stackoverflow.com/questions/14353947/how-to-represent-a-single-space-character-in-a-square-bracket-group
 * https://upload.wikimedia.org/wikipedia/commons/1/1b/ASCII-Table-wide.svg
 * 
 * Sources for shell script and makefile:
 * https://www.cyberciti.biz/faq/run-execute-sh-shell-script/
 * https://www.dummies.com/article/technology/computers/operating-systems/linux/linux-how-to-run-make-150284/
 * https://www.cs.swarthmore.edu/~newhall/unixhelp/javamakefiles.html
 */

package mikefitzgibbon.p0;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

public class P0{
    public static void main(String args[]) {
        File file = new File("file");
        String input = "";
        
        //there can only be one or 0 arguments in the command line operation
        if(args.length > 1) {
            System.out.println("Please only enter the name of 1 file.");
            System.exit(1);
        }
        //if a filename is specified, try getting the input from it
        else if(args.length == 1){
            file = new File(args[0]);
        }
        //else read from System.in
        else {
            Scanner scanner = new Scanner(System.in);
            String response;
            
            file = new File("input");
            try (FileWriter fileWriter = new FileWriter(file)) {
                System.out.println("Please enter strings to put into the tree.");
                System.out.println("Type \"done\" to end taking in input, and type \"exit\" to prematurely quit.");

                // 修改后的输入逻辑
                while (scanner.hasNext()) {
                    response = scanner.next();
                    if (response.equals("exit") || response.equals("done")) {
                        break;
                    }
                    fileWriter.write(response + " ");
                }

                //exits the program with OK return value
                if(response.equals("exit")) {
                    System.out.println("Prematurely ending program now.");
                    System.exit(0);
                }
            }
            catch(IOException e){
                System.out.println("Had trouble writing to file from System.in.");
            }
        }
        
        //scans file for strings until there are no more data or eof is reached
        try(Scanner scanner = new Scanner(file)){
            while(scanner.hasNextLine()){
               input += scanner.nextLine() + " ";
            }
            scanner.close();
        }
        //exit the program is file name is invalid
        catch(FileNotFoundException e){
            System.out.println("The file name you entered does not exist.");
            System.exit(2);
        }

        //checks input for characters outside of the appropriate ASCII range
        for(char c : input.toCharArray()){
            if(!Character.isLetterOrDigit(c) &! Character.isWhitespace(c)) {
                System.out.println("Your file or console input was not readable."
                        + "\nPlease only use alhpanumeric characters.");
                System.exit(3);
            }
        }
        
        //this is only used as a reference for the filename
        if(file.getName().equals("input"))
            file = new File("output");
            
        //creates the tree from the input and then converts it to the output
        Tree tree = new Tree(input);
        
        //displays the input
        System.out.println("Here is your input for the program.");
        System.out.println(input);
        System.out.println();

        //writes to the files
        System.out.println("Outputting data to files " + 
                file.getName() + ".preorder, " + 
                file.getName() + ".inorder, and " + 
                file.getName() + ".postorder.");
        System.out.println();
        System.out.println("Output for " + file +".preorder: ");
        tree.printPreorder(file.getName());
        System.out.println();
        System.out.println("Output for " + file +".inorder: ");
        tree.printInorder(file.getName());
        System.out.println();
        System.out.println("Output for " + file +".postorder: ");
        tree.printPostorder(file.getName());
        System.out.println();

        System.out.println("Ending program now.");
    }

}

Tree类

/**
 * Sources for this class:
 * https://www.w3schools.com/java/java_files_create.asp
 * https://www.softwaretestinghelp.com/binary-search-tree-in-java/
 * https://www.youtube.com/watch?v=WLvU5EQVZqY&ab_channel=TECHDOSE
 */

package mikefitzgibbon.p0;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

public class Tree {
    //nodes that make up this part of the tree
    Node root;

    //constructor calls the buildTree() function
    public Tree(String input){
        buildTree(input);
    }
    
    //takes a list of strings and a root node and creates the tree structure recursively using the addNode helper function
    private void buildTree(String input) {
        Scanner scanner = new Scanner(input);
        
        //recursively builds tree with each word
        while(scanner.hasNext()){
            root = addNode(root,scanner.next());
        }
    }
    
    private Node addNode(Node root, String value){
        //checks root for null and sets it if it is
        if(root == null){
            root = new Node(value);
            return root;
        }
        //compares the first letter of the input to the root's value and recursively traverses tere
        else if(root.getValue().charAt(0) > value.charAt(0))
            root.setLeftNode(addNode(root.getLeftNode(),value));
        else if(root.getValue().charAt(0) == value.charAt(0))
            root.setMiddleNode(addNode(root.getMiddleNode(),value));
        else if(root.getValue().charAt(0) < value.charAt(0))
            root.setRightNode(addNode(root.getRightNode(),value));
        
        //return root if all else fails
        return root;
    }

    //prints the tree printPreorder recursively
    public void printPreorder(String filename){
        try(FileWriter myWriter = new FileWriter(filename + ".preorder")) {
            printPreorder(myWriter, root, 0);
            myWriter.close();
            System.out.println();
            System.out.println("Successfully wrote to the preorder file.");
        } 
        catch (IOException e) {
            System.out.println("An error occurred while writing to the preorder file.");
        }
    }
    
    //helper function for printPreorder()
    private void printPreorder(FileWriter fileWriter, Node root,int depth) {
        //base case
        if(root == null)
            return;
        //write to file and recursive cases
        try{
            String indent = "";
            for(int a = 0 ; a < depth ; a++){
                indent += "  ";
            }
            fileWriter.write(indent + root.getValue().charAt(0) + ":" + root.getValue() + "\n");
            System.out.println(indent + root.getValue().charAt(0) + ":" + root.getValue());
        }
        catch(IOException e){
            System.out.println("Something went wrong while writing to the .preorder file.");
            System.exit(4);
        }
        depth++;
        printPreorder(fileWriter, root.getLeftNode(), depth);
        printPreorder(fileWriter, root.getMiddleNode(), depth);
        printPreorder(fileWriter, root.getRightNode(), depth);
    }

    //prints the tree printInorder recursively
    public void printInorder(String filename){
        try(FileWriter myWriter = new FileWriter(filename + ".inorder")) {
            printInorder(myWriter, root, 0);
            myWriter.close();
            System.out.println();
            System.out.println("Successfully wrote to the inorder file.");
        } 
        catch (IOException e) {
            System.out.println("An error occurred while writing to the inorder file.");
        }
    }
    
    //helper function for printInorder()
    private void printInorder(FileWriter fileWriter, Node root,int depth) {
        //base case
        if(root == null)
            return;
        
        //write to file and recursive cases
        int previousDepth = depth;
        depth++;
        printInorder(fileWriter, root.getLeftNode(), depth);
        
        try{
            String indent = "";
            for(int a = 0 ; a < previousDepth ; a++){
                indent += "  ";
            }
            fileWriter.write(indent + root.getValue().charAt(0) + ":" + root.getValue() + "\n");
            System.out.print(indent + root.getValue().charAt(0) + ":" + root.getValue() + "\n");
        }
        catch(IOException e){
            System.out.println("Something went wrong while writing to the .preorder file.");
            System.exit(4);
        }
        
        printInorder(fileWriter, root.getMiddleNode(), depth);
        printInorder(fileWriter, root.getRightNode(), depth);
        
        depth++;
    }

    //prints the tree printPostorder recursively
    public void printPostorder(String filename){
        try(FileWriter myWriter = new FileWriter(filename + ".postorder")) {
            printPostorder(myWriter, root, 0);
            myWriter.close();
            System.out.println();
            System.out.println("Successfully wrote to the postorder file.");
        } 
        catch (IOException e) {
            System.out.println("An error occurred while writing to the postorder file.");
        }
    }
    
    //helper function for printPostorder()
    private void printPostorder(FileWriter fileWriter, Node root,int depth) {
        //base case
        if(root == null)
            return;
        
        //write to file and recursive cases
        int previousDepth = depth;
        depth++;
        
        printPostorder(fileWriter, root.getLeftNode(), depth);
        printPostorder(fileWriter, root.getMiddleNode(), depth);
        printPostorder(fileWriter, root.getRightNode(), depth);
        
        try{
            String indent = "";
            for(int a = 0 ; a < previousDepth ; a++){
                indent += "  ";
            }
            fileWriter.write(indent + root.getValue().charAt(0) + ":" + root.getValue() + "\n");
            System.out.print(indent + root.getValue().charAt(0) + ":" + root.getValue() + "\n");
        }
        catch(IOException e){
            System.out.println("Something went wrong while writing to the .postorder file.");
            System.exit(4);
        }
    }

    //getter and setter
    public void setRoot(Node node) {
        root = node;
    }

    public Node getRoot() {
        return root;
    }

}

Node类

/**
 * Sources for this class:
 * https://www.softwaretestinghelp.com/binary-search-tree-in-java/
 */
package mikefitzgibbon.p0;

public class Node {
    //this is how the tree branches out, 3 children per node
    Node left, middle, right;
    String value = "";
    
    public Node(String val) {
        value=val;
    }
    
    //getters and setters
    public void setRightNode(Node node) {
        right=node;
    }

    public void setLeftNode(Node node) {
        left=node;
    }

    public void setMiddleNode(Node node) {
        middle=node;
    }

    public Node getRightNode() {
        return right;
    }

    public Node getLeftNode() {
        return left;
    }

    public Node getMiddleNode() {
        return middle;
    }

    public String getValue() {
        return value;
    }

}

内容的提问来源于stack exchange,提问作者The Dog on the Log

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 06:55:21