Exception Names

M

Martin Gregorie

There's something entirely exceptional about asking an object for
something (a next byte) that it can't give you. If a method can't do
what you've asked it to do, it should throw an exception.
Requiring exception handlers for everyday events like End Of File and
Missing Key (in an indexed file) was one of the most annoying features of
PL/1.

I much prefer getting null, -1 or whatever in those cases - in short,
anything that a normal 'while' condition can handle .
 
A

Arne Vajhøj

Roedy said:
It may be too late now, but it would be nice if some exceptions were
renamed and the old names deprecated.

NullPointerException : We Javites make such a production of the fact
Java has no pointers, just references. This should be called
NullReferenceException.

IllegalArgumentException: there is nothing illegal involved. This
should be renamed InvalidArgumentException.

There needs to be some exceptions much like IllegalArgumentException
that make a finer distinction.

InvalidDataError : Somebody goofed preparing the data.
CorruptDataError : checksums bad, wrong data format.
ProgrammingError : something that should not be possible, similar to a
failed assertion that is not turned off.

If you can travel back in time to before the release of Java 1.0
and convince Gosling, then fine with me.

But I can not see any reason to change such fundamental classes
in Java today just because of some rather subtle nuances in the
English language.

It is not worth the trouble.

Arne
 
A

Arne Vajhøj

Lew said:
Besides, there's nothing exceptional about reaching the end of a
stream. One would venture to say that one nearly always reaches the end
of a stream, *unless* something exceptional happens.

Very relevant point.

Arne
 
A

Arne Vajhøj

Mike said:
Right; the most Java-ish thing would be for Streams to be
iterator-like:

while (stream.hasNext())
{
char c = stream.next();
}

or even

for (char c: stream)
{
}

1) performance would most likely not be good.
2) semantics could become very confusing - either hexNext
would do the actual read or for some types of streams next
could fail even ig hasNext returned true

Arne
 
A

Arne Vajhøj

Tom said:
I don't believe it for a second, and even if it is true,

It depends on the bad ratio.

No bad cases means approx. same speed.

But all bad cases will decrease performance by a factor 10 by
using exceptions instead of return values.
it's not a good
enough reason.

I agree.

But as Lew pointed out end of stream is not exceptional, so good
programming practice is also against the exception.

Arne
 
A

Arne Vajhøj

Tom said:
Is this a good time to mention that in python, iterators don't have a
hasNext method, and instead their next method just throws StopIteration
at the end? :)

It is obviously interesting for the question being debated.

But Python is a different language from Java.

Arne
 
M

Mike Schilling

Arne said:
1) performance would most likely not be good.

Because of two method calls rather than one? (I'm assuming streams
wouldn't have to implement java.util.Iterator, so that next() could
return a byte rather than a Byte.)
2) semantics could become very confusing - either hexNext
would do the actual read or for some types of streams next
could fail even ig hasNext returned true

The semantics would have to be well-defined. Since we're not assuming
any asynchrony, I'd expect hasNext() to do actual I/O, if that's
necessary to ensure that a character is available. (This is hidden
when the for loop is used, anyway.)

The result is something like:

public Interface ByteSource
{
boolean hasNext() throws IOException;
byte next() thoews IOException;
}

And the adaptor is simply

public ByteSourceIterator InputStreamByteSource
{
pivate InputStream strm;
private int c;
private boolean atEOF;

public InputStreamByteSource(InputStream is)
{
strm = is;
c = -1;
atEOF = false;
}

public boolean hasNext() throws IOException;
{
if (atEOF)
return false;
if (c < 0)
c = getNextByte();
return c >= 0;
}

public byte next()
{
if (!atEOF && c < 0)
c = getNextByte();
if (c < 0)
throw new NoSuchElementException();
byte r = c;
c = -1;
return r;
}

private byte getNextByte() throws IOException
{
if (atEOF)
return -1;
byte b;
try
{
b = strm.read();
}
catch (IOException ex)
{
atEOF = true;
strm.close();
throw ex;
}

if (b < 0)
{
atEOF = true;
strm.close();
}
return b;
}
}
 
A

Arne Vajhøj

Mike said:
Because of two method calls rather than one?
Yes.


The semantics would have to be well-defined.

Well-defined is required but not sufficient to make it good.
Since we're not assuming
any asynchrony, I'd expect hasNext() to do actual I/O, if that's
necessary to ensure that a character is available.

I don't think that is intuitive.
(This is hidden
when the for loop is used, anyway.)

True.

It is only a problem when used more explicit.

Arne
 
M

Mike Schilling

Arne said:
Well-defined is required but not sufficient to make it good.


I don't think that is intuitive.

It is to me (how do you know whether there's a next character if you
don't fetch it?), but perhaps that's because I've implemented a lot of
iterators where hasNext() had to do significant work.
 
A

Arne Vajhøj

Mike said:
It is to me (how do you know whether there's a next character if you
don't fetch it?), but perhaps that's because I've implemented a lot of
iterators where hasNext() had to do significant work.

I have seen it too, but from an ultra strict puristic view then
hasXxxx should not change the state of an object.

Arne
 
A

Alan Gutierrez

I certainly agree that both these use cases are valid (although i'd bet
the latter is ten times more common), but i don't see why having a null
return is necessary to address the former. This code:

Thing value = map.get(key);
if (value != null) {
        dealWithValue(value);}

else {
        dealWithLackOfValue();

}

Is trivially rewritten as:

try {
        Thing value = map.get(key);
        dealWithValue(value);}

catch (KeyException e) {
        dealWithLackOfValue();

}

With no loss of readability. There is a potential performance penalty, but
i don't believe it would be significant with modern VMs.

Many people will dislike the latter version because it 'abuses'
exceptions. I think this betrays an overly dogmatic attitude to
exceptions, but it's a matter of taste.

Returning -1 or null to indicate the absence of a value is not 20th
century C bullshit. It is an exceedingly common pattern that is easily
understood.

The notion that an exception is a bad thing in Java is a useful norm.
It means that unhandled checked exceptions are identified as potential
problems. It means that exception handling blocks are understood to be
blocks of code outside the normal flow of the program. When I look in
a catch block, I expect to see error logging, or exception wrapping in
an exception class that has additional information about the error.

How does your notion extend to String.indexOf(char)?

public class Emailer {
public void sendEmailEx(String address, String message) {
// No C bullshit.
try {
address.indexOf("@");
sendToRemoteMachine(address, message);
}
catch (CharacterNotFoundException e) {
putInLocalHostMailbox(address, message);
}
}

public void sendEmailReturn(String address, String message) {
// With C bullshit.
if (address.indexOf("@", -1) == -1)
putInLocalHostMailbox(address, message);
else
sendToRemoteMachine(address, message);
}
}

In the case of indexOf, what "default" value would I ever return
besides an error indicator? Why are we calling it a "default" value
when it is really just the reintroduction of the function you're
trying to replace?
The thing that most motivates me to want the latter version is that it
makes it impossible to ignore absent keys. With a null return, code like
this:

The ability to ignore the absence of a value is one of the benefits of
returning a -1 or null result. Are you suggesting that
CharacterNotFoundException should be a checked exception? Does this
code motivate?

if (address.matches("@")) {
int i;
try {
i = address.indexOf('@');
} catch (CharacterNotFoundException e) {
// Impossible to get this green in test coverage.
throw new RuntimeException("This will never happen.", e);
}
InternetMailer.send(address.substring(0, i), address.substring(i +
1), message);
} else {
putInLocalHostMailbox(address, message);
}

Basically, there are times when null or -1 is a valid response for a
function. It is not the same sort of coding horror as a COM error
result code. In the case of indexOf I can ignore the absence, or
ignore the index and test for absence, or I do both at the same time,
because indexOf really is a linear scan of the string for the first
occurrence of a character. It is a loop over the underlying character
array. I want the results of that algorithm. I know what to do with
that C bullshit.

Just like read is really a possibly blocking poll of an I/O device, or
a socket or stdin. It is not an iteration over a finite collection of
characters in memory.

Alan Gutierrez - (e-mail address removed) - http://blogometer.com
 
A

Alan Gutierrez

I have seen it too, but from an ultra strict puristic view then
hasXxxx should not change the state of an object.

Arne

Arne and Mike

Indeed, the Iterator interface doesn't apply because it is supposed to
be an iterator over the state of an object. The read method does
change the state of a stream, which is why I/O streams are their own
library, with their own patterns. The read method is not an iterator,
it reads, it goes to I/O and comes back with a result, and one valid
result is that there is nothing there.

Is hasNext supposed to block? Where is there support for that in
Iterator? How would I set a timeout? It seems like this discussion is
so focused on turning read into an Iterator, it loses sight of the
basic differences between objects and streams.

You can remove those differences, but only by adding a layer of
abstraction. You can create helper libraries that slurp files for you
and throw coarse exceptions for any I/O error, but to really take
control of I/O you need an API that will accurately model I/O, that
will accurately model an I/O read.

Even if we managed to hammer out how to implement Iterator over an
InputStream, now how do we implement the other flavors of read? Does
an InputStream somehow generate a Iterator<List<Byte>> to replace
InputStream.read(byte[])?

Alan Gutierrez
 
K

Karl Uppiano

Roedy Green said:
It may be too late now, but it would be nice if some exceptions were
renamed and the old names deprecated.

NullPointerException : We Javites make such a production of the fact
Java has no pointers, just references. This should be called
NullReferenceException.

IllegalArgumentException: there is nothing illegal involved. This
should be renamed InvalidArgumentException.

There needs to be some exceptions much like IllegalArgumentException
that make a finer distinction.

InvalidDataError : Somebody goofed preparing the data.
CorruptDataError : checksums bad, wrong data format.
ProgrammingError : something that should not be possible, similar to a
failed assertion that is not turned off.

Not so much a naming thing, but I kinda wish InterruptedException was a
runtime exception instead of a checked exception. IMHO, there may be more
incorrect code written to handle InterruptedException than all of the others
combined. More often than not, it seems when someone wants to wait, they
catch and "eat" the InterruptedException, often resuming in some loop, when
someone much higher up wanted to interrupt the wait and regain control of
the thread.
 
L

Lew

Karl said:
Not so much a naming thing, but I kinda wish InterruptedException was a
runtime exception instead of a checked exception. IMHO, there may be

Then no one would handle it.
more incorrect code written to handle InterruptedException than all of
the others combined. More often than not, it seems when someone wants to

This is only the tip of the iceberg when it comes to incorrect thread programming.
wait, they catch and "eat" the InterruptedException, often resuming in
some loop, when someone much higher up wanted to interrupt the wait and
regain control of the thread.

These folks have obviously not read and assimilated /Java Concurrency in
Practice/ by Brian Goetz, et al.

Making 'InterruptedException' runtime would not have helped; indeed, it would
have exacerbated the problem. People would have learned the hard way that
they were getting the exception, then still handled it incorrectly.

Face it, Java is a language that must be studied, and it must be learned.
Some of the problems it solves, such as multi-threaded programming, are
inherently hard. The language cannot make the problem easier; the best it can
do is not make it any harder.

The point of making an exception checked or not is not to prevent abuse of the
exception. Nothing but care by the practitioner can do that. The point of
making an exception checked is to identify methods that intentionally throw
that exception, and force their clients to deal with it with a compile-time
check. Forcing clients to deal with the exception correctly is something that
Java as a language cannot do.

Give us smarter programmers, not a smarter programming language.
 
J

Joshua Cranmer

Karl said:
Not so much a naming thing, but I kinda wish InterruptedException was a
runtime exception instead of a checked exception. IMHO, there may be
more incorrect code written to handle InterruptedException than all of
the others combined. More often than not, it seems when someone wants to
wait, they catch and "eat" the InterruptedException, often resuming in
some loop, when someone much higher up wanted to interrupt the wait and
regain control of the thread.

Programmer stupidity is not a good reason to make a checked exception a
runtime exception. The entire point of checked exceptions it that it
forces programmers to deal with potentially dangerous situations in some
manner; if programmers choose to deal with them idiotically, they're
just opening themselves up to a world of hurt.

If someone is eating InterruptedExceptions, he or she probably doesn't
know what that exception means. In that case, there are likely much
larger multithreading bugs in the same code.
 
D

Daniel Pitts

Tom said:
I certainly agree that both these use cases are valid (although i'd bet
the latter is ten times more common), but i don't see why having a null
return is necessary to address the former. This code:

Thing value = map.get(key);
if (value != null) {
dealWithValue(value);
}
else {
dealWithLackOfValue();
}

Is trivially rewritten as:

try {
Thing value = map.get(key);
dealWithValue(value);
}
catch (KeyException e) {
dealWithLackOfValue();
}

With no loss of readability. There is a potential performance penalty,
but i don't believe it would be significant with modern VMs.

Many people will dislike the latter version because it 'abuses'
exceptions. I think this betrays an overly dogmatic attitude to
exceptions, but it's a matter of taste.

The thing that most motivates me to want the latter version is that it
makes it impossible to ignore absent keys. With a null return, code like
this:

class Customer {
private static Map<Locale, Country> COUNTRIES_BY_LOCALE;

private Country country;

public Customer(Locale locale) {
country = COUNTRIES_BY_LOCALE.get(locale);
}
}

Effectively fails silently; when there is no country for that locale in
the map, the customer gets a null country, and the code continues.
Later, at some distant point in the code, things go tits-up because of
that null country. Yes, you could add a null check in the constructor,
but that's an extra line of code that has to be remembered to be
written. Because Map.get fails silently, it has to be written *every*
time that method is called! If Map.get threw an exception on a missing
key, it would be much harder to ignore - it would take active work to
write a catch-and-ignore.


Horrible!

The Right Thing to do would be to have two methods, get (which throws an
exception) and getIfPresent (which returns null). Or get(K), and get(K,
V), where the second version takes a default value to return if the key
isn't in the map - often much more useful than a null return. Of course,
this is a change which would be impossible to retrofit, because it would
break existing code - this would have to have been done when Map was
first written. But then, any change to the semantics of Map.get at this
point falls foul of the same trap.


That's a good idea - it would be another Collections.somethingMap
method. The wrapper would probably have to disallow null values in order
to work efficiently. And you could have a Collections.defaultingMap
which does the return-a-default thing, althought the default would be
fixed per instance rather than per call.
The default-value "strategy" would have to be per instance, but the
actual value per key can be different. This is often very useful:

public class LazyMap<K, V> implements Map<K, V> {
private final Map<K, V> backingMap;
private Factory<K,V> valueFactory;

// Delegate to backingMap, but call valueFactory.create(key) when
// key not found in backing map.
}

As for "get", I always thought it would be more useful to have get
return an Entry object, or to at least have a getEntryFor() method.
 
K

Karl Uppiano

Lew said:
Then no one would handle it.


This is only the tip of the iceberg when it comes to incorrect thread
programming.


These folks have obviously not read and assimilated /Java Concurrency in
Practice/ by Brian Goetz, et al.

Making 'InterruptedException' runtime would not have helped; indeed, it
would have exacerbated the problem. People would have learned the hard
way that they were getting the exception, then still handled it
incorrectly.

Face it, Java is a language that must be studied, and it must be learned.
Some of the problems it solves, such as multi-threaded programming, are
inherently hard. The language cannot make the problem easier; the best it
can do is not make it any harder.

The point of making an exception checked or not is not to prevent abuse of
the exception. Nothing but care by the practitioner can do that. The
point of making an exception checked is to identify methods that
intentionally throw that exception, and force their clients to deal with
it with a compile-time check. Forcing clients to deal with the exception
correctly is something that Java as a language cannot do.

Give us smarter programmers, not a smarter programming language.

I get all that. I know why we have runtime exceptions and I know why we have
checked exceptions. Sometimes exceptions fall into a gray area as to whether
it should be checked or unchecked, and I think InterruptedException falls
into that category, and I would have preferred that it was tossed into the
unchecked bucket. I have my reasons. I don't expect to convince you
differently. I’m just talking here.

But given the number of designs in which threads are interrupted (quite rare
in my experience -- I have seen it legitimately and brilliantly done exactly
once in 15 years of programming in Java), there seems to be quite a lot of
bad code written to handle that very rare exception. If someone calls
Thread.interrupt, they know what is going to happen, and they will design
their thread to deal properly with InterruptedException, whether it is
checked or not.

On the other hand, if I designed the thread, and I just want to wait -- I
know whether I’m calling Thread.interrupt, and it would be extremely
unexpected for someone else to call it unless I made the thread object
available to them. If such a runtime InterruptedException popped up after
all that, then I would say that a serious design review is in order.
 
K

Karl Uppiano

Joshua Cranmer said:
Programmer stupidity is not a good reason to make a checked exception a
runtime exception. The entire point of checked exceptions it that it
forces programmers to deal with potentially dangerous situations in some
manner; if programmers choose to deal with them idiotically, they're just
opening themselves up to a world of hurt.

If someone is eating InterruptedExceptions, he or she probably doesn't
know what that exception means. In that case, there are likely much larger
multithreading bugs in the same code.

Ok, but all engineering is a compromise. IME, threads are rarely
interrupted, but every wait requires a handler for the InterruptedException.
It is the frequency of the need to wait vs. the infrequency of actually
encountering the InterruptedException that I think makes it a better
candidate for a runtime exception. I believe this was the rationale for
making some other exception types unchecked. As it is, InterruptedException
is usually more of an annoyance, and programmers just eat it to shut up the
compiler. I know it isn't the right thing to do, but it gets done. I have
seen it done all too often. If it were a runtime exception, it would just
fly out to the run method. I usually have a guard handler up there for
unexpected exceptions like this, where I generally shut down gracefully.
Runtime exceptions would get caught there. If I'm really doing something in
my design that involves interrupting threads, I could catch it without it
having to be a checked exception.

I'm not being frivolous here. This is the only exception that I have
encountered so far that I think would have been better classified as a
runtime exception.

When you need to wait, and must now handle the InterruptedException, what do
you do with it?
 
A

Alan Gutierrez

Ok, but all engineering is a compromise. IME, threads are rarely
interrupted, but every wait requires a handler for the InterruptedException.
It is the frequency of the need to wait vs. the infrequency of actually
encountering the InterruptedException that I think makes it a better
candidate for a runtime exception.

Apparently, the JSR-166 crew agreed. You can choose between Lock.lock
() and Lock.lockInterruptably() because as many have said,
interrupting a thread is something that you need to consider
carefully.
When you need to wait, and must now handle the InterruptedException, what do
you do with it?

Oh, something frivolous, I suppose. Following the guiding principle of
checked exceptions, IntertuptedException is saying, how do you plan to
handle someone calling interrupt on your thread? If you didn't design
for it, then tell the caller as much.

You can wrap it in an Error with a message that says, "Not designed
for interruption."

If your thread is not part of an API, then maybe you can use the new
Lock class and avoid having to test for yourself that which will never
happen.

Checked exceptions are always a source of contention, though. It gets
into an older argument. Whether or not it should be checked or
unchecked is an unwinnable argument of Java. I agree with you Karl
that this is a gray area for checked and unchecked.

I agree with the other people in the thread who've said that making
InterruptedException checked has not forced people to correctly use
concurrency. If you spawn threads you have no intention of
interrupting, then how do you handle an interrupt? The same way you
handle an NPE. Why not force programmers to handle OutOfMemory by
making that a checked exception? I disagree that making
InterruptedException a checked exception has somehow made people
better concurrent programmers.

Seems to me that the documentation around Lock provides a better API
around interruptibility.

Alan Gutierrez - (e-mail address removed) - http://blogometer.com
 
E

EJP

Roedy said:
It may be too late now, but it would be nice if some exceptions were
renamed and the old names deprecated.

Well of course it's too late. What about binary compatibility?
NullPointerException : We Javites make such a production of the fact
Java has no pointers, just references.

The JLS doesn't.
This should be called NullReferenceException.

A reference is defined in the JLS as a non-null pointer. So
NullReferenceException would be a contradiction in terms.
 

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,066
Latest member
VytoKetoReviews

Latest Threads

Top