hedgehogrider
hedgehogrider

Reputation: 1198

Building a Scanner with an embedded FileReader recursively in java

public static Scanner getFileScanner()
{
    try{
        Scanner input = new Scanner(System.in);
        String file = input.nextLine();
        Scanner fs = new Scanner(new FileReader(file));            
    }catch (FileNotFoundException fe) {
        System.out.println("Invalid filename. Try another:");
        getFileScanner();
    }finally{
        return fs;
    }
}

I keep getting the error that the variable fs isn't found. I can't figure out why for the life of me.

Upvotes: 0

Views: 622

Answers (6)

Stephen C
Stephen C

Reputation: 719248

Lets start by listing the problems in your code:

  1. The compilation error on the return statement is caused by fs being out of scope as described in other answers.

  2. When you make the recursive call to getFileScanner(), you don't assign or return the result. So it won't make it back to the caller.

  3. Using a return in a finally block is a bad idea. It will squash (throw away) any other exceptions that might be propagating at that point; e.g. exceptions that don't match a catch or exceptions thrown in a catch block.

  4. The input.nextLine() call will throw an exception if the underlying stream has reached the EOF; e.g. the user typed [CONTROL]+D or whatever. You don't have to catch it (it is unchecked), but the return in the finally block squashes it (probably) resulting in the caller getting a null instead. Ughh ...

  5. Hard-wiring System.in and System.out makes your method less reusable. (OK, this may not be an issue you should address in this particular case. And I won't, below ...)

  6. In theory, your method could be made to throw a StackOverflowError; e.g. if the user hits [ENTER] a number of times. This problem is inherent in your recursive solution, and is a good reason not to do it that way.

Finally, here's a version of the method that addresses these problems:

public static Scanner getFileScanner() throws NoSuchElementException
{
    Scanner input = new Scanner(System.in);
    while (true) {
        String file = input.nextLine();
        try {
            return new Scanner(new FileReader(file));           
        } catch (FileNotFoundException fe) {
            System.out.println("Invalid filename. Try another:");
        }
    }
}

Note that I've replaced the recursion, gotten rid of the finally, and declared the exception that is thrown. (One could catch that exception and either report it, or rethrow it as an application specific exception.)

Upvotes: 1

ColinD
ColinD

Reputation: 110084

Variables declared inside a try block are not in scope inside the corresponding finally block. There are a number of issues with your approach in general... it's generally not a good idea to return inside a finally block, for example.

Here's what I'd do:

public static Scanner getFileScanner() {
  Scanner input = new Scanner(System.in);
  File file = null;
  while (true) {
    file = new File(input.nextLine());
    if (file.exists() && file.isFile())
      break;
    System.out.println("Invalid filename. Try another:");
  }
  return new Scanner(new FileReader(file));
}

Upvotes: 1

Jabbslad
Jabbslad

Reputation: 546

Just to expand on what the other guys indicated with their code samples...

Because you declare the fs variable within the try block the variable will only be scoped (visible) within the braces immediately after the try keyword.

By moving the fs variable declaration out of the try block and into the getFileScanner method body you are ensuring that the variable can be accessed by all blocks within the method body (try, catch and finally blocks).

Hope that helps!

Upvotes: 0

corsiKa
corsiKa

Reputation: 82589

Declare it first:

public static Scanner getFileScanner() {
    Scanner input = new Scanner(System.in);
    Scanner fs = null;
    while(fs == null) {
        try{
            String file = input.nextLine();
            Scanner fs = new Scanner(new File(file));            
        }catch (FileNotFoundException fe) {
            System.out.println("Invalid filename. Try another:");
        }
    }
    return fs;
}

Upvotes: 0

Voo
Voo

Reputation: 30226

You declared fs in the try block and try to access it in a different scope (the finally block). The usual paradigms is to declare fs before the try block as null.

Upvotes: 0

limc
limc

Reputation: 40176

Your fs is declared under try block... to fix this, declare it outside the block:-

Scanner fs = null;
try {
    ...
    fs = new Scanner(new FileReader(file));
}
catch (FileNotFoundException fe) {
    ...
}
finally {
    return fs;
}

Upvotes: 1

Related Questions