Checking hasNextInt() in if and then receive an input - java

So a simple program would be:
import java.util.*;
public class practice {
static Scanner reader = new Scanner(System.in);
public static void main(String[] args) {
if(reader.hasNextInt()){
int numberEntered = reader.nextInt();
}
}
}
So I have a misunderstanding. hasNextInt() is supposed to check if the next input will be an int or not. I saw this program and I don't understand how the number can be inputed. Because already for getting an input the reader.hasNextInt() needs to be true and the program hasn't got an input. So how will the program get inside the if statement?

The method Scanner#hasNextInt(), in your case, is a blocking method. This means, it is a method which waits and does only return if some conditions are met. It looks something like this:
public boolean hasNextInt() {
...
boolean condition = false;
while(!condition) {
...
}
...
return stuff;
}
To be more precise, the blocking method is Scanner#hasNext(). It is described in its documentation.
If the method blocks or not depends on the Scanners source. If it is, for example System.in, it will wait. If it is just a File, it will read the whole file until its end and then return, no blocking.
So, what happens? The hasNextInt in your if-condition waits for you to enter some input (until you send it by typing Enter). Then the Scanner saves the input inside a buffer. hasNextInt checks the internal buffer but does not delete stuff from the buffer.
Now comes nextInt which reads from the internal buffer and also deletes the stuff inside it. It advances past read input.
You can read it in detail inside the documentation mentioned above.
Things short: Scanner#hasNextInt() waits for input before it returns true or false.

Related

Code after while loop never executes

Obviously, my real code is more complex, but here's an example:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in).useDelimiter("\n");
String[] cmdSplit = null;
while (true) {
while (input.hasNext()) {
cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
}
for (int i = 0; i < cmdSplit.length; i++) System.out.println(cmdSplit[i]);
}
}
}
In the above example, the code takes input from System.in, splits it, and should output each piece. However, for some reason, the code after the inner while loop never executes. If I replace while with if, it works. If you test it, you can see it doesn't run infinitely, because it only prints "stuff" once, showing the loop runs once. What is the issue with the while loop?
Reading from System.in is different than reading from a file or other fixed-size source of input. The input doesn't necessarily exist until you create it, and so attempts to read it need to block until the input actually arrives (i.e. you type it). Try typing another line - you'll see the stuff message again; that will allow .hasNext() to return because there is now input.
To have .hasNext() return false the input source needs to be closed. For a command line application you can do this by sending the EOF signal (Ctrl+D on Linux) which tells the process stdin has no more input. That's not generally how you want a program to work, though, so if your intent is to only read one line and then move on, you should in fact be using an if instead of a while as you've tried to do. Later if you need to read more input you'll call .hasNext() again and your program will block there until the user passes more input.
As #user7 mentions your outer while (true) combined with while(input.hasNext()) is redundant. If you want to read only once get rid of the while (true) and use if (input.hasNext()). Otherwise if you want to read forever just combine the two loops:
while (input.hasNext()) {
cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
for (int i = 0; i < cmdSplit.length; i++) System.out.println(cmdSplit[i]);
} // Loop will terminate once stdin is closed, e.g. by the user sending EOF.
Yes , your code won't go to the for loop because the Scanner.hasNext() will always listen to the console for inputs.
You have to break the loop in order to come out and go to the for loop.
Scanner input = new Scanner(System.in).useDelimiter("\n");
String[] cmdSplit = null;
while (true) {
while (input.hasNext()) {
cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
break;
}
for (String element : cmdSplit) {
System.out.println(element);
}
}
The reason it is printing "stuff" only one time is because the hasNext() returned false.
Let me explain what I have observed.
To get "stuff" printed indefinately the assignment has to be removed. meaning once you assigned the input the scanner does not have any more token
The java.util.Scanner.hasNext() method Returns true if this scanner has another token in its input.
This will print indefinitely
while (input.hasNext()) {
// cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
}

How input was taken just using object of Scanner class?

public class Two {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int c=0;
while(sc.hasNext())System.out.println(++c+" "+sc.nextLine());
}
}
I came across this code and i want to confirm that by taking input directly without using object of any datatype all we are doing is taking input and displaying it and we are not storing it anywhere?
and also how is the condition inside while loop is true for the first time? As we have not given any input yet.
Sure, your code doesn't store sc.nextLine() , so this value will be discarded past the System.out.println instruction.
Also for hasNext() :
This method may block while waiting for input to scan.
so the condition will be met once the stream begins to provide input, and the method will block waiting for this to happen or an Exception to happen (e.g : if the Scanner gets closed ).
As long as nothing of those things happen, hasNext() method doesn't return, so the condition in while is still not evaluated, so the loop is blocked there .
Let's go through your code:
Scanner sc = new Scanner(System.in)
The java.util.Scanner.Scanner(InputStream) constructor is called, and you have an object sc of type Scanner which reads from System.in.
int c = 0;
You now have a primitive c of primitive type int.
while(sc.hasNext()) { ... }
The while loop evaluates sc.hasNext(), which is true. As per the documentation, sc.hasNext() returns true if and only if the input has another token in it. In your case, this means that the InputStream is open.
{... System.out.println(++c + " " + sc.nextLine()); ...}
sc.nextLine() is the problem. Assuming you have not changed System.in, the console/terminal will block the loop (i.e. hold the loop paused) until you give it an input (type in some text and hit [ENTER]).
So, overall:
Scanner::hasNext() will return true if and only if it is possible to get more input (if you are using System.in, this will always be true until you close the scanner).
If you are printing the input directly, you will not be storing any references to it, and no memory will be allocated for it (unless Scanner.nextLine() stores it somewhere).

Java Program for Word Extraction Not Terminating

The words get extracted and displayed but the program doesn't terminate.
import java.io.*;
import java.util.*;
public class Exp2
{
public static void main(String args[]) throws IOException
{
Scanner obj=new Scanner(System.in);
System.out.println("Enter sentence");
while(obj.hasNext())
{
String str1=obj.next();
System.out.println(str1);
}
}
}
Scanner.next blocks on IO to get data from standard input and hence it doesn't terminate. You need to do something like below to come out of loop:
String str1 = obj.next();
if (str1.equalsIgnoreCase("exit"))
break;//break from while loop when user types exit
This means when you will enter exit (see that you could even give Exit as it would do a case insensitive match of exit), it will terminate your program gracefully by coming out of the loop.
Scanner#next() with Scanner reading from a console becomes a blocking I/O call. That's why the loop would never terminate unless you explicitly break out of it. Something like
while(obj.hasNext())
{
String str1=obj.next();
System.out.println(str1);
if ("quit".equalsIgnoreCase(str1)) {
break;
}
}
Use "quit" or "/quit" or "/q" if you like to break out of the loop as shown in my answer.
You need to understand that reading from a console blocks indefinitely because you can always type something at the prompt and that's what the program then waits for.
Standard input stream i.e. System.in does not behave like a file stream because there is no End of File EOF marker to let the Scanner know that no more data is available.

while (scanner.hasNext()) loop not working twice? Java

I have made a program which is like a vending machine!
My code is similar to:
public static void main (String [] args) {
Scanner sc = new Scanner (System.in);
while(sc.hasNext()) {
String string = sc.next();
sum = generateSum(sum)
.....
}
}
public static int generateSum(int sum) {
Scanner sc = new Scanner (System.in);
while (sc.hasNext()) {
....
}
return sum;
}
Sorry for simplifying my code, but the normal one is very long! However, the problem is that I use while (sc.hasNext()) loop twice. Basically I want to continue my main method until the input from the user is TERMINATE, but my program terminates after running once.
I figured that if I take out my generateSum method, then the loop in my main method works fine so i guess it has to be something to do with have the while (sc.hasNext()) loop twice.
Any ideas how I can fix the problem?
The hasNext() method is going to block until you hit the end of file marker on System.in because it doesn't know if there's more input until it reads a full buffers worth or hits end of file (which you can signal with Control-Z on windows and Control-D on unix). At that point System.in is at the EOF mark and there's no way to re-open it from your code.
If you need to process multiple streams of data from System.in you are going to have to use some sort of sentinel value (such as the word END) to mark the end of one input stream and the beginning of another.
I'm quite sure that if you consume the input being scanned with sc.next() the state changes and hasNext() returns accordingly.The problem may be there.
The hasNext() method can be called as much as you want. But if in the inner loop you are calling the next() method, then that can eat the values from your outer loop.
So the inner loop most probably breaks after hasNext() is false and thus the outer loop also finishes.

Why does hasNextLine() never end?

Sorry if this sounds too simple. I'm very new to Java.
Here is some simple code I was using to examine hasNextLine(). When I run it, I can't make it stop. I thought if you didn't write any input and pressed Enter, you would escape the while loop.
Can someone explain to me how hasNextLine() works in this situation?
import java.util.*;
public class StringRaw {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextLine()) {
String str = sc.nextLine();
}
System.out.print("YOU'VE GOT THROUGH");
}
}
When reading from System.in, you are reading from the keyboard, by default, and that is an infinite input stream... it has as many lines as the user cares to type. I think sending the control sequence for EOF might work, such as CTL-Z (or is it CTL-D?).
Looking at my good-ol' ASCII chart... CTL-C is an ETX and CTL-D is an EOT; either of those should work to terminate a text stream. CTL-Z is a SUB which should not work (but it might, since controls are historically interpreted highly subjectively).
CTRL-D is the end of character or byte stream for UNIX/Linux and CTRL-Z is the end of character or byte stream for Windows (a historical artifact from the earliest days of Microsoft DOS).
With the question code as written, an empty line won't exit the loop because hasNextLine() won't evaluate to false. It will have a line terminator in the input byte stream.
System.in is a byte stream from standard input, normally the console. Ending the byte stream will therefore stop the loop. Although nextLine() doesn't block waiting for input, hasNextLine() does. The only way the code terminates, as designed, is with CTRL-Z in Windows or CTRL-D in UNIX/Linux, which ends the byte stream, causes hasNextLine() not to block waiting for input and to return a boolean false which terminates the while loop.
If you want it to terminate with an empty line input you can check for non-empty lines as part of the loop continuation condition. The following code demonstrates how to change the basic question design that uses hasNextLine() and nextLine() to one that terminates if it gets an empty line or an end of input character (i.e. CTRL-Z in Windows or CTRL-D in UNIX/Linux). The additional code in the while condition uses a feature of assignment operators wherein they can be evaluated like an expression to return the value that was assigned. Since it is a String object, the String.equals() method can be used with the evaluation.
Other additional code just adds some printed output to make what is going on obvious.
// HasNextLineEndDemo.java
import java.util.*;
public class HasNextLineEndDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// this code is a bit gee-whiz
// the assignment expression gets assigned sc.nextLine()
// only if there is one because of the &&
// if hasNextLine() is false, everything after the &&
// gets ignored
// in addition, the assignment operator itself, if
// executed, returns, just like a method return,
// whatever was assigned to str which,
// as a String object, can be tested to see if it is empty
// using the String.equals() method
int i = 1; // input line counter
String str = " "; // have to seed this to other than ""
System.out.printf("Input line %d: ", i); // prompt user
while (sc.hasNextLine() && !(str = sc.nextLine()).equals("")) {
System.out.printf("Line %d: ", i);
System.out.println("'" + str + "'");
System.out.printf("Input line %d: ", ++i);
} // end while
System.out.println("\nYOU'VE GOT THROUGH");
} // end main
} // end class HasNextLineEndDemo
Hit Ctrl + D to terminate input from stdin. (Windows: Ctrl + Z) or provide input from a command:
echo -e "abc\ndef" | java Program
I had a similar problem with a socket input stream. Most solutions I found would still block the execution. It turns out there is a not-blocking check you can do with InputStream.available().
So in this case the following should work:
int x = System.in.available();
if (x!=0) {
//Your code
}
As per my understanding , if you take an example of result set object from JDBC or any iterator then in these cases you have a finite set of things and the iterators each time check whether end of the set has been reached.
However in the above case , their is no way of knowing the end of user input i.e. hasNextLine() has no way of knowing when user wants to terminate, and hence it goes on infinitely.
Best way is to put additional condition on the for loop that checks for some condition inside for loop that fails in the future.
In the above post #Jim 's answer illustrates this.
In fact using hasNextLine() as loop terminator for console input should be discouraged because it will never return false.

Categories

Resources