Close a Scanner Linked to System.In

Close a Scanner linked to System.in

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

Scanner.close method closes all scanners why?

Why? Because that is how the specification says it should behave; see @Sun's answer for the reference and the text from the spec.

And how can it overcome this?

Don't call close() in a Scanner that wraps System.in. This is just an application of the general principle that a resource should be closed by the same code that opens it. (The JVM opens System.in so you shouldn't close it.)

Alternatively if you must close the Scanner, write or find a InputStream wrapper class that ignores the close() method and then use that to wrap System.in.

By the way, it is a bad idea to instantiate new Scanner(System.in) more than once. The problem is that a Scanner may read any or all type-ahead. If you have two or more of them wrapping the same underlying stream, one Scanner can capture input that a later one needs to read. This can lead to occasional unexpected behavior, and is likely to cause your application to fail if standard input is redirected ... at the shell level.

How to close Scanner opened in a method JAVA

Thanks to Vince, I was able to create a good version of my code.
and this is the answer I needed.


public class Que01 {

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int principle=acceptInt(sc,"Principle");
int roi=acceptInt(sc,"Rate Of Interest");
int years=acceptInt(sc,"Years");
sc.close();
float si=simpleInterest(principle,roi,years);

System.out.println("Simple Interest for given details is : "+si);
}

static int acceptInt(Scanner sc,String s1)
{ System.out.println("Please Enter value for "+s1+" :");

int i= sc.nextInt();
return i;
}
static float simpleInterest(int p,int r, int yr)
{
return p*yr*r/100;
}

}```

What does scanner.close() do?

Yes, it does mean that System.in will be closed. Test case:

import java.util.*;

public class CloseScanner {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
scanner.close();
System.in.read();
}
}

This code terminates with

$ java CloseScanner 
Exception in thread "main" java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:162)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:206)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
at CloseScanner.main(CloseScanner.java:7)

Once closed, you won't be able to use System.in for the rest of your program. The fact that close() is passed through is nice because it means you don't have to maintain a separate reference to the input stream so that you can close it later, for example:

scanner = new Scanner(foo.somethingThatMakesAnInputStream());

You can do that and call .close() on the scanner to close the underlying stream.

In most cases you won't want to close System.in, so you won't want to call .close() in that case.

Close Scanner without closing System.in

You can just ignore close by implementing custom decorator.

public class UnClosableDecorator extends InputStream {

private final InputStream inputStream;

public UnClosableDecorator(InputStream inputStream) {
this.inputStream = inputStream;
}

@Override
public int read() throws IOException {
return inputStream.read();
}

@Override
public int read(byte[] b) throws IOException {
return inputStream.read(b);
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
return inputStream.read(b, off, len);
}

@Override
public long skip(long n) throws IOException {
return inputStream.skip(n);
}

@Override
public int available() throws IOException {
return inputStream.available();
}

@Override
public synchronized void mark(int readlimit) {
inputStream.mark(readlimit);
}

@Override
public synchronized void reset() throws IOException {
inputStream.reset();
}

@Override
public boolean markSupported() {
return inputStream.markSupported();
}

@Override
public void close() throws IOException {
//do nothing
}
}

And use it in main

public static void main(String[] args) throws Exception {
System.setIn(new UnClosableDecorator(System.in));
}

How to close a scanner object when input is taken in a loop?

Closing a Scanner object causes it to also close its associated InputStream or file. If you were to use a Scanner in your input() method to read data from a file instead of from the keyboard, you might use it like this:

String input() {
InputStream is = new FileInputStream(INPUT_FILE_NAME);
Scanner s = new Scanner(is);
String str = s.nextLine();
s.close();
return str;
}

As you see, the Scanner is closed, so that there are no resource leaks. If you didn't close it, the InputStream, which was opened on a file, would remain open. Just closing the Scanner also closes the InputStream on which the Scanner was constructed. So there is no need to close the InputStream too.

The above is equivalent to the following, but the code below is safer as it deals properly with exceptions:

String input() {
try (
InputStream is = new FileInputStream(INPUT_FILE_NAME);
Scanner s = new Scanner(is)
) {
String str = s.nextLine();
return str;
}
}

This is the try-with-resources statement, which you can read about on Oracle's website or a good textbook. It ensures that the InputStream and the Scanner are always closed before the method returns, no matter what happens.

So why shouldn't we do the same with a Scanner that is opened on System.in? That is because System.in is an InputStream that we want to keep open for the whole duration of the program. If we close the Scanner, that would also close System.in and we don't want that. But now that we don't close the Scanner, we don't want to create a new Scanner every time we enter the input() method. We just want to create a single Scanner that lasts the duration of our program. One way to do this is by having it as a field:

public class Validation {
private static Scanner in = new Scanner(System.in);

String input() {
return in.nextLine();
}

...
}

Now the Scanner is created as soon as the JVM loads your class, and remains usable until your program exits.

I am not sure if Eclipse will still complain about a resource leak if you construct your Scanner object as a static field (I don't use Eclipse). Perhaps you can let me know if it does or not.

How to close a scanner without closing the underlying System.in?

Scanner scan = new Scanner(new FilterInputStream(System.in) {
@Override
public void close() throws IOException {
// do nothing here !
}
});

Or , Just ignore close() by implementing custom decorator.

public class UnClosableDecorator extends InputStream {

private final InputStream inputStream;

public UnClosableDecorator(InputStream inputStream) {
this.inputStream = inputStream;
}

@Override
public int read() throws IOException {
return inputStream.read();
}

@Override
public int read(byte[] b) throws IOException {
return inputStream.read(b);
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
return inputStream.read(b, off, len);
}

@Override
public long skip(long n) throws IOException {
return inputStream.skip(n);
}

@Override
public int available() throws IOException {
return inputStream.available();
}

@Override
public synchronized void mark(int readlimit) {
inputStream.mark(readlimit);
}

@Override
public synchronized void reset() throws IOException {
inputStream.reset();
}

@Override
public boolean markSupported() {
return inputStream.markSupported();
}

@Override
public void close() throws IOException {
//do nothing
}
}

And while using in main(),

public static void main(String[] args) throws Exception {
System.setIn(new UnClosableDecorator(System.in));
}

After close Scanner(System.in), create Scanner(System.in), but not operate correctly

public void b(){
Scanner scan = new Scanner(System.in);
int b = scan.nextLine();
....
input.close();
}

this should not be input.close();! b() method cannot access the input variable of a() method. So you should replace it with scan.close()

public void b(){
Scanner scan = new Scanner(System.in);
int b = scan.nextLine();
....
scan.close();
}


Related Topics



Leave a reply



Submit