When to actually use exceptions (file exists, etc)

E

EdwardH

When should one use exceptions and when should one just return null/false?

My virtual filesystem will return exceptions when trying to open a file
that is not readable or does not exist.

Should I not just return false when trying to open a nonexistent file?
 
I

Ingo R. Homann

Hi,
When should one use exceptions and when should one just return null/false?

My virtual filesystem will return exceptions when trying to open a file
that is not readable or does not exist.

Should I not just return false when trying to open a nonexistent file?

Exceptions are a good thing to make something fail-fast. When an error
occurs and there is no way to handle that in a proper way and to
continue as if the error did not occur, then an exception is the best
way to propagate this error.

If a File.getOutputStream() returns null rather than throwing an
Exception, if the File can not be written, then it is easy for the
programmer to ignore the possibility of such error:

File f=new File(...);
FileOutputStream out=f.getOutputStream();
f.write(datasource.getSomeObject());

This example-code (and nearly every other code) will fail sooner or
later - in this case by throwing a NullPointerException in the third
line. But it is much better when the code fails fast instead of ignoring
the error and fail later, because when the the code fails early, the
error can be found, interpreted and resolved much better.

For example: If the user gets an error-message "NullPointerException in
line x" he must call the support to find out what went wrong. The
support perhaps thinks that "datasource" is null and is even more confused.

Whereas, when there would be a "FilePermissionException", the programmer
*has* to catch it (if it is a checked exception) and normally, he would
write an errormessage like "You are not allowed to write to that file"
instead of some cryptic "NullPointerException".

Even worse if the code does not produce a NPE, but an incorrect result
which seems to be valid at first glance!

Ciao,
Ingo
 
E

Eric K Idema

EdwardH said:
When should one use exceptions and when should one just return null/false?
My virtual filesystem will return exceptions when trying to open a file
that is not readable or does not exist.
Should I not just return false when trying to open a nonexistent file?

I would prefer to have an exists method so I can avoid opening a
nonexistent file in the first place. Then if I fail to check for
existence, I would definitely want an Exception thrown. A return
value is too easy to ignore, and I can end up in an unintended state
where other errors occur that are harder to track down. For example:

VirtualFile vf = VirtualFile.open( "some virtual path" );
InputStream in = vf.getInputStream();

If the first line returns null because the file doesn't exist, the
second line will throw a NullPointerException. Wouldn't it be much
better if the first line through a VirtualFileException? Which
would be easier to debug?

Eric
 
G

Gordon Beaton

I would prefer to have an exists method so I can avoid opening a
nonexistent file in the first place.

The problem with this kind of check is that the result is already
history by the time you actually attempt to open the file (even though
that might be "immediately" afterwards). Also, there are other factors
that could cause the open to fail.

So, since you still need to check whether you succeeded in opening the
file anyway, what is gained by checking beforehand?

/gordon
 
E

Eric K Idema

The problem with this kind of check is that the result is already
history by the time you actually attempt to open the file (even though
that might be "immediately" afterwards).

You raise a good point. There is, of course, the problem that we probably
can't guarantee atomicity with a virtual filesystem. So I'd still recommend
an Exception be thrown if a problem occurs when opening a file.

if ( file.exists() ) {
file.open();
}

It seems to me that the odds of the file being made nonexistent between
the call to exists() and open() is likely to be very small (though
perhaps we shouldn't make assumptions about the environment). I'd
consider it an exceptional situation.
Also, there are other factors that could cause the open to fail.

If there are other reasons that opening a file might fail, I'd like
checks for those conditions, as well.
So, since you still need to check whether you succeeded in opening the
file anyway, what is gained by checking beforehand?

The check is to avoid the Exception that I advocated having the operation
throw. I won't reiterate my reasons for prefering that an Exception be
thrown.

Eric
 
O

Oliver Wong

EdwardH said:
When should one use exceptions and when should one just return null/false?

My virtual filesystem will return exceptions when trying to open a file
that is not readable or does not exist.

Should I not just return false when trying to open a nonexistent file?

I think returning a value indicating whether an operation succeeded or
not is a C/C++ habit. The "Java way" of doing things is to instead throw
exceptions when an operation fails. The rational for this is that client
code using your method might not check the return value to see if the
operation failed or not, leading to unstable buggy code.

- Oliver
 
S

Stefan Ram

Oliver Wong said:
I think returning a value indicating whether an operation
succeeded or not is a C/C++ habit. The "Java way" of doing
things is to instead throw exceptions when an operation fails.
The rational for this is that client code using your method
might not check the return value to see if the operation failed
or not, leading to unstable buggy code.

I would like to to define the open-file operation as a new
control structure, as in

iffopen( "path" )
( File file )
{ /* success block using the file "file" */ }
else
( Report report )
{ /* failure block using the report "report" */ }

AFAIK, it is not possible to implement it like this in Java.
It should be possible in Lisp or possibly Smalltalk.
 
C

Chris Uppal

Stefan said:
I would like to to define the open-file operation as a new
control structure, as in

iffopen( "path" )
( File file )
{ /* success block using the file "file" */ }
else
( Report report )
{ /* failure block using the report "report" */ }

AFAIK, it is not possible to implement it like this in Java.
It should be possible in Lisp or possibly Smalltalk.

It is certainly possible in Smalltalk (where such patterns are used routinely
and extensively), but it's probably significant that although the file API
/could/ be arranged so that you said

openfile := OpenFile
open: 'filename'
ifAbsent: [... error handling code goes here...].


(
For those who can't read Smalltalk syntax, the nearest equivalent in Java would
be something like (slightly abusing the Runnable interface for simplicity)

OpenFile openfile = OpenFile open(
"filename",
new Runnable({
public void run()
{
... error handling code...
...goes here...
});
where the static factory method, open(), on the (fictitious) class OpenFile is
declared:
public static OpenFile open(String filename, Runnable errorHandler);
So it /can/ be done in Java too, but it's too messy to be practical.
)

But in fact (AFAIK) no implementation does that, they all throw exceptions if
the file doesn't exist, and indeed that turns out to be more convenient in the
vast majority of cases.

BTW, most implementations do use a similar pattern to the above. Instead of an
error handler, the caller provides a block that will be executed if the file
/does/ exist, passing the open file to it as a parameter, and automatically
closing the file again after the block has finished executing. IMO that's a
very neat bit of API design (actually it's a very common idiom).

-- chris
 
R

Roedy Green

I think returning a value indicating whether an operation succeeded or
not is a C/C++ habit.

And the typical C programmer's tactic is most of the time to ignore
the return code. It really clutters the code to have to keep testing
if all went ok. It is a hold-over from days before exceptions.
 
D

Dimitri Maziuk

Roedy Green sez:
And the typical C programmer's tactic is most of the time to ignore
the return code. It really clutters the code to have to keep testing
if all went ok. It is a hold-over from days before exceptions.

It's called "fault-oblivious programming": the code works as specified
in the requirements paper; if you don't give it enough resources or point
it to non-existing files, it's your fault and you get to keep the pieces.

Dima
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top