This page contains an archived post to the Design Forum (formerly called the Flexible Java Forum) made prior to February 25, 2002.
If you wish to participate in discussions, please visit the new
Artima Forums.
Message:
Exceptions and Performance
Posted by Bill Venners on 09 Jul 1998, 10:50 AM
> So even if myObj != null 99.999% of the time, checking for > myObj == null is cheaper than setting up a try/catch block > for myObj? > I guess I could have run some performance tests for this one.. I was just reading through the reader comments for the exceptions article at JavaWorld and a lot of people mentioned that they wished I would have said something about the performance implications of exceptions. The funny thing was that some people said "the performance costs of exceptions" and other people said "the performance benefit of using exceptions." Well, that same dichotomy kind of came out in this thread of discussion. As Mike Manion mentioned, when an exception is thrown the JVM has to do a lot more stuff than it has to do when a method returns normally. It has to look through the method's exception table for a matching catch clause, and if none is found, it has to pop the stack and rethrow the exception one stack frame down, where it has to check through the exception table again. So a method completing normally is more "efficient" than a method completing abruptly by throwing an exception. On the other hand, Bryan Boone pointed out that if most of the time the method won't throw the exception, then having some condition be signaled by a thrown exception could end up being more efficient. Somebody who posted to the JavaWorld reader feedback mentioned that if you have a loop that executes 10000 times, it can be more efficient to wait for an exception to be thrown to indicate a loop termination condition (say EOF) than to invoke a method each pass through the loop to check for the termination condition. But every time I get on this topic of performance, I feel the urge to jump up on a desk and yell: Don't do premature optimization! You guys are probably already well aware of this guiding principle, but just for the heck of it, here's my philosophy in a nutshell: When you are designing a class like Mike's Supplier class: class Supplier { boolean canDoIt() {...} void doIt() {...} }
You should design it with flexibility in mind over performance, because the odds are that this class won't be critical to the actual performance of your application. (Because usually only 10% to 20% of the code is performance-critical--executed 80* to 90% of the time.) So I would design it with a canDoIt() method, as Mike recommends. Then when I finish my program and realize I have a performance problem, I would profile the program to identify the 10% to 20% of the code I need to worry about, then I'd just focus on that code. I would try to use better algorithms, try to make better uses of the APIs, apply standard techniques like loop unrolling. Each time I tried something I would re-measure the performance to see how I was doing and only keep performance tweaks that made a difference. And only as a last resort would I screw up my nice, flexible, object-oriented, thread-safe design in the name of performance. And each time I did that I would measure to see if my uglifying of the code in the name of performance actually bought me better performance. Whew! I feel better now that I got that out. So I think the answer to Bryan's original question is: it depends. If I were to go through all the above steps and end up finding that the doit1() method of Bryan's MyClass was the heart of my performance bottleneck: class MyClass { MyObject myObj; ... ... void doit1() { if(myObj == null) { myObj = new MyObject(); } myObj.process(); } void doit2() { try { myObj.process(); } catch(NullPointerException e) { myObj = new MyObject(); myObj.process(); } } }
I would be inclined to try and change doit1() to use doit2()'s approach. Because if this thing really is in the performance- critical part of the code, it is probably being called again and again and again and again, so many times that most of the time the myObj reference actually isn't null. So most of the time the exception probably isn't being thrown. So I'd be willing to try it. BUT, I would measure the performance again after I changed doit1() into doit2(), to see if I really got results. If I didn't achieve satisfactory results, I'd change it back to just checking for null explicitly, because I think that is the more flexible (in this case, easier to read) way to write this code. bv
Replies:
|