Forums Register Login

Throwing a second exception question

+Pie Number of slices to send: Send
I encountered interesting case regarding exception. I had two choices in the following question when I took Enthuware Standart Test 5:
-----
What is wrong with the following code?

You had to select 1 option.

A. It will not compile because you cannot throw an exception in finally block.
B. It will not compile because you cannot throw an exception in catch block.
C. It will not compile because NullPointerException cannot be created this way.
D. It will not compile because of unhandled exception.
E. It will compile but will throw an exception when run.
-----

I thought D and E as correct answers, but I chose option E at the end. Because I remembered that I read from my OCA book the exception from the catch block gets forgotten if finally block throw exception. According this manner I thought that MyException gets forgotten and main method throw NullPointerException. Therefore it didn’t need declare or handle MyException.
But I saw the correct answer was option D when I checked my results. I looked for the consistent part from book and I found it on page 312. I have taken a note the same part in my note file with a bit different form:
This code compile successfully although catch block throw checked exception. It doesn’t need declaring or handling because test() method throw runtime exception. I compared these two codes:
and I understood that if we write tc.m2(); in finally block line 1 does not compile. But if write throw new NullPointerException(); instead of tc.m2(); the code will compile.
What happens? Compiler can’t determine that m2() method throw NullPointerException?
1
+Pie Number of slices to send: Send
 

Mushfiq Mammadov wrote:
What happens? Compiler can’t determine that m2() method throw NullPointerException?


Compiler only checks for checked exceptions. That is why they are called "checked exceptions"
Compiler doesn't bother with unchecked exceptions at all.

Also, look at it another way - compiler cannot execute the method m2, so it doesn't know what all this method will actually throw. For all it knows, the method may not throw any exception.
+Pie Number of slices to send: Send
RE the exception being forgotten - what OCA book are you using Mushfiq? I wouldn't mind going back over that if you have a reference.

So if m2 threw and correctly handled a checked exception, would the catch block still be ok to not handle tc.m1()?

Also, Paul, are the test questions randomised? Pretty sure I had this question in Test 2, I got it right, but completely missed this 'level' of depth. I just assumed it wasn't handled correctly.

Regards,

Nick
+Pie Number of slices to send: Send
 

nick woodward wrote:

So if m2 threw and correctly handled a checked exception, would the catch block still be ok to not handle tc.m1()?


Good question. You should try it out. Remember that having a throws clause does not mean that the method will always throw that exception. It just means that the method may throw any of the exceptions listed in the throws clause.


Also, Paul, are the test questions randomised? Pretty sure I had this question in Test 2, I got it right, but completely missed this 'level' of depth. I just assumed it wasn't handled correctly.


No, the questions are not randomized across standard tests. There are questions that look the same but are actually not. So I am pretty sure that you saw a different question in test 2 if you haven't taken test 5 yet.
+Pie Number of slices to send: Send
 

Paul Anilprem wrote:
Good question. You should try it out. Remember that having a throws clause does not mean that the method will always throw that exception. It just means that the method may throw any of the exceptions listed in the throws clause.


hmmm. ok, so you mean that the compiler won't know if it is actually thrown.

but then why does explicitly throwing MyException in a try catch block within the finally clause also not work?

anyway, I'll let Mushfiq come back to the thread before I take it over too much!!


No, the questions are not randomized across standard tests. There are questions that look the same but are actually not. So I am pretty sure that you saw a different question in test 2 if you haven't taken test 5 yet.



Seems to be question 18/70 on Test 2 for me!
+Pie Number of slices to send: Send
 

nick woodward wrote:

Paul Anilprem wrote:
Good question. You should try it out. Remember that having a throws clause does not mean that the method will always throw that exception. It just means that the method may throw any of the exceptions listed in the throws clause.


hmmm. ok, so you mean that the compiler won't know if it is actually thrown.


Correct. The compiler cannot know whether the call to a method will actually cause a particular exception to be thrown at run time.

The compiler can know while analyzing a block of code whether that block of code always throws an exception or not. That is how it figures out stuff like "unreachable code". So if a block of code has an explicit throw statement that is not nested inside any conditional statement (such as an if or while or switch), it can know that the block will always throw that exception. It cannot evaluate a condition or call a method at compile time.


but then why does explicitly throwing MyException in a try catch block within the finally clause also not work?


I am not sure I understand the scenario you are describing here. Can you put that in code?



No, the questions are not randomized across standard tests. There are questions that look the same but are actually not. So I am pretty sure that you saw a different question in test 2 if you haven't taken test 5 yet.



Seems to be question 18/70 on Test 2 for me!


Looks like you are using the question bank for OCAJP7 while Mushfiq is using the question bank for OCAJP 8. The question id for this question is 2.1276. It is appears in both the banks but in different tests
+Pie Number of slices to send: Send
Hi Paul,

I meant by nesting another try/catch in the finally block which guarantees to throw a checked exception, my logic being that the compiler should know that finally definitely throws an exception:

but that doesn't work. I'm guessing because the compiler assumes that an exception might not be thrown because it's in a try block? Because this:


works fine, and seems much the same to me.

And yeah, that makes sense with the question banks!!

Regards,

Nick
+Pie Number of slices to send: Send
 

nick woodward wrote:Hi Paul,
I meant by nesting another try/catch in the finally block which guarantees to throw a checked exception, my logic being that the compiler should know that finally definitely throws an exception:

but that doesn't work. I'm guessing because the compiler assumes that an exception might not be thrown because it's in a try block? Because this:


Sorry but I am still not clear on your question. Please copy complete code and what you mean by "not work". The rule is simple. If the compiler sees a possibility that a checked exception may be thrown outside a method, then that exception must be declared in the throws clause of that method.

Guessing what you are trying to convey, if you replace the finally block with the one posted above, the finally block doesn't throw any exception and the MyException thrown by the code in try/catch is not overridden by any exception from finally. Hence, you must declare MyException in the throws clause.
2
+Pie Number of slices to send: Send
 

Mushfiq Mammadov wrote:I thought D and E as correct answers


I assumy you meant you were doubting between answer D and E? Because those two answers together can never be correct: either the code compiles (and you can execute it and you might get an exception at runtime) or the code fails to compile and you have a compiler error (but you can not execute the code).

Mushfiq Mammadov wrote:I looked for the consistent part from book and I found it on page 312. I have taken a note the same part in my note file with a bit different form


That slight difference between both code snippets is the reason why the test() method compiles successfully and the TestClass class doesn't. Why? Just read on

Mushfiq Mammadov wrote:I understood that if we write tc.m2(); in finally block line 1 does not compile. But if write throw new NullPointerException(); instead of tc.m2(); the code will compile.
What happens? Compiler can’t determine that m2() method throw NullPointerException?


I have repeated this rule many, many, many times already but I repeat it once more because people seem to keep forgetting this very simple but very, very, very important rule: The compiler doesn't execute any code! So every compiler error you get, is because the compiler knows something is wrong without executing any line of code.

Let's apply this rule to the TestClass class: the compiler sees only the method invocation tc.m2(); in the finally block. But the compiler has no clue (and doesn't care) about what's happening in this method. So for the compiler the finally block will complete normally, so there's no reason to forget the (possible) unhandled and undeclared checked exception from the method invocation tc.m1(); and is (very) happy to give you a compiler error
Now in the test() method the compiler obviously sees the finally block won't complete normally (because an exception will be thrown) and forgets the unhandled and undeclared checked exception from the catch block and happily compiles the code for you.

Hope it helps!
Kind regards,
Roel

PS. Remember it's considered a very bad practice to prevent the finally block from completing normally (by throwing an exception or returning a value). Because (as you can see) it might result in very tricky behavior and hard to detect bugs.
1
+Pie Number of slices to send: Send
 

nick woodward wrote:RE the exception being forgotten - what OCA book are you using Mushfiq? I wouldn't mind going back over that if you have a reference.


It's not really a book reference, but almost as good Here's a thread with an explanation of myself about the same topic
+Pie Number of slices to send: Send
 

nick woodward wrote:works fine, and seems much the same to me.


That's not the same at all!

First of all, let's have a look at your first code snippetFor the compiler the finally block ends normally. Why? Because the checked exception you throw on line1 is handled by the catch block on line2. So from the perspective of the compiler: the try block is always executed and line1 is always executed and thus the checked exception MyException is always thrown. Because of that, the catch block (on line2) is always executed as well handling this checked exception. So this checked exception is "gone", because it's handled by the catch block (on line2). And thus the finally block completes normally.
Now if you would throw a runtime exception from inside the catch block (on line2), e.g.the code will successfully compile. Why? Let's again look from the perspective of the compiler: the try block is always executed and line1 is always executed and thus the checked exception MyException is always thrown. Because of that, the catch block (on line2) is always executed as well and thus the runtime NullPointerException (on line3) is also thrown always. Because this runtime exception is always thrown (and not caught), the finally block won't complete normally and the possible checked exception from tc.m1(); is forgotten (because the compiler can think only of one exception at a time and is thinking about that NullPointerException on line3 ) and the code compiles normally.

Now in your second code snippet, you are not handling the checked exception MyException2 in the finally block, but you have declared it. And that's a big difference! A checked exception must be handled or declared (to have a happy compiler). When you handle the exception, the exception is "gone" (you have handled the exception, you have taken care of it); but if you declare the exception, the exception is still "there" (it's not yet handled), you have deferred the exception handling to another method. So the finally block won't complete normally and the possible checked exception from tc.m1(); is forgotten.

Hope it helps!
Kind regards,
Roel
+Pie Number of slices to send: Send
And finally (pun intended ), it's time for a bonus question. How can you make the original code snippet compile without handling or declaring MyException? Also removing and/or commenting lines is not allowed I can think of (at least) 2 possible solutions. I have a cow on offer for the rancher who can list both

Good luck!
Kind regards,
Roel
+Pie Number of slices to send: Send
 

Roel De Nijs wrote:And finally (pun intended ), it's time for a bonus question. How can you make the original code snippet compile without handling or declaring MyException? Also removing and/or commenting lines is not allowed I can think of (at least) 2 possible solutions. I have a cow on offer for the rancher who can list both

Good luck!
Kind regards,
Roel




Damnit! I need to go to bed.....

Ummm.... calling System.exit(); ? or a runtimeexception? both undoubtedly not what you meant, but still.....

I'll check your longer response (and yours paul), out tomorrow. Thanks both of you.

Regards,

Nick


*edit: drop the catch clause?

obviously the || part isn't real code
+Pie Number of slices to send: Send
 

nick woodward wrote:Ummm.... calling System.exit(); ? or a runtimeexception? both undoubtedly not what you meant, but still.....


I don't give cows for free So you have to provide the appropriate code snippets. Calling System.exit(); or a runtime exception is not enough (as you can call it on many different lines and it might be appropriate on only one specific line).

nick woodward wrote:*edit: drop the catch clause?


That qualifies of course as removing lines

nick woodward wrote:obviously the || part isn't real code


And non-compilable code won't qualify of course
+Pie Number of slices to send: Send




heh
definitely cheating, but to spec


+Pie Number of slices to send: Send
 

nick woodward wrote:heh
definitely cheating, but to spec


Throwing a runtime exception from the finally block is indeed one of the possible solutions Changing MyException from a checked exception to a runtime exception is a good attempt, but that's cheating and doesn't count So still one to go to earn a well-deserved cow.
(1 cow) 1
+Pie Number of slices to send: Send
ah, 'return' in the finally block! that took me way too long. are there other ways? I doubt I can come up with any more....

anyway, am going to go over your larger response now, thanks for that.
1
+Pie Number of slices to send: Send
 

nick woodward wrote:ah, 'return' in the finally block! that took me way too long.


Exactly! Just using the return statement will do the jobHere is your more than well deserved cow!
+Pie Number of slices to send: Send
Thanks!


So I just got round to looking back over the thread and your longer reply, and I think what I was missing was the idea that finally 'ends normally' as you put it.

So anything that interrupts finally prevents control going back to the catch block (so to speak). so the compiler knows it doesn't have to be concerned by that tc.m1() if a runtime exception is explicitly thrown, or if a checked exception is thrown but declared in main's signature. However if the checked exception is handled in finally it completes correctly, tc.m1() again becomes the focus and needs to be handled itself. And I guess the same applies to calling a method in finally, the compiler at the time cannot be sure if it does or doesn't complete correctly, so assumes it does, leading to tc.m1() needing to be handled or declared.

(however on that last poing I'm a bit I'm a bit confused as to why the compiler doesn't know - I assume that even though the method which throws the exception is right there in the class, the compiler can't be sure if tc.m2() won't end up calling a method polymorphically? )

Hope that made some sense!

Nick
+Pie Number of slices to send: Send
 

nick woodward wrote:(however on that last poing I'm a bit I'm a bit confused as to why the compiler doesn't know - I assume that even though the method which throws the exception is right there in the class, the compiler can't be sure if tc.m2() won't end up calling a method polymorphically? )


No, it has nothing to do with polymorphism or not. The actual reason is much easier: a method declaration with a throws clause is not a guarantee this method will always throw that exception! And even if you would have a method which will always throw e.g. a runtime exception likethe compiler still doesn't know, because the compiler (as you already know) does not execute any code.

But if the method has a throws clause with a checked exception, you always have to handle or declare this exception. It doesn't matter if this method is invoked from within a catch or finally block. Otherwise you'll get a big fat compiler error So if you change the method declaration of m2() toyou'll have 2 compiler errors in the TestClass class: both tc.m1(); and tc.m2(); have an unhandled checked exception.

Hope it helps!
Kind regards,
Roel
+Pie Number of slices to send: Send
ok, thanks, I think I get it. I'm just messing about with a bit of code at the moment to make sure, then I'm going to try and simplify all of that to a couple of index cards I think what the compiler does or doesn't check frequently confuses me on things like this!

Cheers,

Nick
+Pie Number of slices to send: Send
 

nick woodward wrote:I think what the compiler does or doesn't check frequently confuses me on things like this!


If you remember only one thing about the compiler, it definitely has to be: the compiler does not execute any code at all when verifying if the code is valid or not! Using this "rule" and your common sense, you'll be able to answer several questions with nothing more but some reasoning.

Let's try! Does this code snippet compile successfully? And if it doesn't, why not?
+Pie Number of slices to send: Send
I don't think so, because the compiler checks a.eat() based on the class, not the object type at runtime.

I don't know though, I guess my confusion comes from the fact that I feel the compiler *should* be able to see in that code that 'a' is a new Lion, because it's explicitly stated - it isn't a situation where 'a' could be anything other than a lion, for example a = animalArr[x].
I know I'm wrong with this thinking, and yes, it doesn't execute any code, but that's where my confusion comes from I think. It can't *see* or execute the RuntimeExceptions in finally either, or the constant required for narrowing either, but somehow knows that they are/are not acceptable.

I hope you understand where I'm coming from with this!

Nick
+Pie Number of slices to send: Send
 

nick woodward wrote:I don't think so, because the compiler checks a.eat() based on the class, not the object type at runtime.


Spot-on! Although it should be "the type of the reference variable" (not "the class") to be 100% correct

nick woodward wrote:I don't know though, I guess my confusion comes from the fact that I feel the compiler *should* be able to see in that code that 'a' is a new Lion, because it's explicitly stated - it isn't a situation where 'a' could be anything other than a lion, for example a = animalArr[x].


How the compiler currently works is very consistent: check the type of the reference variable and verify everything is compliant with all the rules. And consistency is a very good thing! Once you know the rules, you can determine what will happen without the slightest doubt.

But if the compiler *should* be able to act upon what's explicitly stated, it becomes less consistent and it's much harder and cumbersome to determine what will happen. And that applies to both the compiler itself (and the code required to pull this one off) and the Java developers. The OCA (and OCP) exams which are already pretty difficult, will become a gazillion times more difficult. And as always I illustrate with a small code snippet to prove my point With the current compiler it's very easy to spot that both line1 and line2 must handle or declare the checked exception in order to successfully compile this code snippet (animals is an array of Animal reference variables). But what about the new enhanced compiler? Do we need to handle or declare the checked exception? Or will the compiler be able to figure out both will always refer to a Lion? What do you think?

nick woodward wrote:I hope you understand where I'm coming from with this!


Definitely! That's why I really emphasize that rule whenever I can. It's a really very, very, very important one! But I hope this post (and especially the code snippet) illustrates why your feelings/thoughts about the compiler's skills are simply mission impossible (even for Ethan Hunt ). And interpreting code snippets would become waaaaaaaaay more harder and every Java developer will have plenty of moments

Hope it helps!
Kind regards,
Roel

PS. The code snippet uses nothing but static methods. But it's very easy to turn them into instance methods and use a slightly adjusted main method and ask the same questions
+Pie Number of slices to send: Send
No, I agree, if the compiler doesn't execute code then it will never know if it's always a lion. It's just working from the reference type/return type of the method. I'm not sure what this enhanced compiler that I've created is, or should do.... I'm going to guess handle everything, because it's the boss

Anyway, looking back at the original exceptions problem that does make sense - I think I was just confusing the compiler's ability to check primitive assignments on the RHS with explicit object assignments, but can see why it would be better to treat objects with different rules,

Thanks!

Nick
+Pie Number of slices to send: Send
 

nick woodward wrote:I think I was just confusing the compiler's ability to check primitive assignments on the RHS


Do you refer to the compiler error you'll get when you try to do something like this?Or am I completely mistaken?
+Pie Number of slices to send: Send
yeah, although now looking at it i guess it's more similar to a switch expression and the case constants needing to be of the same type.

if it can check those, then it just seemed odd that it couldn't see that Animal a = new Lion(), and that a.eat() (in this limited case) had to refer to the Lion's eat method. although at this point i think i'm starting to dig myself into a hole.....! (as the compiler is actually doing the same thing as with the primitives by allowing the assignment of the Lion() in the first place.)

either way, I'd definitely forgotten what the compiler is/isn't capable of, so this has been a great read,

Nick
+Pie Number of slices to send: Send
 

nick woodward wrote:yeah, although now looking at it i guess it's more similar to a switch expression and the case constants needing to be of the same type.


It doesn't make any difference. As you know case statements have to be compile-time constants (and literals are implicitly considered to be compile-time constants). So the compiler knows the values without having to execute any code, they are known at compile-time (hence their name ). And it's exactly the same with this code snippetThe compiler knows these values (and knows the result of the addition will fit into a byte). But from the moment compile-time constants are not involved anymore, the compiler doesn't know the value anymore and requires you to add an appropriate cast in order to still successfully compile the code

And compile-time constants can only have a primitive or String type! So objects (except for String) can never be compile-time constants. And that's why byte b = 100 + 50; behaves different than Animal a = new Lion(); although both seem to look pretty similar.
Do Re Mi Fa So La Tiny Ad
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com


reply
reply
This thread has been viewed 1626 times.
Similar Threads
compilation error in try/catch/finally
Too many exceptions?
Exceptions
Exception must be caught, or it must be declared in the throws clause of this method
exception dilema
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
More...

All times above are in ranch (not your local) time.
The current ranch time is
Mar 29, 2024 05:37:35.