Andreas Tasoulas
Andreas Tasoulas

Reputation: 453

Use of Scanner class in recursive functions

I am trying to use a recursive method/function, which uses the Scanner class. Closing the scanner, causes an exception to be thrown the next time the same method is called within the recursion. A workaround to this is not to close the scanner at all, but this is not a right approach. I suspect the same scanner object is used between recursive calls, so that's why closing it creates havoc. If my assumption is correct then closing the scanner in the last method call would be a valid workaround (i.e. no actual resource leak). Is there anything I may be missing before jumping into Scanner and related implementation code?

EDIT

The answers provided were really useful and enlightening. In summary, the problem is the constant re-opening and closing of the scanner, and not recursion per se. The reason I would avoid passing the scanner object as parameter is that this example simulates a larger project, calling multiple recursive functions and I would have to pass the scanner object in all of them.

On the practical side, and from the answers provided, I think just closing the scanner in the last recursive call would work without having any resource leaks. Any related opinions would be welcome, esp. if you see something wrong with my approach.

Here is an example of my initial experiment:

package scanner;

import java.util.Scanner;

public class Main {

  public static void acceptValidInput() {

    System.out.print("Enter a number greater than 10: ");
    Scanner sc = new Scanner(System.in);
    int i = sc.nextInt();

    // Adding this will make an exception to be thrown:
    sc.close();

    if (i <= 10) {
        acceptValidInput();
    }
}

  public static void main(String[] args) {
    acceptValidInput();
    System.out.println("Your input is valid");
  }
}

Upvotes: 2

Views: 6093

Answers (4)

thejh
thejh

Reputation: 45578

Once you start to consume an input stream using a Scanner, you should not try to read from it in any other way anymore. In other words, after you have constructed a Scanner to read from System.in, you need to use it for all further reading from System.in. This is because Scanner buffers input, so you have no idea how much input it has already consumed but not emitted yet.

Therefore, I recommend that you construct one Scanner, then use it for all the reading:

public class Main {
  public static void acceptValidInput(Scanner sc) {
    System.out.print("Enter a number greater than 10: ");

    int i = sc.nextInt();

    if (i <= 10) {
      acceptValidInput(sc);
    }
  }

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    acceptValidInput(sc);
    System.out.println("Your input is valid");
    sc.close();
  }
}

Upvotes: 2

nik
nik

Reputation: 210

public class abc{
public void acceptValidInput() {

    System.out.print("Enter a number greater than 10: ");
    Scanner sc = new Scanner(System.in);
    int i = sc.nextInt();

    // Adding this will make an exception to be thrown:


    if (i <= 10) {
        acceptValidInput();
    }
}

  public static void main(String[] args) {
     while(true){
      abc a=new abc();
   a.acceptValidInput();
   System.out.println("Your input is valid");
     }
  }}

try this.

Upvotes: -1

Ashot Karakhanyan
Ashot Karakhanyan

Reputation: 2830

It works:

package scanner;

import java.util.Scanner;

public class Main {

    public static void acceptValidInput(Scanner sc) {

        int i = sc.nextInt();

        if (i <= 10) {
            System.out.print("Enter a number greater than 10: ");

            acceptValidInput(sc);
        }
    }

    public static void main(String[] args) {

        System.out.print("Enter a number greater than 10: ");
        Scanner sc = new Scanner(System.in);

        acceptValidInput(sc);
        sc.close();

        System.out.println("Your input is valid");
    }
}

The result is:

Enter a number greater than 10: 4
Enter a number greater than 10: 5
Enter a number greater than 10: 11
Your input is valid

Process finished with exit code 0

Upvotes: 2

nils
nils

Reputation: 1382

Closing the scanner closes also the underlying input stream. In this case it is the System.in stream - you shouldn't do this. Either do not close it or create a single scanner for all method calls.

Upvotes: 1

Related Questions