I'm writing a game in java, and I have a method that asks user to input the value from Console:
public String getUserInput() {
try (Scanner scan = new Scanner(System.in)) {
String s = scan.nextLine();
return s;
}
}
The thing is I want to invoke this method various number of times depends on external parameters and I never know in advance, will I invoke again or not.
But when I invoke methods like this for the second call - I get
Exception in thread "main" java.util.NoSuchElementException: No line found
Problems:
I dont understand the root cause of this error: I know I can not
reopen the scanner, but here I dont reopen it but I recreate it.
How can I deal with it?
Don't reopen or recreate it. Use one Scanner for the duration of your program.
Closing a Scanner (as in this case, with your try-with-resources block) will close its input, in this case System.in. You don't want to close that, since you can't reopen it.
Related
I'm writing a console application in Java that gets input from the user by
'Scanner' class. I don't want to enter each time that I test my program the input manually in the console, so I want to put all my inputs in a text file and make the Java program read this text file instead of typing again the inputs.
The way I found to do it is changing the line:
Scanner sc = new Scanner(System.in);
to:
Scanner sc = new Scanner(new File(path_to_text_file));
Can you recommend another way that doesn't involve changing the code?
Since you want to have this for testing, the best way would be to write a test for this class. Have a look at JUnit.
In such a test you could provide a different Scanner to you original class, either by using
Scanner sc = new Scanner(new File(path_to_text_file));
or you could use a framework like Mockito in order to fake different user inputs through Scanner and then check whether these inputs produced the correct outputs.
If you absolutely can't change your code, use System.setIn to replace the default input stream with one of your choosing.
Be sure always to change the stream back to the original one once you've finished testing - in doing this, you're mutating global state, so you can leave things in a bad state for the rest of your tests.
InputStream previousIn = System.in;
InputStream replacement = new FileInputStream(path_to_text_file);
System.setIn(replacement);
try {
// ... Do your testing.
} finally {
System.setIn(previousIn);
}
Or, change the design of your code so that you inject the input stream that you depend on. This avoids the mutation of global state, which is a good thing.
To get around the skipping nextLine() issue, and to make the code cleaner, have I a couple of times used the following approach:
private String getInput() {
return new Scanner(System.in).nextLine();
}
This have not been any production code, just small projects, so I haven't cared much if this could give performance issues since I found the approach very convenient. I really like to use this method for all inputs and parse the return value.
To the question - is this a very bad practice? I does not feel good to not close the Scanner, but since the object gets out of reach, have I been thinking that the Scanner object should be garbage collected and therefore also closed. How does the gc handle this?
You must not close it in this case otherwise System.in will be closed too such that you won't be able to get any new input, indeed if you execute this simple code:
Scanner scanner = new Scanner(System.in);
scanner.close();
scanner = new Scanner(System.in);
scanner.nextLine(); // -> Exception here
You will get the next exception:
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1540)
at hello.Application.main(Application.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
The only real issue that I see with your approach is the fact that it can be inefficient if you call this method regularly as you create a new Scanner instance at each call, moreover it could be JDK implementation specific because if you have one implementation of Scanner that implements the method finalize it may close the Scanner which would lead to the error described above.
The Scanner has a finalize() method which will close any native resources when the object is GC'd.
The code below gives me a warning on Eclipse: "resource leak, input is never closed":
Code: 1
import java.util.Scanner;
public class Ex {
public void sum() {
Scanner input = new Scanner(System.in);
}
}
I found that declaring the input variable in the class level does the trick, the warning is gone.
But, is this the right way of fixing this issue? And what is the difference between the second code and the third code? Does code 3 means that I have abandoned the first object?
Code: 2
import java.util.Scanner;
public class Ex {
private Scanner input;
public void sum() {
input = new Scanner(System.in);
}
}
Code: 3
import java.util.Scanner;
public class Ex {
private Scanner input = new Scanner(System.in);
public void sum() {
input = new Scanner(System.in);
}
}
but , is this the right way of fixing this issue - No its not... The input is still not closed, only that Eclipse is not able to detect it anymore... The issue is still present...
That being said, it's not a good idea to close the Standard input System.in too (closing the Scanner object would close the underlying stream too as I understand)... Hence it would be better to leave it like that even though there is a warning...
Yes, since in code 3 you have reinitialized input, you have abandoned the first object.
The presence of a warning is almost always a sign of a problem. But the absence of a warning doesn't mean there is no problem.
The first snippet warns you that you're not closing the Scanner object when you're done with it. The proper fix would be to close it. Not to make your code worse by using a field instead of a local variable, and still not closing the scanner when you're done with it. That will make the warning disappear, but not the problem. Variables should always have the narrowest possible scope.
That said, A Scanner opened with System.in as argument, although it implements Closeable (that's why you have the warning), should in fact not be closed, because that would close the underlying stream: System.in. File or Socket streams must be closed, but System.in should generally not. If you close it, the user won't be able to enter anything anymore to your program.
You are getting the warning because the scanner instance is never closed. Modify the code: 1 as below to eliminate the warning,
public void sum() {
Scanner input = null;
try {
input = new Scanner(System.in);
// do operation
} finally {
input.close();
}
}
Regarding code:2, declare any variable at Object level only when its required. i.e if it needs to be accessed by multiple member functions defined in the class.
To answer your question is this the right way of fixing this issue , and what is the difference between the second code and the third code ? Does code : 3 means that i have abandoned the first object ?
No, Code: 3 is not the right way way to fix the issue. And yes, code:3 creates a new instance of scanner inside the member function "sum" and the reference of the member variable input will point to the newly created scanner instance.
In summary, create a member variable (object level) only when its absolutely required, otherwise create a local variable - this will ensure that the objects get collected much earlier. (i.e. these objects will become eligible for GC when the method execution completes). Also, make sure that, call close() on almost all of the IO classes (stream classes) that we operate on.
Also, Note that if you close System.in, you won't be able to read from it again
I have a program in java, in which I have to get user input, however, I only need to get the user input once, after that, I do not need a scanner anymore. Doing the following:
int userInput = new Scanner(System.in).nextInt();
Gives me a Resource Leak warning, saying that <unassigned closeable value> is never closed.
Is there another way I can use a Scanner only once, and get rid of it afterwards so there's no Resource Leak? Maybe something similar to C#'s using statement.
The equivalent to C#'s using is a try-with-resources. Don't use that, it will close the System.in and you don't want that. Ignore the warning for this particular case. Let the garbage collector claim the Scanner and leave the standard input as is.
I can see the following two options...
Option #1 : Explicitly close the scanner as soon as you read the input once.
Scanner sc = new Scanner(System.in);
int userInput = sc.nextInt();
sc.close();
Option #2 : Use the try-with-resource statement
try(Scanner sc1 = new Scanner(System.in)) {
int userInput1 = sc1.nextInt();
}
The downside of option #2 is that it will close all the resources that exist in try-with-resource statement, which included System.in.
Java has Automatic garbage collection. Automatic garbage collection is the process of looking at heap memory, identifying which objects are in use and which are not, and deleting the unused objects. An in use object, or a referenced object, means that some part of your program still maintains a pointer to that object. An unused object, or unreferenced object, is no longer referenced by any part of your program. So the memory used by an unreferenced object can be reclaimed.
This means you shall not to worry about this type of warnings. Additionally in Eclipse you can use#SuppressWarning to get rid of annoying warnings.
I have a Scanner linked to System.in. Now, after using the Scanner, I should close it, as it is bad coding practice to leave it open. But, if I close the Scanner, I will also be closing System.in! Can anyone tell me how I can close the Scanner without closing System.in (if there is any way).
The simplest thing is to not close Scanner if you don't want to close the underlying stream.
Ideally you should create just one Scanner which you use for the life of the program. In any case, it appears you don't have a good reason to close it.
One option is to wrap your System.in stream in a CloseShieldInputStream that prevents it from being closed. Your reader would then use the CloseShieldInputStream rather than the raw System.in stream.
Here is the API for the class:
http://commons.apache.org/io/apidocs/org/apache/commons/io/input/CloseShieldInputStream.html
Instead of adding shield classes and stuff like that, just put a nice comment and a
#SuppressWarnings("resource")
That's good enough. And I don't seem to see a lot of drawbacks to this approach. Don't forget the comment.
I have vague memories of strange, undiagnosable problems long ago with using the same Scanner of System.in twice, so this is what I use (even though you should probably just use one scanner for the duration of the program):
static String input() {
try {
return new Scanner(System.in).nextLine();
} catch (NoSuchElementException e) {
throw e;
}
}
For some reason this works without warnings, whereas if I don't do the catch-throw, Eclipse will complain Resource leak: '<unassigned Closeable value>' is never closed.
According to the API for InputSteam "The close method of InputStream does nothing.", so since System.in is an instance of InputStream, you don't need to worry about close() being called on it.