Scanner.hasNext()导致需要两次输入



我正在做一些家庭作业,遇到了一个问题。该程序创建一个Tree,输出前/中/后顺序遍历,然后将它们保存到多个文件中。我遇到的问题是输入。当您键入输入时,在您键入了应该是不同Nodes的值之后,您可以键入";完成";或";退出"完成";用给定的输入继续程序;退出";只是关闭程序。奇怪的是,您不需要两次键入Node的值来稍后在代码中创建这些Node,但您必须键入";完成";或";退出";两次让节目听你讲。有问题的代码在这里:

//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的感知。

以下是程序中使用的全部三个类: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.");
//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();
}
//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.");
}
}

树:

/**
* 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;
}
}

节点:

/**
* 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;
}
}

scanner.hasNext()阻止(冻结线程(,直到用户输入为止。你可能会认为";不,它将返回false,因为当前没有可用的令牌-没有"下一个";,但事实并非如此。目前可能确实没有下一个。但谁知道接下来会发生什么呢?也许用户键入CTRL+C,关闭管道,因此hasNext()现在将返回false,因为永远不会有下一个令牌。或者,用户键入一些内容,然后它将返回true,因为现在显然有下一个令牌。这就是它阻止的原因:在你做某事之前,它无法给出特定的答案。

这可能毫无意义-请记住,"标准输入">不是键盘。这是。。。任何流连接到标准输入默认情况下这是一个键盘,但使用java -jar whatever.jar <somefile.txt运行应用程序,现在它就是那个文件。它的尺寸有限。一旦到达"文件末尾",hasNext()就会开始返回false。你通常无法到达"键盘的尽头",但抽象并不是专为键盘设计的。

换句话说,你的代码:

response = scanner.next();
while(scanner.hasNext() && ....

意志:

  1. 从标准输入中读取令牌
  2. 威尔。。。再次从标准输入中读取令牌(因为hasNext()会这样做。如果成功,则返回true。如果现在没有令牌,将来也不会有令牌,则返回false(

这解释了为什么必须输入两次输入。解决方案是删除那里的hasNext调用。将其移动到while循环中。不要在循环中使用response = scanner.next(),而是执行以下操作:

if (!scanner.hasNext()) return; // or break, or System.exit(0), or whatever you want.
response = scanner.next();
}

我发现在表达式末尾放置scanner.hasNext((可以解决问题,但我不完全确定如何解决。这是更新后的代码:

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

最新更新