life and death of an object explanation - java

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

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.

Recreating Scanner in Java

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.

resource leak 'Nommy' is never closed error

i'm new to java so please do explain in full were i'm going wrong
thank you.
import java.util.Scanner;
class apples {
public static void main (String args[]){
Scanner Nommy = new Scanner (System.in);
System.out.println (Nommy.nextLine());
}
}
To understand what's wrong, you should learn more about streams stuff.
Briefly, if you open stream, then, you should close it, or a memory leak appears.
See http://www.tutorialspoint.com/java/java_files_io.htm for details.
Good luck!
You should close the scanner after using it. Otherwise, you'll get the warning from the compiler.
The simplest way is to add Nommy.close() after the last statement.
You should, however, call it in a finally block or using the try statement: see https://stackoverflow.com/a/15613676/1547337

How do I use a Scanner only once then get rid of it?

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.

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