Why does Java require the throws clause? Good or bad language design?

L

Lew

Robbert said:
In particular, if you want the commonly useful behavior that any
exception should propagate up the call chain until it is handled, and if
it is not handled otherwise, the program should abort with an error
message, you still have to write "throws Exception" and a try ... catch
block (or, alternatively, convert checked exceptions to unchecked
exceptions at some point).

Not true. If you want to throw an exception that behaves as you describe,
simply throw an unchecked exception and handle it farther up the chain, just
as you say you want. No "mandatory throws clause" needed.

Of course, then you sacrifice the benefits of checked exceptions, but that is
your absolute right as a designer.

If someone else wrote a method with a checked exception that you want to use,
then that programmer is the one requiring you to handle the exception, not
Java, the language itself. That means that that programmer thought about their
API and decided that the exception was important enough to warrant mandatory
handling on the part of all the API's consumers.

Don't blame the language for the programmer's decision. They could have used
an unchecked exception but chose instead to declare a checked one. That is the
power of choice that Java gave them.

- Lew
 
R

Robbert Haarman

?

The very definition of a "checked" exception is one that must be declared
in the throws clause of the method that throws it.

Consider this quote from
<http://www.developer.com/java/article.php/1455891>:

<quote>
Checked exceptions

All exceptions instantiated from the Exception class, or from subclasses of
Exception other than RuntimeException and its subclasses must either be:

* Handled with a try block followed by a catch block, or
* Declared in a throws clause of any method that can throw them

Well, of course. But we are discussing whether or not that latest point
is good language design. So, I assumed that, for purposes of this
discussion, a checked exception is one that must be handled explicitly
by the program (i.e. by a catch block). This can certainly be
accomplished without requiring the exception to be mentioned in any
throws clause.

Regards,

Bob
 
L

Lew

Robbert said:
This gets to the heart of what I think really is wrong with Java's
exceptions (and, in a wider sense, the whole language). I would say the
exceptions that can or cannot be usefully handled depend on the specific
case. Yet, the list of exceptions that your program must handle (as well
as the list of exceptions it does not have to handle explicitly) has
been hardcoded into the language by the designers, in their wisdom.

I am sure that having the compiler check that certain conditions are
accounted for is a good idea. I am not so sure that hardcoding the
(essentially arbitrary) list of exceptions the compiler will do this
for, and forcing that list on every program, is a good idea.

You have an interesting idea of "hard coded". The Exceptions that Java
provides are by no means exhaustive, nor mandatory. You can derive your own,
or choose not to use any of the library Exceptions, just like you are not
required to use any other part of the APIs.

Do you object to the presence of the substring() method in java.lang.String
just because you don't always use it?

It is the nature of APIs, especially ones as robust and comprehensive as the
ones Java offers, to have more than you need, but there are no "API police"
running around forcing you as a programmer to use this method or that Exception.

It is the nature of an API to provide more than any one programmer or project
needs at a time, if it is a good API. Complaining that an API provides things
you personally don't need is actually complaining about a strength of the API.

What you characterize as something "wrong" with Java is simply a choice that
one need not make in Java at all. When someone does choose to use that part of
the API, then clearly that programmer found value in it and is thanking Sun
for having provided it.

- Lew
 
L

Lew

Robbert said:
Well, of course. But we are discussing whether or not that latest point
is good language design. So, I assumed that, for purposes of this
discussion, a checked exception is one that must be handled explicitly
by the program (i.e. by a catch block). This can certainly be
accomplished without requiring the exception to be mentioned in any
throws clause.

Yes, you are right, by throwing an unchecked exception, which Java allows.

My point is that Java allows the programmer the choice of throwing arbitrary
exceptions that the API client need not catch, but may simply crash in the
face thereof, just as you say you want a language to allow. Ergo, nothing
wrong with Java.

Likewise, when the programmer wants to require handling of a certain
exception, they can declare a checked exception, thereby strenghthening the
API by making sure at compile time its clients will not be fubared by an
unexpected exception. So for times when checked exceptions are better, Java
allows that, too. Ergo, nothing wrong with Java.

Since the throws clause is not mandatory, the conclusion that a mandatory
throws clause makes Java bad must be false.

- Lew
 
R

Robbert Haarman

Not true. If you want to throw an exception that behaves as you describe,
simply throw an unchecked exception and handle it farther up the chain,
just as you say you want. No "mandatory throws clause" needed.

Yes, of course. If you write the code, you can write whatever you want,
including code that never throws any exceptions at all. However, that is
not the situation I was referring to. I meant the case where you use an
existing method which could throw an exception.

For example, and I apologize in advance if I don't get the details
exactly right, if you were to write a program that read a file and wrote
its contents to standard output, you could write the following:

public void passThroughStream(InputStream is, OutputStream os) {
// some code to read from the input stream and write to
// the output stream, which could throw IOException
}

public void passThroughFile(String name, OutputStream os) {
// open the file and call passThroughStream
}

public static void main(String args[]) {
passThroughFile(args[0], System.out);
}

However, this code would not work, because the IOException is not
handled. If you want the exception to propagate up the call chain and
eventually abort the program with an error message, you would need to
add throws clauses to both passThrough* methods, and a try ... catch
block to main, or convert the IOException to an unchecked exception;
precisely as I said.

Regards,

Bob
 
R

Robbert Haarman

Yes, you are right, by throwing an unchecked exception, which Java allows.

No, that's not the same. An unchecked exception is one that the program
is not required to handle explicitly. What I am talking about is an
excetion which the program _is_ required to handle explicitly. I am
saying this requirement can be enforced without requiring methods that
propagate the exception up the call chain to list the exception in a
throws clause.

For example, if I write:

public void foo() {
// call something that could throw an IOException
}

public void bar() {
// call foo
}

public static void main(String arg[]) {
bar();
}

Even though I have not written "throws IOException", the compiler can
infer that foo and bar can throw this exception, and that the program
does not catch that exception. If IOException is one that must be
handled (what I have called a checked exception), the compiler can
reject the program. Thus, exceptions that a program is required to
handle can exist without the throws clause. This is the point I was
trying to make earlier.

Regards,

Bob

--
Using a (signed) 64-bit value introduces a new wraparound date in about
290 billion years, on Sunday, December 4, 292,277,026,596. However, this
problem is not widely regarded as a pressing issue.

-- Wikipedia, Year 2038 Problem
 
R

Robbert Haarman

Robbert Haarman wrote:

You have an interesting idea of "hard coded".

I simply meant that every exception derived from one class (I think
Exception) is a checked exception, and every exception derived from
another class (I think Error) is an unchecked exception. There is
(AFAIK) no way to influence the compiler's behavior after the decision
about which class to derive the exception from has been taken.

Such a way would be useful. For example, to write more robust code, it
could be useful to be able to tell the compiler that a certain program
or snippet of code must catch all exceptions, no matter their base
class.
What you characterize as something "wrong" with Java is simply a choice
that one need not make in Java at all. When someone does choose to use that
part of the API, then clearly that programmer found value in it and is
thanking Sun for having provided it.

Thanking Sun for providing something is different from saying it is
perfect.

Regards,

Bob
 
L

Lew

Robbert said:
Yes, of course. If you write the code, you can write whatever you want,
including code that never throws any exceptions at all. However, that is
not the situation I was referring to. I meant the case where you use an
existing method which could throw an exception.

For example, and I apologize in advance if I don't get the details
exactly right, if you were to write a program that read a file and wrote
its contents to standard output, you could write the following:

public void passThroughStream(InputStream is, OutputStream os) {
// some code to read from the input stream and write to
// the output stream, which could throw IOException
}

public void passThroughFile(String name, OutputStream os) {
// open the file and call passThroughStream
}

public static void main(String args[]) {
passThroughFile(args[0], System.out);
}

However, this code would not work, because the IOException is not
handled. If you want the exception to propagate up the call chain and
eventually abort the program with an error message, you would need to
add throws clauses to both passThrough* methods, and a try ... catch
block to main, or convert the IOException to an unchecked exception;
precisely as I said.

But this is not a Java issue, it is a design issue with the method that
declares that it throws the IOException. That is something that the designer
of that method put in for a reason. Mainly, it alerts you at compile time that
you have handled those things in the method that can be handled, or not.

That is a good thing, for that method with that particular exception. It is
the API designer's way of helping you. It says nothing about whether checked
exceptions /per se/ are a good thing, unless you agree with me that this
particular use actually helps the user of the API and that therefore the fact
that Java allowed the API designer to do it is also a good thing.

Discussion of whether checked exceptions are a "good" or "bad" feature of Java
does not depend on how one specific API call uses the feature, but on whether
the feature helps programmers and fails to hinder them.

As to whether a particular checked exception is "good" or "bad" for, say, a
Reader.read() call, that is a different matter. I think that the declaration
in the throws clause really helps the API consumer to be thorough in handling
what can go wrong.

In any event, just because one particular method uses a throws clause doesn't
make the throws clause itself mandatory in the language. It is a feature that
some programmer chose to use, just like you can when it's your API to write.

- Lew
 
A

Arthur J. O'Dwyer

No, there isn't any contract between these two.

catcher calls higherLevel, so one contract is between catcher and
higherLevel.

higherLevel calls cbf, so there's another contract: between
higherLevel and cbf.

FWIW, you're wrong. The "contract" is obviously between the main
function 'catcher' and its helper function 'callbackFunc'. Now, I'll
agree that Java does not let us /express/ that contract; but that's
not the same thing as its not existing in the first place.
Now, let's reformulate your code in Java:

interface CBF {
public void execute(int x);
}

public void higherLevel( CBF cbf, int arr[] ) {
for ( int i = 0; i < arr.length; i++ )
cbf.execute(arr);
}

public void catcher() {
int arr[] = new int[]{1,2,3,42,5};
higherLevel( callBackFunc, arr );
}

There are two things to mention:

1. callBackFunc is not defined, yet.

2. If one looks at CBF one can see the obvious contract that must be
fullfilled when calling or *implementing* CBF#execute:
- the caller must provide one argument of type int.
- execute does not throw a checked exception.


3. 'catcher' doesn't contain a 'catch' clause, which makes its
name misleading at best. ;)
Now, let's implement CBF:

CBF callBankFunc = new CBF() {
public void execute( int x ) {
if ( x == 42 )
throw new Exception();
}
};

This would lead to a compile-time error since the CBF promises that there's
no checked exception when 'execute' gets called.

Okay, so you can't do it that way.
If you really want to throw an exception, there are two ways. Either throw
an unchecked exception

"Unchecked exception" being the Java equivalent of C++'s exceptions,
right? That is, they behave the same way as checked exceptions, but you
don't have to declare them in exception specifications.
http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html
or if you a checked exception should be thrown,
declare it in CBF#execute's throws-clause.

That would be nice, but you just said that Java won't allow you to
do that. ("This would lead to a compile-time error ...") Unless of
course you propagate the exception specification all the way up into
'higherLevel', which would mean no code reuse in the presence of
checked exceptions.

It sounds like Java indeed has not yet found a magic bullet for
statically analyzing exception-handling. Not that there's anything wrong
with that. But it does mean that the comp.lang.misc discussion, which
is basically a search for a magic bullet, isn't totally pointless. Now
if only I can get the crosspost to c.l.m right this time...

-Arthur
 
L

Lew

Robbert said:
Even though I have not written "throws IOException", the compiler can
infer that foo and bar can throw this exception, and that the program
does not catch that exception. If IOException is one that must be
handled (what I have called a checked exception), the compiler can
reject the program. Thus, exceptions that a program is required to
handle can exist without the throws clause. This is the point I was
trying to make earlier.

I see what you mean.

If I understand you correctly, the complaint with Java is the notational
overhead of actually having to put the words "throws Blah" in the method
signature.

I think that the "self-documentation" feature of those words would offset the
overhead for many programmers, myself included, but I agree that those words
are overhead. You are most likely correct that some Java-like language could
have checked exceptions in the way that you describe.

There is a purpose for that overhead in Java. The question boils down to
whether the purpose is sufficient to justify the overhead. You think it is
not. I respect that.

- Lew
 
G

Guest

Robbert said:
No, that's not the same. An unchecked exception is one that the program
is not required to handle explicitly. What I am talking about is an
excetion which the program _is_ required to handle explicitly. I am
saying this requirement can be enforced without requiring methods that
propagate the exception up the call chain to list the exception in a
throws clause.

For example, if I write:

public void foo() {
// call something that could throw an IOException
}

public void bar() {
// call foo
}

public static void main(String arg[]) {
bar();
}

Even though I have not written "throws IOException", the compiler can
infer that foo and bar can throw this exception, and that the program
does not catch that exception. If IOException is one that must be
handled (what I have called a checked exception), the compiler can
reject the program. Thus, exceptions that a program is required to
handle can exist without the throws clause. This is the point I was
trying to make earlier.

That only work for toy examples.

main, bar and foo may be in different files.

Different projects/libraries.

Arne
 
R

Robbert Haarman

Robbert said:
No, that's not the same. An unchecked exception is one that the program
is not required to handle explicitly. What I am talking about is an
excetion which the program _is_ required to handle explicitly. I am
saying this requirement can be enforced without requiring methods that
propagate the exception up the call chain to list the exception in a
throws clause.

For example, if I write:

public void foo() {
// call something that could throw an IOException
}

public void bar() {
// call foo
}

public static void main(String arg[]) {
bar();
}

Even though I have not written "throws IOException", the compiler can
infer that foo and bar can throw this exception, and that the program
does not catch that exception. If IOException is one that must be
handled (what I have called a checked exception), the compiler can
reject the program. Thus, exceptions that a program is required to
handle can exist without the throws clause. This is the point I was
trying to make earlier.

That only work for toy examples.

main, bar and foo may be in different files.

Different projects/libraries.

Yes, but what is the problem with that? As far as I know, there is
nothing preventing the compiler from putting exception information in
the class files. Once the information about which exceptions a method
can throw has been inferred, it can be treated exactly the same way Java
now treats the information in throws clauses.

Regards,

Bob
 
G

Guest

Robbert said:
This gets to the heart of what I think really is wrong with Java's
exceptions (and, in a wider sense, the whole language). I would say the
exceptions that can or cannot be usefully handled depend on the specific
case.

What can the code do in case of a OutOfMemoryError ?

Errors are intended for the not able to be handled in any case.
Yet, the list of exceptions that your program must handle (as well
as the list of exceptions it does not have to handle explicitly) has
been hardcoded into the language by the designers, in their wisdom.

Not at all. Everyone can and should create their own exceptions.
I am sure that having the compiler check that certain conditions are
accounted for is a good idea. I am not so sure that hardcoding the
(essentially arbitrary) list of exceptions the compiler will do this
for, and forcing that list on every program, is a good idea.

The programmer writing a method has the ability to declare the method
with a throws that forces the programmer using the method to do
something to handle it.

If the first programmer does not like it, then he just use unchecked
exceptions.

If the second programmer does mot like it, then he will have to find
a library with an API he likes better.
The problem is that neither Java, nor many of its adherents will let you
get away with that. Java won't, because many exceptions are already hard
coded to be checked exceptions. It's adherents won't, because they
consider unchecked exceptions bad style. And they have a point: it's not
the Java Way, and thus, if you are programming in Java, it is not what
you should do.

SUN developers has been using checked exceptions. But it is rather
universal that if you are using a library, then you must live with
the API provided by those creating the library.

Arne
 
G

Guest

Robbert said:
I simply meant that every exception derived from one class (I think
Exception) is a checked exception, and every exception derived from
another class (I think Error) is an unchecked exception.

RuntimeException.

Error are a third category. But less relevant since your code should not
throw errors or handle errors.
There is
(AFAIK) no way to influence the compiler's behavior after the decision
about which class to derive the exception from has been taken.

They needed to mark the difference in some way. Annotations were
not invented in Java 1.0.
Such a way would be useful. For example, to write more robust code, it
could be useful to be able to tell the compiler that a certain program
or snippet of code must catch all exceptions, no matter their base
class.

I do not think that will work well with the Java compile model. Some
of the code may have been compiled by someone else.

Arne
 
G

Guest

Robbert said:
Yes, but what is the problem with that? As far as I know, there is
nothing preventing the compiler from putting exception information in
the class files. Once the information about which exceptions a method
can throw has been inferred, it can be treated exactly the same way Java
now treats the information in throws clauses.

Oh, so you do want throws in the class files - you just don't want
it the source code ?

Arne
 
L

Lew

That would be nice, but you just said that Java won't allow you to
do that. ("This would lead to a compile-time error ...")

That is not what he said. In fact, he said the exact opposite.

He said the error would come from NOT declaring the checked exception in the
signature. That error would be fixed if CBF and its implementors declared the
exception for the method.
CBF callBankFunc = new CBF() {
public void execute( int x ) {
if ( x == 42 )
throw new Exception();
}
};

This is what Michael said would cause a compiler error if execute() did not
declare the Exception in its signature.
interface CBF {
public void execute(int x) throws Exception;
}

This is what Michael said would allow the implementing class to throw that
checked Exception, because now it is part of the signature. (The implementing
class would also need to include the throws clause in its signature in order
to throw the checked Exception, because it is part of the signature just like
the int argument is.)

- Lew
 
C

Chris Smith

Chris Uppal said:
I agree that there is a contract there (or damn well should be one ;-) But I
don't think it's between the caller and callee -- it seems to me that the
contact (formal or informal) is between the operation, and the handler for any
errors. Java insists on treating every method call as if the caller and callee
were the two principles in that relationship -- and they aren't necessarily,
which is what causes these difficulties.

I'll stick with the original statement. All contracts are between the
caller and the callee. For example, in Arthur O'Dwyer's example, there
is certainly a contract between 'catcher' and 'higherLevel' -- namely,
that 'higherLevel' will throw only those checked exceptions that may be
thrown by the function being passed as its first argument. It would not
be acceptable for 'higherLevel' to throw an IOException on the side, for
example, if that's not expected by 'catcher'.

I'm having trouble assigning meaning to the statement that there's a
contract between a function and the code that handles its errors. The
whole point is to try to use the contract to guarantee that, in fact,
the error handler exists. The error handler can't be a party to such a
contract unless you guarantee that it exists in some other way.
My own suggestion in this area (you'll have to check Google if you're
interested) was a very pragmatic (read: "very hacky") half-way house, in which
the user of an object has some small choice in /what/ contract is statically
enforced.

I'm afraid my Google-zen is failing me on that one. I can sort of
imagine what you may be thinking, though. I agree that a general
solution will need to be flexible and allow people to make these
decisions on a case-by-case basis; that is, there is no magical answer
that will satisfy all needs. I assume that by giving choice to the
"user", you intend to avoid situations like on one hand the
NumberFormatException dilemma, and on the other hand the close() throws
IOException issue; where it seems obvious in retrospect that the wrong
decisions were made, but the choices about strictness of enforcement are
enshrined in library design?
 
R

Robbert Haarman

What can the code do in case of a OutOfMemoryError ?

It depends, and that is the point I was trying to make. In some cases,
the only thing that can be done is to abort the whole program (and, if
possible, print an error message). In other cases, only the current
operation needs to be aborted, and the rest of the program may be able
to recover from that.
Errors are intended for the not able to be handled in any case.

And yet I can come up with scenarios in which they can sensibly be
handled.
Not at all. Everyone can and should create their own exceptions.

Since it seems to have confused a number of people, perhaps I did not
word my statement right. What I meant is that, for the exception classes
that have already been defined, and the methods that use them, you
cannot control which ones the compiler requires you to handle
explicitly. Each time a method (defined by someone else) claims it can
throw an IOException, you _must_ handle it explicitly. Never will the
compiler complain if you fail to explicitly handle an OutOfMemoryError.
These are decisions that have been made for you and you cannot change
them, even though, in the program you are writing, different behaviors
may make more sense.
The programmer writing a method has the ability to declare the method
with a throws that forces the programmer using the method to do
something to handle it.

Exactly. And I am asking people to consider whether the first programmer
is in the right position to make that decision.
If the first programmer does not like it, then he just use unchecked
exceptions.

True. However, I have done this and be criticized for it, because it is
not the canonical way to do things in Java. As said before, you are
expected to use checked exceptions in some cases. If you don't, you
violate people's expectations. Also, you will run into cases where one
of the standarh exception classes would be the right choice. You don't
have any choice about whether that class is checked or unchecked.
If the second programmer does mot like it, then he will have to find
a library with an API he likes better.

Of course. I've found that API by using a different language than Java.

Regards,

Bob
 
B

Bent C Dalager

Such a way would be useful. For example, to write more robust code, it
could be useful to be able to tell the compiler that a certain program
or snippet of code must catch all exceptions, no matter their base
class.

This would seem to make the program less robust in many interesting
cases. For example, let us say that you have written a program that
uses a number of interfaces to access interesting functionality. When
the time comes to deploy the program, it turns out that on some
platforms it refuses to run because the interface implementations on
those platforms happen to use arrays and your compiler never
considered that the methods in question might throw
ArrayIndexOutOfBoundsException because the implementations you worked
with didn't use arrays at all. You therefore never wrote a catch
clause for those exceptions (since your compiler didn't require you to
and you didn't think to do it) and so your program is invalid in this
particular setting.

It would also be somewhat tedious to _have_ to handle the possibility
of a NullPointerException on almost every single line of source code.

Cheers
Bent D
 
R

Robbert Haarman

Oh, so you do want throws in the class files - you just don't want
it the source code ?

In short, yes.

The class files should contain whatever is necessary to make things
work. If that includes some sort of throws clause (which I think it
must, in order to support exceptions that must be handled explicitly),
then that is fine with me.

Now, the source code is different, because the source code is what I
have to type in. Mandating (for exceptions that must be handled
explicitly) throws clauses in the source code has an affect (which I
believe to be net negative) on programmer productivity.

Lew has the right of it: the throws clause (in the source code)
represents a trade-off. Clearly, some people prefer the trade-off to me
made one way, and other people prefer it to made the other way.

What I said about the compiler being able to verify that exceptions are
handled by the program without requiring throws clauses means that this
verification is not part of the trade-off. As far as I can see, the
trade-off is between the amount of code that needs to be written,
maintained, and modified, and having a bit of extra information in the
source code (rather than, say, in the documentation). I will also note
that (as has been stated in this thread), the throws clause can be out
of sync with what exceptions can _really_ be thrown. If, instead, the
list of exceptions that can be thrown is inferred, it will always be
correct.

Regards,

Bob
 

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

No members online now.

Forum statistics

Threads
474,266
Messages
2,571,081
Members
48,772
Latest member
Backspace Studios

Latest Threads

Top