Java - program skips Scanner(System.in) [duplicate] - java

This question already has an answer here:
How to use java.util.Scanner to correctly read user input from System.in and act on it?
(1 answer)
Closed 5 years ago.
public static char[] puzzleInput() {
printEnterPuzzleMessage();
Scanner puzzleS = new Scanner(System.in);
if(puzzleS.hasNext()) {
char[] puzzle = puzzleS.next().toCharArray();
while(!isLegalPuzzleStructure(puzzle)) {
printIllegalPuzzleMessage();
puzzleInput();
}
return puzzle;
}
puzzleS.close();
return null;
}
public static void main(String[] args) throws Exception{ //Q - 8
Scanner fileName = new Scanner(System.in);
if(!fileName.hasNext()) {
System.out.println("No argument has been received");
System.exit(0);
}
String filePath = fileName.nextLine();
fileName.close();
Scanner vocabulary = new Scanner(new File(filePath));
String[] vocabularyArr = scanVocabulary(vocabulary);
vocabulary.close();
printReadVocabulary(filePath, vocabularyArr.length);
printSettingsMessage();
printEnterPuzzleMessage();
char[] puzzle = puzzleInput();
Hi, a beginner in Java is here.
In the function puzzleInput, I open a Scanner to get an input from the user. For some reason, the program won't give me a chance to put in input, and therefor the argument (puzzle) gets a null as default, and later when puzzle is needed not as a null - throws a NullPointerException.
There are many other functions in the code, but most of them are just a print commands, and the ones who are not were being checked by me, and are OK.
The problem is just the scanner won't give me a chance to put in an input.
Some points I'd like to clarify further:
1. The first Scanner (fileName) is not being skipped by the program, and I'm able to give it an argument.
2. I made sure I closed all the other scanners i've opened before.
Can someone explain me what I'm doing wrong?

program won't give me a chance to put in input
Your problem is that you are closing your Scanner in main:
Scanner fileName = new Scanner(System.in);
...
fileName.close();
This in turn closes the System.in input-stream which then cannot be reused in your puzzleInput() method because it is already closed. The right thing to do here is to pass in the Scanner variable into your puzzleInput() method and continue to reuse it there and not try to open up a new Scanner.
public static char[] puzzleInput(Scanner scanner) {
printEnterPuzzleMessage();
if(scanner.hasNext()) {
...
// don't close it here
return null;
}
...
Scanner scanner = new Scanner(System.in);
...
puzzleInput(scanner);
Couple of other comments:
Calling a Scanner fileName is not a good pattern. Choosing good names for your variables will help make the code self-documenting. scanner would be a better name of course.
When dealing with any input/output, it is a good practice to wrap any opening method in a try/finally block so it gets close properly. See also the try-with-resources functionality added in Java 7.

If you want a chance to do something with the input with a prompt, why not assign it to a String variable? This allows you to manipulate the input however you want later on too.
String input = scannerName.nextLine();

Related

Java display file line by line using Enter key

I'm trying to progress displaying a file line by line with an Enter key, but the if statement that I try doesn't seem to work. If I disregard the if statement, it works, but it feels incomplete because then I'm asking for input and doing nothing with it.
This is what I have:
import java.util.Scanner;
import java.io.*;
public class LineByLine {
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
System.out.println("What is the filename?");
String input = in.nextLine();
BufferedReader buff = new BufferedReader(new FileReader(input));
String sen = buff.readLine();
System.out.println(sen);
Scanner enter = new Scanner(System.in);
while (sen != null){
String output = enter.next();
if (output.equals("")){
System.out.println(sen = buff.readLine());
}
}
}
}
I just don't know why my if statement doesn't work.
The core issue is that you misunderstand Scanner and its default configuration: Out of the box, scanner splits on any amount of whitespace. .next() asks for the next token; a token is the thing that appears in between the whitespace.
Thus, pressing enter 500 times produces zero tokens. After all, tokens are what's in between the separator, and the default separator is 'any amount of whitespace'. Pressing enter a bunch of time is still just you entering the same separator.
The underlying problem is that most people appear to assume that Scanner reads one line at a time. It doesn't do that. At all. But you want it to. So, tell it to! Easy peasy - make scanner do what you already thought it did:
Scanner in = new Scanner(System.in);
in.useDelimiter("\\R"); // a single enter press is now the separator.
You should also stop using nextLine on scanners. nextLine and any other next call do not mix. The easiest way to solve this problem is to only ever use nextLine and nothing else, or, never use nextLine. With the above setup, .next() gets you a token which is an entire line - thus, no need for nextLine, which is good news, as nextLine is broken (it does what the spec says it should, but what it does is counterintuitive. We can debate semantics on whether 'broken' is a fair description of it. Point is, it doesn't do what you think it does).
Also, while you're at it, don't make multiple scanners. And, to improve this code, resources must be properly closed. You're not doing that. Let's use try-with, that's what it is for.
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
in.useDelimiter("\\R");
System.out.println("What is the filename?");
String input = in.next();
try (BufferedReader buff = new BufferedReader(new FileReader(input))) {
String sen = buff.readLine();
System.out.println(sen);
while (sen != null){
enter.next(); // why does it matter _what_ they entered?
// as long as they pressed it, we're good, right? Just ignore what it returns.
System.out.println(sen = buff.readLine());
}
}
}

Can't get program to break on specific string [duplicate]

This question already has answers here:
Scanner only reads first word instead of line
(5 answers)
Closed 2 years ago.
The code works for the most part, but if I type "No way" it still stops the loop. Should I set it up a different way or use a length function ? Everything I've searched on breaking a loop used integers.
See the code below:
import java.util.Scanner;
public class CarryOn {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("Shall we carry on?");
String answer = String.valueOf(scanner.next());
if (answer.equalsIgnoreCase("no")){
break;
}
}
}
}
Using .next in this case only stores "no" in "no way". Use .nextLine instead:
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("Shall we carry on?");
String answer = String.valueOf(scanner.nextLine());
if (answer.equalsIgnoreCase("no")){
break;
}
}
Output:
Shall we carry on?
no way
Shall we carry on?
no
Check this post for more information.
scanner.next()
only reads a single token. No way is two tokens: No and way.
Use scanner.nextLine() instead, if you want to read the whole line.

Can you reopen a closed Scanner? close() not working the way I want it to

Just for context I am working on MOOC Object-Oriented Programming with Java, Week 9 exercise 21: Printer.
In this exercise I am making a Printer class which can receive any file input to its constructor parameter to print out text.
In the method printLinesWhichContain(String word), I need to, using a Scanner, print lines of a file which only contain the word in the parameter.
public void printLinesWhichContain(String word){
if(!word.equals("")){
String string = "";
while(reader.hasNextLine()){
String line = reader.nextLine();
if(line.contains(word)){
string += line;
string += "\n";
}
}
System.out.println(string);
}
else {
printAll();
}
reader.close();
}
If I run my program once with multiple of the above method, the first method works, with the others receiving a Scanner closed error. Example below...
Printer printer = new Printer("src/textfile.txt");
printer.printLinesWhichContain("on"); //this works
printer.printLinesWhichContain("vanha"); //Scanner closed
printer.printLinesWhichContain("tuli"); //Scanner closed
I have no idea how a Scanner works. The Scanner is closing as programmed but once I need to use it again, it's inaccessible. reset() method doesn't help lol. Even if the close() method isn't coded, it doesn't want to print out the rest as, what I could guess, the Scanner's "line" has permanently "moved" with nextLine(). I need a little explanation.

How can I clear the input buffer to ignore input given before prompt?

I have a client/server game where users take turns giving input to the game. I want anything a user types when it is not their turn to be ignored. I want to scan only the inputs the user gives after they are prompted. I am using java.util.Scanner for input, but I can't find a way to "flush" the scanner buffer without the program hanging. I also cannot find examples of other input reading methods doing what I want.
This is what I tried:
Scanner in = new Scanner(System.in);
//do game stuff
//I don't care about anything typed at this time
while(in.hasNextLine()){
in.nextLine();
}
System.out.println("Enter your move:");
String input = in.nextLine();
There is no way to disable a Scanner and re-enable it. Here are a few suggestions:
You can manually empty the Scanner before the player's turn like so (what (I think) you've been doing):
while(in.hasNext()) in.next();
Or, you can close the scanner at the end of the player's turn and instantiate a new one at the beginning of the next turn (you can't reopen a closed Scanner):
//Player's turn
//
//End of player's turn...
in.close();
//Beginning of player's turn
in = new Scanner(System.in);
This, however, will throw an IllegalStateException if you try to access the Scanner after it has been closed. To solve this, try (on Java 7 and later) the try-with-resources block:
//Overridden close method because you don't want to close System.in
try (Scanner in = new Scanner(new InputStreamReader(System.in)
{public void close() throws IOException {}})) {
System.out.println("Enter your move:");
String input = in.nextLine();
}
//End of player's turn
//Scanner is automatically closed and this code is out of the scanner's scope
I think this last option is your best bet. It restricts the scope of the Scanner to the relevant code, and it automates the instantiating/closing. Plus, it uses a (relatively) recent Java feature, so that might be the required answer to your problem.

Java Multiple Scanners

I have a class that creates multiple Integer objects and puts them into a LinkedList as shown below:
public class Shares<E> implements Queue<E> {
protected LinkedList<E> L;
public Shares() {
L = new LinkedList<E>();
}
public boolean add(E price) {
System.out.println("How many of these shares would you like?");
Scanner scanInt;
scanInt = new Scanner(System.in);
Integer noShares = scanInt.nextInt();
for (int i = 0; i < noShares; i++) {
L.addLast(price);
}
scanInt.close();
return true;
}
}
I have an application that scans for the input "add" from the console and if found, invokes the method add as shown below:
public class Application {
private static Scanner scan;
public static <E> void main(String[] args) {
Queue<Integer> S = new Shares<Integer>();
scan = new Scanner(System.in);
System.out.println("Please type add");
String sentence = scan.nextLine();
while (sentence.equals("quit") == false) {
if (sentence.equals("add")) {
System.out
.println("What price would you like to buy your shares at?");
S.add((Integer) scan.nextInt());
} else
System.exit(0);
sentence = scan.nextLine();
}
}
}
The application should allow the user to enter "add" as many times as they wish but the error "no line found" appears after the add method has been invoked.
I'm guessing this is because the Scanner in the method, has not been closed and then reopened when needed. Is this what is wrong with the program and if so, how would I go about fixing it?
Please note, this program is not finished, as I will be adding a selling method that sells these shares. That is why I am using a while loop.
Having multiple wrappers for any stream is a great way to really confuse yourself. I suggest you only ever wrap a stream once unless you really know what you are doing.
The simplest way to do this is to use a singleton in this case as it wraps another singleton (the best is to pass around the Scanner as an argument)
public class Application {
// use this Scanner in all you other code, don't create another one.
static final Scanner scan = new Scanner(System.in);
public static <E> void main(String[] args) {
Im guessing this is because the scanner in the method has not been closed
Once you close a stream it closes the underlying stream and you can't use it again. Only close System.in if you want to prevent it being used again.
how would I go about fixing it?
The best solution is to have all your Scanner use in one place, one method or one class. You have your main() do all the interaction with the user and pass the values to your data structure. Having objects which initialise themselves is a bad practice to get into and if you start doing this, it will plague you for the rest of your development days ;) (Seriously you will see this done again and again and its often a nightmare)
BTW Never exit a program without explanation. Calling System.exit(0); without even an error message is also a nightmare. I once worked on a project which has 260 calls to System.exit() often without an error message, you can imagine how much fun it is to diagnose a server just stopping for no apparent reason.
A first mistake is that this line of code
scanInt.close();
closes the System.in, not just the scanInt object. This means that after the first call to add, the scan object will only consume the input it already has and then you'll receive a NoSuchElementException: Remove this line.
Now, if you replace the last line you have with this
sentence = scan.nextLine();
System.out.println("sentence: \"" + sentence + "\"");
you will see that the last input you get before exiting is an empty String. So in the next loop you enter the else statement and your program stops execution. You can fix this problem by adding the following:
scan.nextLine(); // consume the first always empty String...
System.out.println("Please type add");
sentence = scan.nextLine(); // and then get the actual value
However, I will agree with Peter that you should not use multiple wrappers. Consider passing the Scanner object as an argument in the Shares class contractor.
Having multiple scanners (on same stream) is a very bad practice, because scanners consume the stream they share.
I've verified it while debugging the Scanner class source code, and there I’ve found:
a reference to the source input stream
a internal private buffer used to hold input.
So when a scanner instance consume its stream, basically it just read a bunch of bytes (1024) and the stream's position is moved ahead.
For example when the nextLine() method is invoket, behind the scenes the source.read() copy the result into the private buffer.
Obviously the state of other Scanner becomes corrupted (invalid).
Try to debug the Java source code yourself and/or look at the method Scanner.readInput().

Categories