hasNext() - when does it block and why? - java

I'm trying to read commands via a Scanner Object. For checking the Input Syntax I use sc.hasNext() (for the case of missing commands). It did work fine for many cases already, but now I have the case that's described in the JavaAPI as "MAY block and wait for Input".
When does the hasNext() method block and how can I control it? The funny Thing is that it work's perfectly fine with 3 cases before the block. Also the JavaAPI describes hasNext() as the proper method for checking wether there is another Input or not so that the Method next() doesn't produce an Exception.
Here is the code I did produce till now:
if (sc.hasNext() && sc.next().equals("create")) {
if (sc.hasNextInt()) {
width = sc.nextInt();
if (width > 0) {
if (sc.hasNextInt()) {
heigth = sc.nextInt();
if (heigth > 0) {
if (sc.hasNext()) { //At this point the hasNext Statement blocks for //no reason till an Input is made.
charset = sc.next();
Image = new AsciiImage(width, heigth,charset);
} else {
ret = false;
System.out.println("INPUT MISMATCH");
}
} ...//and so on
Thanks in advance, I couldn't find anything on this Topic an my own.
Edit: The Scanner is defined as a System.in, but that shouldn't be a Problem - at least it hasn't been one till now.

There is a difference between testing via Console or via TextFile. If I read from Console the program expects a Stream and it will wait for further Input.
When testing via Input from Textfile (still with System.in for the Scanner, using Java Program ) the hasNext() will return false at the end of the file as no further Input can be done.
I can't really find documentation (in https://docs.oracle.com/javase/9/docs/api/java/util/Scanner.html#hasNext--) on this Topic. So if anyone finds a proper and technical correct answer I would be very greatfull.

If you have nothing else to do while waiting for user input, then it's fine to be blocked at that call until the next input arrives.
If you do want to run other code while waiting for input, spawn a new thread and call hasNext and other blocking scanner methods from there.

I'm not sure , but the following is my own experience :
when the Scanner object is fed with a file , it will not be blocking !
By the term "fed with a file " I mean that the scanner is constructed like this : Scanner scanner = new Scanner("myFile.txt");
But if the scanner is constructed using the getInputStream()method of a Socket object , like this :
input = socket.getInputStream();
Scanner scanner = new Scanner(input);
the scanner will be blocking !

Related

How to read Multiple line input [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm trying to read multiple line input like a copy past input, but I can't end the while loop to stop reading. Here is my code:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input =null;
while(sc.hasNext()) {
input=sc.next();
}
String [] split = input.split(" ");
for(int i = 0;i<split.length;i++) {
for(int j = split[i].length()-1;j>=0;j--) {
System.out.print(split[i].charAt(j));
}
System.out.print(" ");
}
sc.close();
}
}
Use buffer reader class, by this you'll be able to take multiple inputs at the same time.
https://docs.oracle.com/javase/6/docs/api/java/io/BufferedReader.html
The hasNext() method will look if there is something to read. To do so it might block and wait on the used InputStream as described in the documentation of hasNext():
public boolean hasNext()
Returns true if this scanner has another token in its input. This method may block while waiting for input to scan. The scanner does not advance past any input.
When the InputStream ends it will return from the hasNext() call and return false, since there is no token to read (and the source of data/bytes is closed). But since you are reading from the keyboard via System.in there is no "end" of input because you still can enter new text into your application, which your while() loop will read.
There are several solutions for this:
Depending on how you start your java application, you can press CTRL-D to explicit close the so called "STDIN" stream which is "attached" to your keyboard input. That way the stream System.in will end and no further data can be read. This is also detected by the Scanners hasNext() method, which will return false at that point.
You can call your java application where you provide the data for the "STDIN" stream via a file or via other commands. Examples of these are: echo "data" | java Main or java Main < inputData.txt (depending on the terminal/console you are using).
Add an end marker to your content and look for it. When you place a text like "MY_TEXT_END" in your data and look for it you can use a simple equals() check inside the while() loop and stop reading when you have seen your marker "MY_TEXT_END".
Since you are using while loop and it will loop/execute through a block of code as long as a specified condition is true/met.
And here you are checking any condition to exit the loop.This method may block while waiting for input to scan and the scanner does not advance past any input.
Another gap that I see is, you are re-assigning the input to input var again and again without performing any operation beforehand accepting next line.
You can get more clarity on exiting the while loop here :
How to get out of while loop in java with Scanner method "hasNext" as condition?
Scanner sc = new Scanner(System.in);
String input = null;
while(sc.hasNext() && !(input = sc.next()).equals("exit")) {
System.out.println(input);
}
sc.close();
So, to answer your question, you must provide some check/exit condition for while loop to in-validate and exit out of the loop.

Scanner gets skipped

I'm trying to get 2 integers from the user. This is the related part of my code:
public void play() {
int row=0,col=0;
initializeboard();
printboard();
do {
currentPlayer = players.remove(); //Returns currentPlayer
System.out.println("Ok, "+ currentPlayer.getname() + ", Enter your Move: Row[1-3] & Column[1-3]");
Scanner choice = new Scanner(System.in);
if (choice.hasNext()) {
row = choice.nextInt();
col = choice.nextInt();
while (row<1 || row>3 || col<1 || col>3 || board[row-1][col-1] != '-' ) {
System.out.println("Well, Move is not Valid or has already Been Selected, Try Again :/");
row = choice.nextInt();
col = choice.nextInt();
}
choice.close();
}
board[row][col] = currentPlayer.getsign(); //Places Sign in Game Board
printboard();
System.out.println();
players.append(currentPlayer); //Inserts the Next Player
} while(!win() && !isFull());
}
At first, it throws a NoSuchElementException, so I used .hasNext(). Now, it just skips the scanner and immediately invokes printboard().
The problem is that you are creating and then closing multiple Scanner objects with the same stream.
The answer from Peter Lawrey in this post explains why you shouldn't create multiple Scanner objects from the same stream. Here is a quote from the answer:
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.
The best thing is to create one final Scanner object (per stream) in your program and just pass it into methods when you want to use it:
static final Scanner scan = new Scanner(System.in);
Here is the problem :
do {
Scanner choice = new Scanner(System.in);
[...]
choice.close();
} while (!win() && !isFull());
You are opening a Scanner in a loop (first mistake) but more important, you are closing the Scanner.
Closing a Scanner also close the InputStream used, in your case System.in. You can't open that stream again so you will never be able to execute your loop twice.
public void close()
If this scanner has not yet been closed then if its underlying readable also implements the Closeable interface then the readable's close method will be invoked.
And this is in fact the problem you are facing. Once you have closed the first Scanner created and then try to open a new one, since System.in is closed, there is no value to read (hasNext return false). And you most likely enter an infinite loop since !win() && !isFull() will always give the same result.
I suggest not close it (in this case, this is not always a bad thing since it is a local variable, there is no risk).
Or simply use a parameter in the method to provide it (and still not closing it in the method). Let the main method manage the Scanner.
public void play(Scanner choice){
...
}
It might have been throwing the NoSuchElementException because you didn't input a integer.
The reason it "skips" over the Scanner is possibly because all hasNext evalutes is whether the System.in has a String contained in it. So it evalutes that expression and returns true or false. Your program then evaluates the expression in the while loop, possibly finding it to be false. Then finally moving on and invoking printboard.
I would suggest going back and changing hasNext to
row = choice.nextInt();
col = choice.nextInt();
Then make sure you are inputting integers.

Data Validation and Scanners in Java

I have a question regarding data validation and scanners.The following piece of code checks userinput.Anything other than an integer is not allowed and the user is asked to re-enter a value.My question is that the code works only if the scanner is declared within the while loop.The program executes infinitely if the scanner is declared outside.Why is that?Thanks.
int UserInp;
boolean dataType=false;
while(dataType==false)
{
Scanner sc=new Scanner(System.in);
try
{
System.out.print("\nEnter a number: ");
UserInp=sc.nextInt();
dataType=true;
}
catch(Exception JavaInputMismatch)
{
System.out.println("Option not available.Try again.");
}
}
Interesting problem!
What happens is that the Scanner attempts to translate the non-integer to an integer, and realizes it can't -- so it throws an InputMismatchException. However, it only advances past the token if the translation was successful.
Meaning, the invalid string is still in the input buffer, and it will fail the translation every single time you loop and try to call nextInt(). You never set dataType to true, and so you loop infinitely.
To see this in action, you can grab the arbitrary content in your catch block and print it out:
catch(Exception JavaInputMismatch){
System.out.println( sc.next() );
System.out.println("Option not available.Try again.");
}
Indeed, after invalid input, we get the following:
Enter a number: hello
hello
Option not available.Try again.
Enter a number:
And we don't loop infinitely. This is because the call to next() grabbed the value from the input buffer and advanced the scanner's pointer into that buffer to the next slot, which is now empty. So nextInt() will wait for input in that case.
Oh, and the reason it works fine if you initialize in the loop is that the scanner will always start reading input fresh; scanners don't share state across instances, so the "hello" that was in the buffer for the previous iteration isn't in the buffer for the next one due to the reinitialization.
Technically, it's still in the standard input buffer, but the scanner's pointer into that buffer is beyond the invalid string because it will start reading any new input, not existing input.
To add to Purag's answer, you could alternatively use nextLine() to advance the Scanner past the current line.
So your catch block will look like this:
catch(Exception JavaInputMismatch)
{
System.out.println("Option not available.Try again.");
sc.nextLine();
}
Tricky question.
You may get it!
The answer is simple. The Scanner object is kept live till the end of the execution as it is declared outside the while loop. Look this problem in the memory level.
The Scanner object is kept live so while entering the loop next time still the value(String value) will be there in Scanner object and it doesn't listens keyboard as the exception is already thrown.So the loop keeps going.
Note : The next() method in Scanner class will accept all the types of keyboard input but not the rest of the methods such as nextInt(), nextFloat() etc..,

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().

How do I keep a Scanner from throwing exceptions when the wrong type is entered?

Here's some sample code:
import java.util.Scanner;
class In
{
public static void main (String[]arg)
{
Scanner in = new Scanner (System.in) ;
System.out.println ("how many are invading?") ;
int a = in.nextInt() ;
System.out.println (a) ;
}
}
If I run the program and give it an int like 4, then everything goes fine.
On the other hand, if I answer too many it doesn't laugh at my funny joke. Instead I get this(as expected):
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:819)
at java.util.Scanner.next(Scanner.java:1431)
at java.util.Scanner.nextInt(Scanner.java:2040)
at java.util.Scanner.nextInt(Scanner.java:2000)
at In.main(In.java:9)
Is there a way to make it ignore entries that aren't ints or re prompt with "How many are invading?" I'd like to know how to do both of these.
You can use one of the many hasNext* methods that Scanner has for pre-validation.
if (in.hasNextInt()) {
int a = in.nextInt() ;
System.out.println(a);
} else {
System.out.println("Sorry, couldn't understand you!");
}
This prevents InputMismatchException from even being thrown, because you always make sure that it WILL match before you read it.
java.util.Scanner API
boolean hasNextInt(): Returns true if the next token in this scanner's input can be interpreted as an int value in the default radix using the nextInt() method. The scanner does not advance past any input.
String nextLine(): Advances this scanner past the current line and returns the input that was skipped.
Do keep in mind the sections in bold. hasNextInt() doesn't advance past any input. If it returns true, you can advance the scanner by calling nextInt(), which will not throw an InputMismatchException.
If it returns false, then you need to skip past the "garbage". The easiest way to do this is just by calling nextLine(), probably twice but at least once.
Why you may need to do nextLine() twice is the following: suppose this is the input entered:
42[enter]
too many![enter]
0[enter]
Let's say the scanner is at the beginning of that input.
hasNextInt() is true, nextInt() returns 42; scanner is now at just before the first [enter].
hasNextInt() is false, nextLine() returns an empty string, a second nextLine() returns "too many!"; scanner is now at just after the second [enter].
hasNextInt() is true, nextInt() returns 0; scanner is now at just before the third [enter].
Here's an example of putting some of these things together. You can experiment with it to study how Scanner works.
Scanner in = new Scanner (System.in) ;
System.out.println("Age?");
while (!in.hasNextInt()) {
in.next(); // What happens if you use nextLine() instead?
}
int age = in.nextInt();
in.nextLine(); // What happens if you remove this statement?
System.out.println("Name?");
String name = in.nextLine();
System.out.format("[%s] is %d years old", name, age);
Let's say the input is:
He is probably close to 100 now...[enter]
Elvis, of course[enter]
Then the last line of the output is:
[Elvis, of course] is 100 years old
In general I really, really dislike using the same library call for both reading and parsing. Language libraries seem to be very inflexible and often just can't be bent to your will.
The first step that pulls data from System.in should not be able to fail, so have it read it as a string into a variable, then convert that string variable to an int. If the conversion fails, great--print your error and continue.
When you wrap your stream with something that can throw an exception, it gets kind of confusing just what state the whole mess leaves your stream in.
It's always a benefit to have your application throw an error when an error occurs opposed to ways to keep it from happening.
One alternative is to wrap the code inside a try {...} catch {...} block for InputMismatchException.
You might also want to wrap the code inside a while loop to have the Scanner keep prompting until a specific condition is met.

Categories