Close a Scanner linked to System.in - java

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.

Related

Usage of SuppressWarnings in java

I am working with Files in java and my IDE is VS-Code.The problem I am facing that it is showing the following as warnings alongwith a bunch of others-
Resource leak: 'sc' is never closed
Resource leak: 'scan' is never closed
where "sc" is defined as -
Scanner sc = new Scanner(System.in);
and "scan" as -
File fobj=new File("Marks.txt");
Scanner scan = new Scanner(fobj);
I am asking that Using #SuppressWarnings("resources") only blocks warning from Scanner object sc.Is there any way to block all of these open resources warnings which can be defined at the beginning of the Java file because I have to include #SuppressWarnings("resources") in every class I write.
You can add suppressions to the containing class:
#SuppressWarnings("resources")
class YourClass {
// ...
}
and this will suppress all resources warnings in the class.
This isn't such a great idea, though, because it will also suppress warnings about resources you do want to close, like scan.
I would say you've got a deeper problem if you're worried about adding suppressions in all the places where the warnings occur, because this implies you've got warnings in a lot of places.
In terms of suppressing the warning just on the Scanner sc = new Scanner(System.in);: you should only be creating a single scanner on a stream, and, as such, you should only need to add the suppression in one place.
If you're creating multiple scanners on System.in, you may get unexpected results from them, consider each scanner may consume part of the input stream. A better approach is to construct one scanner (on a given stream), and pass it around.
For Scanner scan, a better approach than suppressing the warning would be just to close the stream, so there is no warning to suppress. Try-with-resources guarantees this:
File fobj=new File("Marks.txt");
try (Scanner scan = new Scanner(fobj)) {
// ... Do stuff with scan.
}
// And now it's guaranteed to be closed.
Note that you can use try-with-resources around new Scanner(System.in), and it is guaranteed to be closed - but you shouldn't. Closing the Scanner closes the underlying stream - System.in.
You should only close streams that your code opened directly - your code didn't open System.in, the JVM did. System.in can't be reopened once closed, so you could accidentally break other parts of your code which assumed it would be open.
It's gross that you have to consider System.in and "other" streams separately - the "helpful" closing of child streams in Scanner (etc) is behavior that predates the try-with-resources syntax, so it's just something Java is stuck with.

Java Scanner with string input should be closed?

Sonar complains that the Scanner should always be closed, is it right?
Scanner scanner = new Scanner("simple string")
This scanner is not scanning from file etc. Why should it be closed?
By calling new Scanner("string") it creates a StringReader which creates a character stream. So you have to close it.
See the OpenJDK source code
public Scanner(String source) {
this(new StringReader(source), WHITESPACE_PATTERN);
}
As specified in Sonar doc,
Connections, streams, files, and other classes that implement the
Closeable interface or its super-interface, AutoCloseable, needs to be
closed after use.
And Scanner does implement Closeable interface. Hence it should be closed.
Refer this link.
There is no need to close the Scanner, but it is better to do it in order to release the resources allocated for Scanner to optimize your code and make it faster and efficient.

life and death of an object explanation

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

Can I use both Scanner which uses an InputStream and the inputstream itself at the same in the same program?

I suppose this is the input counterpart of this question which I asked some time back:
Can I use both PrintWriter and BufferedOutputStream on the same outputstream?
Q1) I need to read both String lines and byte [] from the same inputstream. So can I use the scanner wrapper to read lines first and then use the inputstream directly to read byte []? Will it cause any conflict?
Q2) If there are no more references to the scanner object and it gets garbage collected, will it automatically close the connection?
Q3) If the answer to the first question is yes and the answer to the second question is no, once I am done with the reading I only have to call inputstream.close() and not Scanner right? (Because by then I won't have a handle to the scanner object anymore)
For 1), you can always read bytes and convert them to String using the encoding of your choice. I'm pretty sure this is what all "readers" to under the hood.
For 2), no, Scanner class doesn't override the finalize method so I'm pretty sure it doesn't close the handle (and it really shouldn't). The section on finalizers in the Effective Java book has a detailed explanation on this topic.
For 3), closing the Scanner would automatically close the underlying stream. I'm pretty sure this is how almost all I/O classes handle the passed in file/resource handle.
Q1) Yes, the scanner buffers its input so when you come to switch to a different stream some of the bytes you want may have been consumed.
If you can use the Scanner to read bytes, that is a better option.
Q2) The connection will be closed when it is cleaned up.
Q3) You only need to close the input stream as Scanner is a pure Java object (and an input) For Buffered outputs you need to call flush() or close() to ensure unwritten data is sent.

How can I unit test classes that read input in Java?

How is it possible to run tests against a class that reads from System.in for user input?
For example:
private int getUserInput() {
Scanner scanner = new Scanner(System.in);
System.out.print("What's ya input? [1-3]: ");
return scanner.nextInt();
}
I've thought maybe subclassing the main class and overridding getUserInput to feed back scripted answers. Though this won't work if you need to read System.out to decide the input.
I spent a few hours looking up Threads however couldn't figure out how to use them for this either.
Well, you can replace System.in using System.setIn() but I would not favour that approach. Setting global state always makes your tests a bit more fragile and non-transparent.
Instead you should really try to break the dependency, for example by injecting the InputStream that you want to read from into your class through the class' constructor. Once you do that, when you unit test it you can pass in your own InputStream that reads from static data, and in your production code you can inject System.in.
Either put your references to System.in and System.out to variables or to result values of methods that you can override in your test (by other streams, like ByteArrayInput/OutputStream, or (if that is not possible) use System.setOut and System.setIn to replace the default streams, run your test, validate the output and set them back.
You can create Mock objects that imitates user input.

Categories

Resources