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.
Related
I have a command-line game and am testing with JUnit, this is the test:
#Test
public void testBattle() throws IOException{
String input = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
"right\nnormal attack\nnormal attack\nquit\n";
provideInput(input);
actual = new File("src/main/testFiles/testBattle.txt");
expected = new File("src/main/testFiles/testBattleExpected.txt");
PrintStream o = new PrintStream(actual);
System.setOut(o);
ui.gameLoop();
assertTrue(FileUtils.contentEqualsIgnoreEOL(actual, expected, null));
}
And this is the provide input method:
private void provideInput(String data) {
String newdata = data.trim();
testIn = new ByteArrayInputStream(newdata.getBytes());
System.setIn(testIn);
}
I'm doing scanner nextline so:
command = input.nextLine().toLowerCase().trim();
where "input" here represents the scanner object
but I'm still getting this error, specifically when the first "normal attack" is passed into System.in
java.util.NoSuchElementException: No line found
on that line above. I thought nextline ignored whitespace? If not did I format my string wrong to not include it?
EDIT:
From the first few lines of UI.gameLoop() I only initialize the scanner once.
public void gameLoop() throws IOException, JsonSyntaxException {
input = new Scanner(System.in);
engine = new GameEngine(path);
I thought nextline ignored whitespace?
Nope. According to the javadocs, it reads past the next end-of-line sequence (or to EOF), and then returns everything up to but not including the end-of-line sequence.
If you are getting
java.util.NoSuchElementException: No line found
that means that the Scanner has already reached the end of the input stream, or (maybe) the Scanner is trying to read from an input stream that was prematurely closed somewhere else in your code.
We can make guesses about what the real problem is, but without seeing >>your<< minimal reproducible example, we can't take this much further.
Actually, I just spotted a clue:
... I am testing with JUnit ...
This is possibly at the root of your problems. A JVM can only "read to the end of System.in" once in its lifetime. If you have two or more JUnit tests that need to do this, it is going to be difficult, unless you can find a way to "mock" the System.in variable.
It may be simpler to reorganize your code so that you take the input from some stream that is passed to your game code as a parameter. By reorganizing you can make it easier to write unit tests.
There's not a lot to go on, but I'm guessing you're creating multiple Scanners, one for each time you want to read a line. This usually works ok interactively since humans are slow typers, but fails when each Scanner's readahead ends up consuming multiple lines.
You can see the difference in this MCVE:
import java.util.*;
import java.io.*;
class Foo {
public static void main(String[] args) throws Exception {
String newdata = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
"right\nnormal attack\nnormal attack\nquit\n".trim();
ByteArrayInputStream testIn = new ByteArrayInputStream(newdata.getBytes());
System.setIn(testIn);
boolean includeBug = Boolean.valueOf(args[0]);
if (includeBug) {
for(int i=0; i<8; i++) {
Scanner input = new Scanner(System.in);
System.out.println("Read: " + input.nextLine());
}
} else {
Scanner input = new Scanner(System.in);
for(int i=0; i<8; i++) {
System.out.println("Read: " + input.nextLine());
}
}
}
}
When includeBug is true, it creates a new Scanner for each line and crashes like you say. If it's false, it creates a single Scanner and works correctly:
$ javac Foo.java
$ java Foo true
Read: go forward
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1540)
at Foo.main(Foo.java:17)
$ java Foo false
Read: go forward
Read: go left
Read: take Pointy Stick
Read: go backward
(etc)
Are you checking if it has a next line? With Scanners, you usually either have to handle the exception (not really something I'd prefer) or you have to use the hasNextLine() method to avoid the exception.
while (input.hasNextLine()) {
command = input.nextLine().toLowerCase().trim();
}
int selection;
while (true) {
selection = printing();
if (selection == 4) {
id = starting();
if (id < 1 || id > 10) {
if (id == -20150901) {
System.out.println("Exit code entered");
break;
}
id = incorrectId(id);
}
}
}
public static int printing(){
Scanner sc = new Scanner(System.in);
System.out.print("Main menu\n1: check balance\n2: withdraw\n3: deposit\n4: exit\nEnter a choice: ");
System.out.print("Enter a choice: ");
int selection = sc.nextInt();
return selection;
}
This is part of my java code.
The NoElementException occured in the third line.
If the whole code is needed, I will copy and paste here and explain what it is about.
How can I solve this exception?
I want to get keyboard input every time the loop starts.
Thank you.
Your code creates a new Scanner wrapping System.in each time you call printing(). This is incorrect. Instead, your application should create exactly one Scanner wrapping System.in, save it somewhere, and reuse it for each printing() call and all other places where you are reading from System.in.
The problem with creating multiple Scanner objects is that that the hashNext* and next* methods can cause characters to be "read ahead" characters into the Scanner's buffer. So the first printing() could "consume" all characters.
Now this may not be the actual cause of your problem. Other possible causes could be:
standard input could be empty, or
you may be (directly or indirectly) closing the System.in in some other part of the code.
However, the problem I identified is a bug that would cause application failures in other contexts ... and it is advisable to understand and fix it.
I am very new to Java but am working through the book Java: How to program (9th ed.) and have reached an example where for the life of me I cannot figure out what the problem is.
Here is a (slightly) augmented version of the source code example in the textbook:
import java.util.Scanner;
public class Addition {
public static void main(String[] args) {
// creates a scanner to obtain input from a command window
Scanner input = new Scanner(System.in);
int number1; // first number to add
int number2; // second number to add
int sum; // sum of 1 & 2
System.out.print("Enter First Integer: "); // prompt
number1 = input.nextInt(); // reads first number inputted by user
System.out.print("Enter Second Integer: "); // prompt 2
number2 = input.nextInt(); // reads second number from user
sum = number1 + number2; // addition takes place, then stores the total of the two numbers in sum
System.out.printf( "Sum is %d\n", sum ); // displays the sum on screen
} // end method main
} // end class Addition
I am getting the 'NoSuchElementException' error:
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:838)
at java.util.Scanner.next(Scanner.java:1461)
at java.util.Scanner.nextInt(Scanner.java:2091)
at java.util.Scanner.nextInt(Scanner.java:2050)
at Addition.main(Addition.java:16)
Enter First Integer:
I understand that this is probably due to something in the source code that is incompatible with the Scanner class from java.util, but I really can't get any further than this in terms of deducing what the problem is.
NoSuchElementException Thrown by the nextElement method of an Enumeration to indicate that there are no more elements in the enumeration.
http://docs.oracle.com/javase/7/docs/api/java/util/NoSuchElementException.html
How about this :
if(input.hasNextInt() )
number1 = input.nextInt(); // if there is another number
else
number1 = 0; // nothing added in the input
You should use hasNextInt() before assigning value to variable.
NoSuchElementException will be thrown if no more tokens are available. This is caused by invoking nextInt() without checking if there's any integer available. To prevent it from happening, you may consider using hasNextInt() to check if any more tokens are available.
I faced this Error with nextDouble(), when I input numbers such as 5.3, 23.8 ... I think that was from my PC depending on computer settings that use Arabic (23,33 instead 23.33), I fixed it with add:
Scanner scanner = new Scanner(System.in).useLocale(Locale.US);
You must add input.close() at the end...
This error is mostly occur in case of 0nline IDE's on which you are testing your code. It is not configured properly, as if you run the same code on any other IDE/Notepad it works properly because the online IDE is not designed such a way that it will adjust the input code of your format, So you have to take input as the Online IDE supports.
If I may, I solved this issue today by realizing that I had multiple functions that used an instance of a Scanner, each. So basically, try refactoring so that you have only one instance opened and then closed in the end - this should work.
For anyone using gradle's application plugin, you must wire it to the standard console in build.gradle(.kts) otherwise it will keep throwing the NoSuchElementException error if you try to use scanner.
For groovy:
run {
standardInput = System.in}
For gradle kotlin dsl:
tasks.withType<JavaExec>() {
standardInput = System.`in`}
Integer#nextInt throws NoSuchElementException - if input is exhausted
You should check if there is a next line with Integer#hasNextLine
if(sc.hasNextLine()){
number1=sc.nextInt();
}
I added a single static scanner (sc) at the top of my class and closed it (sc.close()) when coming out of the whole class wherever I used return statements. Again that's one instance of scanner as suggested by another answer, which should be static.
package com.example.com;
import java.util.Scanner;
public class someClass {
static Scanner sc = new Scanner(System.in);
//Whole world of methods using same sc.
//sc.close()); return;
}
Other than that you can add #SuppressWarnings("resource") on the top of the troubling method to make the warning go away. But be careful about resource leaks.
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();
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