I've seen a similar question to this but mine's a little more specific. I have the below
File f = new File("./data.txt");
if(f.isFile())
{
try
{
FileChannel fc = new RandomAccessFile(f,"r").getChannel();
//Get information and return it
}
catch(FileNotFoundException e)
{
System.out.println("FileNoFoundException: "+e.getMessage());
}
}
else
{
//If the file wasn't found, return default values
}
I was wondering, should I just put the default returning of the information in the catch block?
I assumed that'd be a no because you're not really supposed to use it to control flow. But having the both the if and the try catch just looks too redundant to me.
2 Answers 2
In cases like this, I like taking a default-unless-better approach... Consider this re-working of your code to do the same thing in a different order.
The basic premise is:
- set up a default value (or null if it is a complicated thing to do).
- do the hard work which may be missing dependencies or may fail
- if the hard work completes successfully, return that result.
The reason this works well is because you can exit from the hard work at any point, and have the default standing by to continue.....
... also, as an exercise, use the try-with-resources and new NIO2 features in Java7
// set up the default value...
SomeValue result = null;
Path path = Paths.get("./data.txt");
if (Files.isRegularFile(path)) {
try (SeekableByteChannel channel =
Files.newByteChannel(path, StandardOpenOptions.READ)) {
// do the work required for your file....
...
// after everything is successful... set the result:
result = new SomeValue(....real arguments ....);
} catch (IOException ioe) {
System.out.println("FileNoFoundException: " + e.getMessage());
}
}
result == null ? new SomeValue(defaults...) : result;
Additionally, there is no reason, if you are in a method that builds these things, that you can't return immediately with the right answer.
Often if you are doing things like the above, it indicates that what you are doing should be in a sub-method, with an early-return when you have a successful setup, and a default return value when things fail.
-
\$\begingroup\$ It actually is in a submethod and after reworking it a bit I found that this was the best option. Thanks! Very similar to the answer below but I understood this one more. \$\endgroup\$Cobertos– Cobertos2014年01月23日 14:24:09 +00:00Commented Jan 23, 2014 at 14:24
My usual pattern here is to set the default values first, then replace the defaults with the expected values in the happy path.
int resultA = DEFAULT_FOR_A;
String resultB = DEFAULT_FOR_B;
File f = new File("./data.txt");
if(f.isFile())
{
try
{
FileChannel fc = new RandomAccessFile(f,"r").getChannel();
resultA = computeA(fc);
resultB = readB(fc);
}
catch(FileNotFoundException e)
{
// TODO: replace with a logging framework
System.out.println("FileNoFoundException: "+e.getMessage());
}
}
// use resultA and resultB as required.
If computeA()
and readB()
can also throw, then you need to think about whether the results are coupled or not. If they are coupled, then I would advise storing the results of the functions in variables scoped to the try block, and only overwriting the results after you are certain that no further exceptions will be thrown.
if(f.isFile())
statement looks redundant to theFileNotFoundException
. Also, what iff
isnull
? \$\endgroup\$