So I decided to start studying Java, and I’m working on a really basic program. The plan here is to do this:
a) read in a filename from the keyboard.
b) open that filename for input.
c) read in a fictional list of employees and store them in an array of objects of type Employee.
d) display the info.
It was all working fine until I tried to add a FileNotFoundException handler. So what I"m doing, is this: I have a while loop with a boolean variable called success, initialized to true. Inside the while loop, I have a try block that reads in the filename and opens it as a stream. Once it’s successful, it should exit the loop with a valid file handle. But it doesn’t. It fails to complile, telling me that later on when I try to do DATA.readLine(), it tells me that variable DATA might not have been initialized.
Is this a scope problem? Opening the file handle has to be inside the try statement, otherwise it doesn’t work.
Here’s the relevant code:
BufferedReader IN = new BufferedReader(new InputStreamReader(System.in));
InputStreamReader istream;
BufferedReader DATA;
boolean success = true;
while(success==false)
{
System.out.println("Enter the full path of the file containing employee information: ");
String filename = IN.readLine();
try
{
istream = new FileReader(filename);
DATA = new BufferedReader(istream);
}
catch(FileNotFoundException e)
{
System.out.println("File Not Found. Try again.");
success=false;
}
}
I’m not an expert, but I’ve dabbled in Java a little. Try setting DATA to null initially. (And then, if necessary, making sure to check for a null value before doing something that would cause problems if it was null.)
Here is the complete source, with the lines causing me the problem commented out. It compiles as is, but when I put in the while { try {} } block, it gives me the “variable DATA might not have been initialized” error.
Here’s your problem - you are initializing DATA inside your try block. What happens if it throws an exception before it gets to your line of code? You wind up with a variable that is not initialized.
Initialize DATA outside of the try block, then just re-assign its value = BufferedReader after that. Don’t use the new operator inside the try block.
I see what you’re saying, but remember I’m new at this stuff. I thought that was the part that can throw the exception… Opening a new FileReader(variableFilehandle) would give a FileNotFoundException if it doesn’t exist, right? Or wrong?
Does try{} have its own scope with local variables, like a function? If so, how do you do something like this, where the statement that will throw an exception (and so has to be inside a try block) assigns something to a filehandle or variable?
The whole point of putting sensitive code in a try block is to say “anything in here can blow up at any time!” Since your try block also contains the new FileReader instantiation, the Java compiler is putting out the warning to say, “Hey, an exception might get thrown before DATA is initalized.” The code probably would run without errors, but the compiler is trying to help you by noting that this is a dicey situation.
A safer solution might be something like:
BufferedReader DATA = null;
boolean success = true;
while(success==false)
{
System.out.println("Enter the full path of the file containing employee information: ");
String filename = IN.readLine();
try
{
istream = new FileReader(filename);
DATA = new BufferedReader(istream);
}
catch(FileNotFoundException e)
{
System.out.println("Something went wrong. Try again.");
success=false;
}
}
if (DATA != null) {
DATA.readLine();
}
else {
System.out.println("Cannot call readLine because DATA was not initalized.
");
}
And y’know, I really should charge you $25/hour for this advice…
hmmmm…I got it to compile and run (my major, really stupid mistake was that it never enters the while loop. I initialized success to true, then put everything into a loop starting with while(success==false)), but I had to put in a junk initialization of DATA.
Now I’m even more confused than I was before when it wouldn’t work. WHY do I need to give DATA a throwaway initialization, when I don’t see a path through the code where it doesn’t get initialized, even without it.
DATA = new BufferedReader(new InputStreamReader(System.in));
boolean success = false;
while(success==false) {
// ...
try {
DATA = new BufferedReader(new FileReader(filename));
success = true;
}
catch(FileNotFoundException e) { /* ... */ }
}
Try considering the try block like this …
try {
FileReader f = new FileReader(filename);
BufferedReader r = new BufferedReader(f);
DATA = r;
}
which is what the code does. Because ‘new FileReader’ can throw an IO exception (IIRC) it may never get past that line. When the exception is thrown control passes to the catch block and then jumps to after the try/catch combo (it doesn’t resume in the try block).
Hence DATA may not be initialised after the try/catch block, hence the warning.
nope. Breaking up the initialization makes no difference. I still get the error if I don’t include a trash initialization (DATA = new BufferedReader(new InputStreamReader(System.in)) near the top of the listing). The trash init never gets used - there’s no way for the real initialization not to happen properly as far as I can see. I guess I’m doomed to waste the memory for a throwaway object. Maybe it’s a quirk of the compiler?
I don’t think it makes sense to put the entire functionality of the program inside the try block, does it? Would there be any dis/advantages to doing that (besides the obvious lack of compilation error and saving the one wasted piece of memory)?
You should be able to initialize it to null, and not waste an object. To make sure of it, I just copied your exact code, excised the references to the “Employee” class which I don’t
have, verified that I got the error with no initialization, and got it to go away by simply initializing with “DATA = null”. This is a fairly common pattern actually.
What might appeal to your sense of “rightness” a little more is to create a static method which handles the loop and returns the created BufferedReader:
Makes the body of your main look a little cleaner anyway, and what you probably actually want to do is iterate for a few prompts and bail out with a System.exit() if they don’t input a legitimate file.
Yabob, I tried it both ways. thanks for the tip on DATA=null, that worked like a champ. Unfortunately, the way I want my prog to run (loop on an exception, until you get valid input), the change you suggested doesn’t work. Still gets the same error on compile.
But thanks for the advice. I appreciate it greatly.