Java etiquette - when to use try/catch and when to use if

Page 2 - Seeking answers? Join the AnandTech community: where nearly half-a-million members share solutions and discuss the latest tech.

znaps

Senior member
Jan 15, 2004
414
0
0
My point was that sometimes, the Error WILL be wrapped in a RuntimeException automatically...actually not wrapped, but you can catch it. Not sure why you think LinkageErrors are the only important ones, but imagine you're writing some sort of JVM in Java - you'll need to deal with all sorts of things that a regular app doesn't have to, and if you want to throw something you would be wrapping it in some sort of Exception.
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
I'm not following you at all. What do you mean if not wrapped? You can catch an Error just like any Exception if you want. Writing the jvm in java (which to my knowledge has never been completed to the Sun spec) wouldn't be much different from writing any other app in that you will only be catching Throwables that you mean to deal with.

I said LinkageError because it is the ancestor of all the Errors that have to do with incompatible or missing classes and that is the subject we were talking about. I don't think the other Errors would be appropriate to downgrade in such a way.
 

znaps

Senior member
Jan 15, 2004
414
0
0
Ok, look at these two examples.

Code:
public class Test {

	public static void main(String[] args){
		try{
			
			LogTest test = new LogTest();
			System.out.println(test);
		} catch(Throwable t){
			System.out.println("See, I caught an Error");
			System.out.println(t);
		}
	}
	
	
	static class LogTest{
		
		public LogTest(){
			org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(Test.class);
		}
	}
}


public class Test2 {

	public static void main(String[] args){
		try{
			
			org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(Test2.class);
		} catch(Throwable t){
			System.out.println("Why doesn't this get caught?");
			System.out.println(t);
		}
	}

}

In one case, you can catch the error, and in the other you can't.

If you're writing a JVM, or any sort of VM (who cares if it hasn't been done to the Sun spec yet), or a compiler for the new programming language you just invented, then you want to deal with all sorts of Errors that the JVM throws. How about Stack Overflow errors? You'd want to deal with those for sure.
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
Maybe I'm missing something (I haven't run that code), but why would the second example miss something that the first would catch? It's not like anything will escape the second catch block. And what exactly is throwing the Error here? Are you supposed to remove log4j.jar from the classpath when you run the example?

I said that no jvm written in java has passed the spec yet just to point out that it's not commonly done and that you aren't dealing with pure java at that point. At any rate, a jvm written in java will not explicitly catch Errors, it will throw them. If the application itself doesn't catch the Error it will completely unwind the stack of the Thread in context at which point it stops but not necessarily because of a catch block because at that point you're not dealing with ordinary java, you need something special (something that doesn't conform to the language specification) to handle the end of a Thread.

Anyways, I'm not too familiar with all the details of what happens when Throwables escape from the bottom of a Thread stack, doing some investigation/trials right now :)
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
Basic test has a Runnable called DoomedThread that throws an Error when started.

Main method starts a new Thread with an instance of DoomedThread and then continues to do some other safe stuff.

The started Thread gets destroyed when the Error escapes from DoomedThread.run() and the stack trace (ending with Thread.run()) gets printed to stderr but the code in the main thread continues to execute (pretty much as I expected). In this case nobody caught the Error because it stopped when the Thread ended and it doesn't matter what language the jvm was written in.
 

znaps

Senior member
Jan 15, 2004
414
0
0
Ok, now write an application that has to deal with that Error that gets thrown.
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
Modified DoomedThread to catch Throwable before run() exits. The Error gets caught and no stack trace is printed. That's exactly what I was expecting, what were you expecting?
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
Originally posted by: znaps
never mind..we're not getting each other here at all.
Ok, I'm gonna run your example to see if I can figure out what you mean. Should log4j.jar be on or off the classpath?
 

znaps

Senior member
Jan 15, 2004
414
0
0
Off the classpath. It was just to illustrate my point that Errors can be caught sometimes, but not all the time.

And my other point was that sometimes, you DO want to catch errors, depending on what your application is. That's all.
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
Tricky stuff. It happened as you said and for a minute I was confused.

The reason is that in your second example the main() method never runs. The NoClassDefFoundError is thrown when the class containing the reference is loaded, not the first time you try to reference the missing class. In your first example the loading of the LogTest class was delayed until it's constructor was called but in the second example Test2 was loaded (obviously) before the main() method was called.
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
Here's an interesting extension I tried:

After compiling the first example I opened up Test$LogTest.class in a text editor and messed it up. The result was a ClassFormatError before the main() method was run (no Throwable was caught). In this case the ClassFormatError is identical in effect to the NoClassDefFoundError before, except that this time it affects a class referenced from the main class as in the second example, instead of a class referenced in a secondary class like in the first example.

Now I'm no classloading expert but here's my take on what happened. First the main class is loaded (obviously). Then, before calling main() it is linked, which involves loading (but not necessarily linking) LogTest. Everything is fine at this point (if LogTest.class is not messed up) so there are no errors. Then, while the code is executing, we come across a reference to LogTest which is loaded but hasn't had its links verified (otherwise you'd have to load every single dependent class at start up time). So when the reference comes up, the jvm tries to link it, which causes it to search for Logger. That fails and you get an Error during the execution of main().

In the second example Test2 itself references Logger so it can be loaded but not linked, which means that main() can't be run.
 

kamper

Diamond Member
Mar 18, 2003
5,513
0
0
Another test:

I compiled the first example so that it runs properly (catches the Throwable). Then I modified the LogTest constructor to take an int paramter (no particular significance to the int itself). I recompiled but then dropped the old Test.class back in. Now we have incompatible classes because Test is looking for LogTest() when only LogTest(int) exists.

Upon running, the main method was started, a NoSuchMethodError was thrown and it was caught in main(). I'm not quite sure what to make of this, I would have assumed that linking Test would have caused an Error and that main() never would have been run. Maybe linking only consists of finding a class with the right name and nothing more? I should just buck up and read the language specification instead of guessing :p
 

znaps

Senior member
Jan 15, 2004
414
0
0
Originally posted by: kamper
Tricky stuff. It happened as you said and for a minute I was confused.

The reason is that in your second example the main() method never runs.

Good catch. ahahahaha I crack myself up...

 

znaps

Senior member
Jan 15, 2004
414
0
0
Originally posted by: kamper
Another test:

I compiled the first example so that it runs properly (catches the Throwable). Then I modified the LogTest constructor to take an int paramter (no particular significance to the int itself). I recompiled but then dropped the old Test.class back in. Now we have incompatible classes because Test is looking for LogTest() when only LogTest(int) exists.

Upon running, the main method was started, a NoSuchMethodError was thrown and it was caught in main(). I'm not quite sure what to make of this, I would have assumed that linking Test would have caused an Error and that main() never would have been run. Maybe linking only consists of finding a class with the right name and nothing more? I should just buck up and read the language specification instead of guessing :p


Haven't time to check this out now, but I will tomorrow. This stuff is interesting..I've been coding Java for 6 years and learn something new about it every day.