Scanner continuous loop - java

Why isn't my inputScanner blocking after the first input? It goes into a continous loop. Ignore other details of this code.
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in);
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
}
inputScanner.close();
} while (!finished);
}
}
EDIT: On a previous post which was related to this, it was mentioned that "So if you are going use System.in later don't close it (if it is closed, we can't reopen it and read any data from it, hence exception)". Why is this happening?

Why isn't my inputScanner blocking after the first input?
Because you're creating a new Scanner each time you enter the loop, so it's not the same object on 1st iteration than in 2nd and further iterations
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in); //Here you're making a new instance of inputScanner each time you come to this line after the do-while loop ends.
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
}
inputScanner.close();
} while (!finished);
}
}
If you want it to be "blocked" or "closed", then move this line before the do { line.
Scanner inputScanner = new Scanner(System.in);
For your second question:
So if you are going use System.in later don't close it (if it is
closed, we can't reopen it and read any data from it, hence exception)
From Oracle's docs:
"Attempting to perform search operations after a scanner has been
closed will result in an IllegalStateException"
It's like trying to make a dead person to do something, it would be like a zombie! (And Java hates zombies!) D:
But you're not getting that IllegalStateException because as I said on the answer for your 1st question, you're making a new object each time you go into the do-while loop.
Edit
Why can't you reopen it? Also from Oracle's docs:
When a Scanner is closed, it will close its input source if the source
implements the Closeable interface.
Thus inputScanner.close() closes System.in.
And because of the general contract for OutputStream's close (with the help of this answer):
public void close() throws IOException --> Closes this input stream and releases any system resources associated with this stream. The general contract of close is that it closes the input stream. A closed stream cannot perform input operations and cannot be reopened.

If you take a look at documentation of Scanners methods like hasNext(String) or hasNextDouble you will see that it
Throws:
IllegalStateException - if this scanner is closed
(emphasis mine)
So to throw IllegalStateException you first need to close Scanner, not stream from which it is reading data.
So lets take a look at this example:
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
sc.close();
System.out.println("type something:");
System.out.println(sc.hasNext());// throws java.lang.IllegalStateException: Scanner closed
Last line throws IllegalStateException because you are invoking hasNext method on closed scanner (so we know that after invoking sc.close() stream from which it reads must be also closed so we can safely assume that there are no more elements to read, or since stream was closed we may not be allowed to read it).
Now if we don't close scanner but close System.in we will still be able to use this instance of scanner without getting exceptions. So lets simply change sc.close(); to System.in.close() (I will skip exceptions handling for simplicity):
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
System.in.close();
System.out.println("type something:");
System.out.println(sc.hasNext());// false
As you can see there is no exception here because it wasn't scanner which was closed, but stream which scanner which was being read.
Why closing System.in doesn't cause scanner to throw exception?
I suspect that decision to not throw exception here was made with assumption that exception symbolize problem with code. If programmer allowed scanner to being closed he should also make sure that this particular closed instance of scanner will not be used anywhere.
Now returning false instead of throwing exception is normal reaction where there is no more elements to read. So if stream which scanner was reading was closed naturally (like when we read text file and read its last line so there is nothing more to read) scanner handles this situation like something normal (so there is no need to point that this is some exceptional situation).
Now in your loop you are kind of combining these two scenarios. Your code can be simplified to something like:
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
System.in.close();
sc = new Scanner(System.in);//IMPORTANT
System.out.println("type something:");
System.out.println(sc.hasNext());// false
As you see in line
sc = new Scanner(System.in);//IMPORTANT
you are creating new instance of scanner which wasn't closed yet, so its hasXYZ methods always returns false because System.in can't provide no more values.
Additional trap
One problem which I didn't mentioned earlier is fact that in case of wrong input, which is neither "exit" nor double if you are are not consuming that invalid cached value from scanner by using any of nextXZY methods like hasNext("exit") or hasNextDouble will be still based on that invalid data, like:
Scanner sc = new Scanner("foo 1");
System.out.println(sc.hasNextInt());//false because `foo` is not integer
System.out.println(sc.hasNextInt());//also false because we are still
//reading `foo` which is not integer
String str = sc.next();//lets read (sonsume) foo
System.out.println(sc.hasNextInt());//true since 1 is integer
Solution
Simplest solution to such problem is creating only one instance of Scanner which will handle System.in and reuse it in your entire application. Then at the end of your application you can decide to close your scanner or System.in.
So your code can look like:
boolean finished;
Scanner inputScanner = new Scanner(System.in);
do {
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
inputScanner.next();// lets not forget to consume from scanner cached
// invalid data which is neither double or "exit"
}
} while (!finished);
inputScanner.close();

Related

Java: how to reject incorrect input and wait for proper input using Scanner

This is the basic setup for a little console-based quiz game. The answers are numbered. I want the player to give the answer number. If the input is not a number, then my program should give a warning, and wait for proper input.
Instead, what I get (after inserting something that is not a number) is an infinite loop of asking the question and presenting the answers again.
public static void main(String[] args) {
boolean quizActive = true;
while(quizActive) {
presentQuestion();
presentAnswers();
Scanner s = new Scanner(System.in);
if (s.hasNext()) {
String choice = s.next();
if (!NumberUtils.isNumber(choice)) {
presentText("Please insert the answer number.");
} else {
System.out.println("You made a choice!");
checkAnswer(choice);
quizActive = false;
}
s.close();
}
}
}
What am I doing wrong here?
If you do not want to question and answers be presented each time move presentQuestion() and presentAnswers() outside the loop.
But main problem is that you closing Scanner.
Remove s.close(); and move Scanner s = new Scanner(System.in); outside of the loop.
I really don't get the point in using scanner for acquiring user input.
The scanner class is perfect to process structured input from a flat file with known structure like an CSV.
But user input need to deal with all the human imperfection. After all the only advantage you get is not needing to call Integer.parseInt() your yourself at the cost to deal with the not cleared input when scanne.nextInt() fails...
So why not using InputStreamReader aside with a loop suggested by others?
Here an Example :
public class Application {
public static void main(String [] args) {
System.out.println("Please insert the answer number. ");
while (true) {
try {
Scanner in = new Scanner(System.in);
int choice = in.nextInt();
System.out.println("You made a choice!");
checkAnswer(choice);
break;
} catch (Exception e) {
System.out.println("Invalid Number, Please insert the answer number ");
}
}
}
}
You started your Quiz in a loop which is regulated by your quizActive boolean. That means that your methods presentQuestion() and presentAnswers() get called every time the loop starts again.
If you don't input a number but a character for example, your program will run the presentText("Please insert the answer number.") and start the loop again. As it starts the loop again, it will call the methods presentQuestion() and presentAnswers().
To stop that, you can do another loop around the input-sequence. Also your Scanner s = new Scanner(System.in) should be outside the loop. And you shouldn't close your Scanner right after the first input and then open it again!
if you want a code example, please tell me :)

Java Scanner no line found, and then Scanner closed error?

I have Java code that asks for user input and then stores this data in a string variable. The below function is part of a class called 'number' and is called in the main function.
public static void setVal(int i){
Scanner readIn = new Scanner(System.in);
//while (readIn.hasNextLine()){
str = readIn.nextLine();
numCheck = false;
if (i == 1){
while (!numCheck){
if (str.contains(" ")){
System.out.println("Please input a single item.");
str = readIn.nextLine();
}
else if (!isNumeric(str)){
System.out.println("Please input a valid number.");
str = readIn.nextLine();
}
else {
numCheck = true;
value = Double.parseDouble(str);
readIn.close();
}
}
readIn.close();
}
else if (i == 2){
while (!numCheck){
if (str.contains(" ")){
System.out.println("Please input a single item.");
str = readIn.nextLine();
}
else if (!isNumeric(str)){
System.out.println("Please input a valid number.");
str = readIn.nextLine();
}
else {
numCheck = true;
secondV = Double.parseDouble(str);
readIn.close();
}
}
readIn.close();
}
else {
System.out.println("An error has occurred.");
}
// }
readIn.close();
}
Part of the main function looks like this:
number input = new number();
for (int i = 1; i <= 2; i++){
input.setVal(i);
System.out.println("Now please input a second value for computing with the first.");
input.setVal(i);
}
I use the same function twice but handing it a different argument to distinguish assignment of the input to a different variable but when it runs a second time it throws a no line found error.
Applying some other advice you can see commented out I have added a 'hasNextLine()' check to check if the line exists before executing the code but this ends up at a 'Scanner closed' error even though I invoke a new instance of Scanner every time the function runs. I have also closed the scanner appropriately to ensure minimisation of errors.
I have no idea what's going wrong as I can create a Scanner in the main function and call '.nextLine()' as many times as requried without an error but when called again through a class method, I receive these errors.
Any help is appreciated, thanks in advance.
Scanner.close() documentation states that
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. If this scanner is already closed then
invoking this method will have no effect.
On closing scanner, you are also closing System.in input stream, so when you reopen the scanner it will not find any open input stream.
Refer : java.util.NoSuchElementException - Scanner reading user input
Better pass scanner object from outside method as argument and then close it in calling method only when you are done with it.
Just to point out, is your String object str Static?
If not then you can't use it in your static method. Better you remove the static from method declaration.
You have to close the scanner when everything is done.
You have closed the scanner inout stream readIn.close(); twice.
You are closing the stream before picking line by line from the file. So you have to close it once after all the instances that use readIn is finished.

How to properly close a Scanner class inside a method?

I have this code that calls to a method in order to check if a number is a certain length, and if not, a new number should be reintroduced by the user.
Problem here is, I can't find the proper way to close a Scanner class in order to prevent a resource leak.
Here's the code so far.
public static void setIdentification(Person p, int dni) {
Scanner input = new Scanner (System.in);
String lengthChecker = Integer.toString(dni);
if (lengthChecker.length() < 1 || lengthChecker.length() > 8) {
int dni1;
do{
System.out.println("The ID number isn't valid. Please, introduce a valid number: ");
dni1 = input.nextInt();
lengthChecker = Integer.toString(dni1);
} while (lengthChecker.length() > 8 || lengthChecker.length() < 1 );
p.dni = dni1;
} else {
p.dni = dni;
}
}
public static void main(String[] args) {
Scanner input1 = new Scanner (System.in);
int dni = input1.nextInt();
Person person1 = new Person();
setIdentification(person1, dni);
}
I have tried to set the input.close(); in a number of different locations but I always end up getting a run-time error.
There's probably a million ways to optimize this code but right now I'm just really curious as to how to get those Scanners closed.
#Jules is correct. In this case, it is neither necessary or advisable to close the Scanner.
But assuming that you did, then the recommended way to do it is this:
try (Scanner input1 = new Scanner (System.in)) {
int dni = input1.nextInt();
Person person1 = new Person();
setIdentification(input1, person1, dni);
}
... noting that you must change your setIdentification method so that it doesn't attempt to open its own scanner. Creating multiple scanners for the same input stream is a mistake. Indeed, it is the mistake in your code.
This works for Java 7 and later. (Under most circumstances, you should not be writing new code for older versions of Java. Android is an exception, because support for Java 7 extensions has only recently become available in Android toolchains.
So why can't you open and close multiple scanners on the same stream? Two reasons:
When you close a Scanner, you automatically close the underlying stream. That means if you then attempt to open / use another scanner on the stream, it will fail when you attempt to read from the closed stream. Streams cannot be reopened.
Even if you don't close the scanner / stream, creating a second scanner on a stream is likely to lead to trouble. A scanner has to read ahead in order to figure out where the token boundaries are. It then keeps any read-ahead characters in an internal buffer. Each scanner has its own buffer. So if you have two or more scanners for the same stream, and interleave their use, one scanner is liable to "grab" characters that the other scanner needs.
Closing your scanner will close the input stream it was created using. In your case, this is System.in. This stream is a special case: it is opened by the environment before your program starts running, and therefore should not usually be closed by your program.
In this case, it's fine to not close your Scanner. Just let the garbage collector deal with it.

Creating Two Scanners In Different Class

I am currently using two different scanners in my project in two separate classes: both take in user input that do different things. Calling the first scanner works normally, but when I try to call the second scanner, even after I've closed the first, it registers the input as null.
Class 1
Scanner scan = new Scanner(System.in);
public void foobar(){
System.out.println("Enter data: ");
String foo = scan.next();
scan.close();
class2.function(foo);
}
Class 2
Scanner scan1 = new Scanner(System.in);
public void foobar1(String foo){
System.out.println("Enter more data: ");
String fooo = scan1.Next();
//Automatically prints null here and closes program
}
Am I supposed to only use one Scanner somehow? Or do I use the Scanner class in some other manner? Thanks!
scan.close(); also closes System.in so that no more data can be read from the stream. So when you start reading from scan1, System.in will no longer return any data.
Therefore, don't close any Scanner instance until you're done with all the scanning if you're using the same input stream for all the instances.
Look at the docs of Scanner#close() for more info.
Closes this scanner. 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 if you look at the docs of System.in, you can see that it does implement the Closeable interface.
Thus the InputStream#close() is called and that closes the InputStream leaving you without a input stream to read data from.
Closes this input stream and releases any system resources associated with the stream.
No need to create two scanners, You can use same Scanner for both as once scan is closed Stream System.in also get closed.
like:
Scanner scan = new Scanner(System.in);
public void foobar(){
System.out.println("Enter data: ");
String foo = scan.next();
class2.function(foo,scan);
}
where:
public void function(String foo,Scanner scan1){
System.out.println("Enter more data: ");
String fooo = scan1.next();
System.out.println(fooo);
}
but still if you need to create two scanners use scan.reset(); instead of scan.close(); in class1

Java Scanner won't "finish" reading input

I've been having trouble using java's Scanner class. I can get it to read my input just fine, but the problem is when I want to output something. Given multiple lines of input, I want to print just ONE line when all the input has been read completely. Here's the code I use for reading input:
public static void main(String[] args){
Scanner scanner = new Scanner(System.in); //scanner reads block of input
while(scanner.hasNextLine()){
//body of loop goes here
String s = scanner.nextLine();
Scanner ls = new Scanner(s); //scanner to parse a line of input
while(ls.hasNext()){
//body of nested loop goes here
ls.next();
}
}
System.out.println("Fin");
}
Even when all lines of input have been read, the program doesn't reach the System.out.println message. (Note that the message can't go anywhere else or it will output as many times as the loop is run). How do I fix this? Any help would be greatly appreciated.
As I can see in your outer while loop you have used
scanner.hasNextLine();
method. This method gets blocked if it has to wait for the input. Also you have
Scanner scanner = new Scanner(System.in);
statement. So the system.in will be waiting for input all the time, hence the hasNextLine() method has to wait for the input.
That is why the control gets stuck in the loop and can't proceed further.
To fix it you can first store input in a string variable and the call the scanner constructor on it.
You are reading from an Infinite stream in this case. hasNextLine() will keep returning true if there is another line in the input of this scanner. As its a System.in, it will keep reading from the Keyboard, unless you terminate it or tell the stream to stop.
Press "ctrl+Z" in the end, you will see that it works.
Edit : You could do something like this...
Scanner scanner = new Scanner(System.in); //scanner reads block of input
int BLOCK_SIZE =3,count=1;
while(scanner.hasNextLine()){
//body of loop goes here
String s = scanner.nextLine();
Scanner ls = new Scanner(s); //scanner to parse a line of input
while(ls.hasNext()){
//body of nested loop goes here
ls.next();
}
if(count++==BLOCK_SIZE)
{
break;
}
}
System.out.println("Fin");
}
You need to tell the program that there is going to be no more input. This is done by appending an EOF character. This can be done manually on Linux by pressing Ctrl-D in the console. I think on Windows you can press Ctrl-Z. The stream will be automatically closed if you are piping input from one program to another.
eg.
cat filename | java MyJavaProgram
The magic of
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()){
Is that there will never stop being input from System (unless you close the input with ctrl+d (for macs)).
To stop the loop, I suggest throw something more in the condition than just hasNextLine().
E.g.
Scanner scanner = new Scanner(System.in); //scanner reads block of input
int BLOCK_SIZE =3,count=1;
while(scanner.hasNextLine() && count++ <= BLOCK_SIZE){ //<- Use count here.
//body of loop goes here
String s = scanner.nextLine();
Scanner ls = new Scanner(s); //scanner to parse a line of input
while(ls.hasNext()){
//body of nested loop goes here
ls.next();
}
}
System.out.println("Fin");
}

Categories

Resources