public static void maxintRecursive(int max) {
// create scanner
Scanner in = new Scanner(System.in);
// asks user for integer input
int a = in.nextInt();
// checks if integer input satisfies exit condition, closes scanner, prints max and returns
if (a <= 0) {
in.close();
System.out.println("Max int is: " max);
return;
}
// checks if input is greater than previous max registered int
if (a > max) {
max = a;
}
// calls itself again
maxintRecursive(max);
}
I can compile and run it successfully, but at line 3 it underlines "in" saying that it's never closed However, this method keeps calling itself until you reach the exit condition (a <=0) under which the scanner does in fact get closed
Is it an error? Is it actually never getting closed and I'm getting a memory leak?
Should I pass a scanner in the method from the main, or would it be the same?
This recursive method asks the user for an integer input and returns the maximum integer received once the user inputs 0 or less
I created a scanner inside the method and closed it when the recursive method reaches its exit condition
I expected the scanner to be closed by my code inside the exit condition, but VS Code says it never gets closed
CodePudding user response:
Each time method its called, it creates its own local variables. For instance if you have method like
void foo(int n) {
int x = n 1;
if (x < 2)
foo(x);
}
and you call it like foo(0);
then while executing it will have its own two local variables n=0
(method parameter) and x = n 1 = 0 1 = 1
(declared in body of method).
Then when you invoke recursively foo(x);
which will end up as foo(1)
that invocation will create another set of n
x
local variables which will be holding values n=1
x=2
.
Similarly in your case, each time you call maxintRecursive
method it creates its own separate Scanner in = new Scanner(...)
object. So if you called your method N times, the N Scanner
objects ware created (all of them reading from System.in
). Even if you call in.close();
in method handling if (a <= 0)
it will only close Scanner created by that recursive invocation. Other Scanners, created in previous method calls will never be closed.
Possible solution could be also adding in.close();
at the end of your method (after recursive call), which will ensure that each method will close its own Scanner.
But preferred solution would be preventing creating so many Scanners in the first place. Instead create one in main
method and pass it to recursive method as parameter. Since it will be passed Java will not force you to close that scanner in method itself, but in scope where it was created (the main method).
To do this you need to let maxintRecursive
accept Scanner as parameter by modifying its declaration like
public static void maxintRecursive(int max, Scanner in) {
//...
}
This way all you need now is something like
public static main(String[] args){
Scanner scanner = new Scanner(System.in);
maxintRecursive(-1, scanner);
scanner.close();
}
BTW another reason we avoid creating Scanner which handles System.in
inside our own methods is fact that closing such Scanner by that method would also close System.in
. This means when you will try to call your method again it will create Scanner which will try to read from already close System.in
. Again, preferred solution in such case is to pass Scanner handling System.in as method parameter.