Related
I am checking out the new features of Java SE7 and I am currently at this point:
http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html
regarding the catch multiple feature, when I came across this statement:
Note: If a catch block handles more than one exception type, then the
catch parameter is implicitly final. In this example, the catch
parameter ex is final and therefore you cannot assign any values to it
within the catch block.
I never noticed that the caught exception is not final in the classic case of handleing caught exceptions.
I just wonder why is that a good thing in the first place? Would it not be ill-advised to essentially MODIFY a caught exception before I guess rethrowing it or maybe logging it's message? Should it not be up to the trowing mechanism to create the exception so it represents exactly what it should?
I have never seen an exception being modified in the catch block can maybe someone point out it's benefits?
It's pretty much the same as method arguments:
You usually don't modify them and many people agree that they should be treated as final (whether or not to actually write final in front of them is a matter of some debate).
But since there's no technical requirement that says it must be final, the language gives you the option to choose.
Personally I know of no good reason to modify the exception reference of a catch-block.
I cannot think of a convincing use-case for modifying an exception in a classic catch clause. However, that doesn't mean it should be forbidden. Especially given that you can modify a parameter variable. If you find this worrisome, you have the option of declaring the exception variable to be final.
On the other hand, allowing modification in the multi-exception catch would introduces the possibility of truly bizarre and confusing code such as this:
catch (IOException | NullPointerException ex) {
...
ex = new IllegalArgumentException(...);
}
I imagine that's what the designers had in mind when they added the restriction in this case.
But either way, this is how the Java language is defined, and what we have to live with. There's not a lot of point in debating the apparent inconsistencies ... unless you are intending to design and implement a new language.
The reason I can think of to enforce it final is due to performance. Once the catch evaluation starts, having a final immutable value in the mechanics of the evaluation ensures a faster evaluation of all catches. Since try-catch is extensively used throughout any java code, the highest performance design is preferable.
Based on the above, it implies a performance improvement that affects most programs.
The idea behind exception-based error handling is that each error should be recovered, if at all possible, at the appropriate level of abstraction. Such error recovery might require information that is not directly available where the exception is actually handled. For this reason it might be convenient to catch the exception, augment it with the relevant information and rethrow it or possibly set it as cause of a new exception object of a more appropriate class.
How is exception handling implemented in higher-level programming languages (like Java)? By this, I don't mean how to use exceptions within a language; I mean how the compiler generates code (assembly, or some intermediate, like Java byte code) that we recognize as exception-handling, because in the end, the computer can execute only instructions; Everything of a higher-level must be comprised of those instructions.
In C, before exceptions existed, you would return an error code, but if a function already returns something, then what? Perhaps return a structure of both the error code and the real result?
The compiler outputs an athrow instruction (JVM Specification) at the throw site, and an Exceptions attribute (#4.7.5) in the code of the method that shows where all the various catch clauses are, what range of instructions they cover, and what exception types they catch.
This came up in a discussion with a colleague today.
The Javadocs for Java's IllegalStateException state that it:
Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
And Effective Java says (Item 60, page 248):
Another commonly reused exception is IllegalStateException. This is generally the exception to throw if the invocation is illegal because of the state of the receiving object. For example, this would be the exception to throw if the caller attempted to use some object before it had been properly initialized.
It seems there's a bit of discrepancy here. The second sentence of the javadocs makes it sound like the exception could describe a very broad condition about the Java execution state, but the description in Effective Java makes it sound like it's used for conditions related specifically to the state of the state of the object whose method has been called.
The usages I've seen in the JDK (e.g. collections, Matcher) and in Guava definitely seem to fall into the category that Effective Java talks about ("This object is in a state where this method can't be called"). This also seems consistent with IllegalStateException's sibling IllegalArgumentException.
Are there any legitimate IllegalStateException usages in the JDK that do relate to the "Java environment" or "Java application"? Or do any best practices guides advocate using it for the broader execution state? If not, why the heck are the javadocs phrased like that? ;)
Here is one particularly legitimate usage of this exception in JDK (see: URLConnection.setIfModifiedSince(long) among 300+ other usages of it:
public void setIfModifiedSince(long ifmodifiedsince) {
if (connected)
throw new IllegalStateException("Already connected");
ifModifiedSince = ifmodifiedsince;
}
I think the example is pretty clear. If the object is in particular state ("Already connected"), some operations should not be called. In this case when connection was established, some properties cannot be set.
This exception is especially useful when your class has some state (state machine?) that changes over time, making some methods irrelevant or impossible. Think about a Car class that has start(), stop() and fuel() methods. While calling start() twice, one after another, is probably nothing wrong, but fueling a started car is certainly a bad idea. Namely - car is in a wrong state.
Arguably good API should not allow us to call methods in wrong state so that problems like that are discovered at compile time, not at runtime. In this particular example connecting to a URL should return a different object with a subset of methods, all of which are valid after connecting.
Here is an example in the JDK. There is a package private class called java.lang.Shutdown. If the system is shutting down and you attempt to add a new hook, it throws the IllegalStateException. One could argue that this meets the criteria of the "javadoc" guidance - since it is the Java environment that is in the wrong state.
class Shutdown {
...
/* Add a new shutdown hook. Checks the shutdown state and the hook itself,
* but does not do any security checks.
*/
static void add(int slot, Runnable hook) {
synchronized (lock) {
if (state > RUNNING)
throw new IllegalStateException("Shutdown in progress");
if (hooks[slot] != null)
throw new InternalError("Shutdown hook at slot " + slot + " already registered");
hooks[slot] = hook;
}
}
However it also illustrates that there really is no distinction between the "javadoc" guidance and the "Effective Java" guidance. Because of the way Shutdown is implemented, the shutdown-ness of the JVM is stored in a field called state. Therefore it also meets the "Effective Java" guidance for when to use IllegalStateException, since the "state" field is part of the state of the receiving object. Since the receiving object (Shutdown) is in the wrong state, it throws the IllegalStateException.
In my opinion the two descriptions of when to use IllegalStateException are consistent. The Effective Java description is a bit more practical, that's all. For most of us, the most important part of the entire Java environment is the class that we are writing right now, so that is what the author is focusing on.
I guess if you see usage of IllegalStateException I would say second if more appropriate. This exception is used in lot of packages
java.net
java.nio
java.util
java.util.concurrrent etc
To specify one example ArrayBlockingQueue.add throws this exception if queue is already full. Now full is state of the object and it is being invoked at inappropriate or Illegal time
I guess both means same but difference of wording.
Given a library, it should throw an IllegalStateException or IllegalArgumentException whenever it detects a bug due to the user code, whereas the library should throw an AssertionError whenever it detects a bug due to the library's own implementation.
For example, in the library's tests, you may expect the library throws an IllegalStateException when the order of method calls are wrong. But you will never expect the library throws an AssertionError.
There is no 'discrepancy' here. There is nothing in Bloch's wording that excludes what it says in the JLS. Bloch is simply saying that if you have circumstance A, throw this exception. He is not saying that this exception is/should be thrown only in this condition. The JLS is saying this exception is thrown if A, B, or C.
I ran into this with:
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
...
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
I think it will be impractical for me to throw IllegalStateException here in place of AssertionException even though this falls into the "the Java environment" category.
I often find when debugging a program it is convenient, (although arguably bad practice) to insert a return statement inside a block of code. I might try something like this in Java ....
class Test {
public static void main(String args[]) {
System.out.println("hello world");
return;
System.out.println("i think this line might cause a problem");
}
}
of course, this would yield the compiler error.
Test.java:7: unreachable statement
I could understand why a warning might be justified as having unused code is bad practice. But I don't understand why this needs to generate an error.
Is this just Java trying to be a Nanny, or is there a good reason to make this a compiler error?
Because unreachable code is meaningless to the compiler. Whilst making code meaningful to people is both paramount and harder than making it meaningful to a compiler, the compiler is the essential consumer of code. The designers of Java take the viewpoint that code that is not meaningful to the compiler is an error. Their stance is that if you have some unreachable code, you have made a mistake that needs to be fixed.
There is a similar question here: Unreachable code: error or warning?, in which the author says "Personally I strongly feel it should be an error: if the programmer writes a piece of code, it should always be with the intention of actually running it in some scenario." Obviously the language designers of Java agree.
Whether unreachable code should prevent compilation is a question on which there will never be consensus. But this is why the Java designers did it.
A number of people in comments point out that there are many classes of unreachable code Java doesn't prevent compiling. If I understand the consequences of Gödel correctly, no compiler can possibly catch all classes of unreachable code.
Unit tests cannot catch every single bug. We don't use this as an argument against their value. Likewise a compiler can't catch all problematic code, but it is still valuable for it to prevent compilation of bad code when it can.
The Java language designers consider unreachable code an error. So preventing it compiling when possible is reasonable.
(Before you downvote: the question is not whether or not Java should have an unreachable statement compiler error. The question is why Java has an unreachable statement compiler error. Don't downvote me just because you think Java made the wrong design decision.)
There is no definitive reason why unreachable statements must be not be allowed; other languages allow them without problems. For your specific need, this is the usual trick:
if (true) return;
It looks nonsensical, anyone who reads the code will guess that it must have been done deliberately, not a careless mistake of leaving the rest of statements unreachable.
Java has a little bit support for "conditional compilation"
http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21
if (false) { x=3; }
does not result in a compile-time
error. An optimizing compiler may
realize that the statement x=3; will
never be executed and may choose to
omit the code for that statement from
the generated class file, but the
statement x=3; is not regarded as
"unreachable" in the technical sense
specified here.
The rationale for this differing
treatment is to allow programmers to
define "flag variables" such as:
static final boolean DEBUG = false;
and then write code such as:
if (DEBUG) { x=3; }
The idea is that it should be possible
to change the value of DEBUG from
false to true or from true to false
and then compile the code correctly
with no other changes to the program
text.
It is Nanny.
I feel .Net got this one right - it raises a warning for unreachable code, but not an error. It is good to be warned about it, but I see no reason to prevent compilation (especially during debugging sessions where it is nice to throw a return in to bypass some code).
I only just noticed this question, and wanted to add my $.02 to this.
In case of Java, this is not actually an option. The "unreachable code" error doesn't come from the fact that JVM developers thought to protect developers from anything, or be extra vigilant, but from the requirements of the JVM specification.
Both Java compiler, and JVM, use what is called "stack maps" - a definite information about all of the items on the stack, as allocated for the current method. The type of each and every slot of the stack must be known, so that a JVM instruction doesn't mistreat item of one type for another type. This is mostly important for preventing having a numeric value ever being used as a pointer. It's possible, using Java assembly, to try to push/store a number, but then pop/load an object reference. However, JVM will reject this code during class validation,- that is when stack maps are being created and tested for consistency.
To verify the stack maps, the VM has to walk through all the code paths that exist in a method, and make sure that no matter which code path will ever be executed, the stack data for every instruction agrees with what any previous code has pushed/stored in the stack. So, in simple case of:
Object a;
if (something) { a = new Object(); } else { a = new String(); }
System.out.println(a);
at line 3, JVM will check that both branches of 'if' have only stored into a (which is just local var#0) something that is compatible with Object (since that's how code from line 3 and on will treat local var#0).
When compiler gets to an unreachable code, it doesn't quite know what state the stack might be at that point, so it can't verify its state. It can't quite compile the code anymore at that point, as it can't keep track of local variables either, so instead of leaving this ambiguity in the class file, it produces a fatal error.
Of course a simple condition like if (1<2) will fool it, but it's not really fooling - it's giving it a potential branch that can lead to the code, and at least both the compiler and the VM can determine, how the stack items can be used from there on.
P.S. I don't know what .NET does in this case, but I believe it will fail compilation as well. This normally will not be a problem for any machine code compilers (C, C++, Obj-C, etc.)
One of the goals of compilers is to rule out classes of errors. Some unreachable code is there by accident, it's nice that javac rules out that class of error at compile time.
For every rule that catches erroneous code, someone will want the compiler to accept it because they know what they're doing. That's the penalty of compiler checking, and getting the balance right is one of the tricker points of language design. Even with the strictest checking there's still an infinite number of programs that can be written, so things can't be that bad.
While I think this compiler error is a good thing, there is a way you can work around it.
Use a condition you know will be true:
public void myMethod(){
someCodeHere();
if(1 < 2) return; // compiler isn't smart enough to complain about this
moreCodeHere();
}
The compiler is not smart enough to complain about that.
It is certainly a good thing to complain the more stringent the compiler is the better, as far as it allows you to do what you need.
Usually the small price to pay is to comment the code out, the gain is that when you compile your code works. A general example is Haskell about which people screams until they realize that their test/debugging is main test only and short one. I personally in Java do almost no debugging while being ( in fact on purpose) not attentive.
If the reason for allowing if (aBooleanVariable) return; someMoreCode; is to allow flags, then the fact that if (true) return; someMoreCode; does not generate a compile time error seems like inconsistency in the policy of generating CodeNotReachable exception, since the compiler 'knows' that true is not a flag (not a variable).
Two other ways which might be interesting, but don't apply to switching off part of a method's code as well as if (true) return:
Now, instead of saying if (true) return; you might want to say assert false and add -ea OR -ea package OR -ea className to the jvm arguments. The good point is that this allows for some granularity and requires adding an extra parameter to the jvm invocation so there is no need of setting a DEBUG flag in the code, but by added argument at runtime, which is useful when the target is not the developer machine and recompiling & transferring bytecode takes time.
There is also the System.exit(0) way, but this might be an overkill, if you put it in Java in a JSP then it will terminate the server.
Apart from that Java is by-design a 'nanny' language, I would rather use something native like C/C++ for more control.
I currently have a technical point of difference with an acquaintance. In a nutshell, it's the difference between these two basic styles of Java exception handling:
Option 1 (mine):
try {
...
} catch (OneKindOfException) {
...
} catch (AnotherKind) {
...
} catch (AThirdKind) {
...
}
Option 2 (his):
try {
...
} catch (AppException e) {
switch(e.getCode()) {
case Constants.ONE_KIND:
...
break;
case Constants.ANOTHER_KIND:
...
break;
case Constants.A_THIRD_KIND:
...
break;
default:
...
}
}
His argument -- after I used copious links about user input validation, exception handling, assertions and contracts, etc. to back up my point of view -- boiled down to this:
"It’s a good model. I've used it since me and a friend of mine came up with it in 1998, almost 10 years ago. Take another look and you'll see that the compromises we made to the academic arguments make a lot of sense."
Does anyone have a knock-down argument for why Option 1 is the way to go?
When you have a switch statement, you're less object oriented. There are also more opportunities for mistakes, forgetting a "break;" statement, forgetting to add a case for an Exception if you add a new Exception that is thrown.
I also find your way of doing it to be MUCH more readable, and it's the standard idiom that all developers will immediately understand.
For my taste, the amount of boiler plate to do your acquaintance's method, the amount of code that has nothing to do with actually handling the Exceptions, is unacceptable. The more boilerplate code there is around your actual program logic, the harder the code is to read and to maintain. And using an uncommon idiom makes code more difficult to understand.
But the deal breaker, as I said above, is that when you modify the called method so that it throws an additional Exception, you will automatically know you have to modify your code because it will fail to compile. However, if you use your acquaintance's method and you modify the called method to throw a new variety of AppException, your code will not know there is anything different about this new variety and your code may silently fail by going down an inappropriate error-handling leg. This is assuming that you actually remembered to put in a default so at least it's handled and not silently ignored.
the way option 2 is coded, any unexpected exception type will be swallowed! (this can be fixed by re-throwing in the default case, but that is arguably an ugly thing to do - much better/more efficient to not catch it in the first place)
option 2 is a manual recreation of what option 1 most likely does under the hood, i.e. it ignores the preferred syntax of the language to use older constructs best avoided for maintenance and readability reasons. In other words, option 2 is reinventing the wheel using uglier syntax than that provided by the language constructs.
clearly, both ways work; option 2 is merely obsoleted by the more modern syntax supported by option 1
I don't know if I have a knock down argument but initial thoughts are
Option 2 works until your trying to catch an Exception that doesn't implement getCode()
Option 2 encourages the developer to catch general exceptions, this is a problem because if you don't implement a case statement for a given subclass of AppException the compiler will not warn you. Ofcourse you could run into the same problem with option 1 but atleast option 1 does not activly encourage this.
With option 1, the caller has the option of selecting exactly which exception to catch, and to ignore all others. With option 2, the caller has to remember to re-throw any exceptions not explicitly caught.
Additionally, there's better self-documentation with option 1, as the method signature needs to specify exactly which exceptions are thrown, rather than a single over-riding exception.
If there's a need to have an all-encompassing AppException, the other exception types can always inherit from it.
The knock-down argument would be that it breaks encapsulation since I now I have to know something about the subclass of Exception's public interface in order to handle exceptions by it. A good example of this "mistake" in the JDK is java.sql.SQLException, exposing getErrorCode and getSQLState methods.
It looks to me like you're overusing exceptions in either case. As a general rule, I try to throw exceptions only when both of the following are true:
An unexpected condition has occurred that cannot be handled here.
Somebody will care about the stack trace.
How about a third way? You could use an enum for the type of error and simply return it as part of the method's type. For this, you would use, for example, Option<A> or Either<A, B>.
For example, you would have:
enum Error { ONE_ERROR, ANOTHER_ERROR, THIRD_ERROR };
and instead of
public Foo mightError(Bar b) throws OneException
you will have
public Either<Error, Foo> mightError(Bar b)
Throw/catch is a bit like goto/comefrom. Easy to abuse. See Go To Statement Considered Harmful. and Lazy Error Handling
I think it depends on the extent to which this is used. I certainly wouldn't have "one exception to rule them all" which is thrown by everything. On the other hand, if there is a whole class of situations which are almost certainly going to be handled the same way, but you may need to distinguish between them for (say) user feedback purposes, option 2 would make sense just for those exceptions. They should be very narrow in scope - so that wherever it makes sense for one "code" to be thrown, it should probably make sense for all the others to be thrown too.
The crucial test for me would be: "would it ever make sense to catch an AppException with one code, but want to let another code remain uncaught?" If so, they should be different types.
Each checked Exception is an, um, exception condition that must be handled for the program behavior to be defined. There's no need to go into contractual obligations and whatnot, it's a simple matter of meaningfulness. Say you ask a shopkeeper how much something costs and it turns out the item is not for sale. Now, if you insist you'll only accept non-negative numerical values for an answer, there is no correct answer that could ever be provided to you. This is the point with checked exceptions, you ask that some action be performed (perhaps producing a response), and if your request cannot be performed in a meaningful manner, you'll have to plan for that reasonably. This is the cost of writing robust code.
With Option 2 you are completely obscuring the meaning of the exception conditions in your code. You should not collapse different error conditions into a single generic AppException unless they will never need to be handled differently. The fact that you're branching on getCode() indicates otherwise, so use different Exceptions for different exceptions.
The only real merit I can see with Option 2 is for cleanly handling different exceptions with the same code block. This nice blog post talks about this problem with Java. Still, this is a style vs. correctness issue, and correctness wins.
I'd support option 2 if it was:
default:
throw e;
It's a bit uglier syntax, but the ability to execute the same code for multiple exceptions (ie cases in a row) is much better. The only thing that would bug me is producing a unique id when making an exception, and the system could definitely be improved.
Unnecessary have to know the code and declare constants for the exception which could have been abstract when using option 1.
The second option (as I guess) will change to traditional (as option 1) when there is only one specific exception to catch, so I see inconsistencey over there.
Use both.
The first for most of the exceptions in your code.
The second for those very "specific" exceptions you've create.
Don't struggle with little things like this.
BTW 1st is better.