views:

272

answers:

13

Are there are any performance cost by creating, throwing and catching exceptions in Java?

I am planing to add 'exception driven development' into a larger project. I would like to design my own exceptions and include them into my methods, forcing developers to catch and do appropriate work.

For example, if you have a method to get a user from the database based on a name.

public User getUser(String name);

However, it is possible that the user might be null and it is common to forget to check this before using a User's public method.

User user = getUser("adam");

int age = user.getAge();

which would result in NullPointerException and a crash. However, if I made a check, before returning the user-object, if its null and throw an 'UserIsNullException':

public User getUser(String name) throws UserIsNullException;

I force the implementor to think and act:

try {

    User user = getUser("adam");

    int age = user.getAge();

}catch( UserIsNullException e) {

}

It makes the code much safer for unexpected crashes and eliminates more bugs. Let say the website has hundreds of visitors per hour and this design pattern is used pretty much everywhere.

How would such a design approach effect performance? Do the benefits out-weigh the cost or is it just plain bad coding?

Thanks for any help!

UPDATE! To be clear, my attention is not wrap a NullPointerException, as my example might suggest. The goal is to force the implementer to write a try/catch, saving the head ache of a real crash since a:

user == null

was forgotten. The question concerns comparing these two design models:

int age;

try {

User user = getUser("adam");

age = user.getAge();

}catch( UserIsNullException e) {

age = 0;

}

versus:

int age;

User user = getUser("adam");

if( user != null ) {
age = user.getAge();
} else {
age = 0;
}
+2  A: 

Building a stack trace amounts to about a thousand basic instructions. It has a definite cost.


Even though you don't ask, many people will probably tell you the approach you envision does not seem very attractive ... :-(

The code you are forcing on your callers is really ugly, hard to write and maintain.

To be more specific, and try to get understood, I will try to highlight several points.

  • The other developer is responsible for checking the nullity of the User received from your API (if the documentation states it clearly). His code does such checks internally regularly, so he can do it also after a call to your API. Even more, that will give his code some homogeneity.

  • When reusing an existing exception is appropriate, it is much better than creating your own. For example, if it was an error to call your API and ask for an non-existing User, you can throw an IllegalArgumentException.

KLE
A thrown exception does cost something to handle, but an unthrown exception is free. Zero-cost exceptions are a feature of the JVM.
Will
@Will Do you mean, free when I build an exception instance but not throw it? Like in `new Exception();` ? Do you have an official source for this information?
KLE
The normal path through the code should not take the exception. Zero cost exceptions mean that this path is not slowed down because the code *might* in other circumstances throw an exception. In exception driven development, exceptions are still exceptional. So there is generally no noticable performance impact from using EDD.
Will
@Will: I think you're talking about C++, not Java. :-P In Java, creating the exception has the cost, and throwing/catching it is cheap. See http://blogs.sun.com/jrose/entry/longjumps_considered_inexpensive.
Chris Jester-Young
@Will Please note respectfully that my answer mentioned the cost for building the stack trace, not for having a try-catch.
KLE
+5  A: 

"which would result in NullPointerException and a crash."

a NullPointerException is an exception, and can be caught in the a catch.

So the additional exception is redundant unless it adds clarity to the code. In this instance, it really doesn't. In fact, you've just taken an unchecked programmer error exception and promoted it to a checked exception.

Creating a checked exception for a programmer's error actually means your code has to explicitly handle the possibility that the programmer introduced an error, when they haven't.

Will
It adds clarity since it forces the implementer to write a try/catch.
corgrath
It removes clarity because the programmer, forced to put try-catches for novel exceptions everywhere, will have a big bunch of code when in the other case they'd have only code solving the problem, not code checking the programmer hadn't messed up.
Will
@corgrath: Programmers don't like to be forced to do anything, especially something with such a high maintainability cost (you have to change existing code everywhere) and comparatively little gain. If you do that to your team, they will lynch you.
Chris Jester-Young
In the OP's context the absence of a given user object may indicate some exceptional circumstance beyond the programmer's control (e.g. corrupt database) and so it might make sense to throw a checked exception.
Adamski
@corgrath - on the other hand, over-use of checked exceptions can also lead to bad coding practice, like catching Exception or declaring Exception as thrown.
Stephen C
@Adamski: In the latter case there is an exception for that, called `SQLException`. I'm perfectly happy to see `SQLException` declared in the throws clause if that actually comes from the database.
Chris Jester-Young
@Chris: Propagating SQLException is worse IMHO as it exposes the internals of your DAO implementation. What if I decide to switch to using some other storage mechanism? Far better to translate SQLException to a business-related exception specific to your app.
Adamski
@Adamski: I agree with that. My sentiment is that there should be an exception type that is, in spirit, alike to an `SQLException` (but in the business tier, if you like :-)), that is used to signal that the storage provider has failed, as opposed to if there is no data. Those two cases are vital to distinguish between.
Chris Jester-Young
+1  A: 

See this answer about performance with exceptions.

Basically in your idea you are wrapping a RuntimeException, NullPointerException, into a checked Exception; imho I would say that the problem can be managed at the business level with an ObjectNotFoundException: you did not find the user, the fact that user is null and that this generates errors comes after.

Alberto Zaccagni
A: 

I like this style of coding as it makes it very clear about what is going on from the point of view of someone using your API. I sometimes even name API methods getMandatoryUser(String) and getUserOrNull(String) to distinguish between methods that will never return null and those which can return null.

Regarding performance unless you're writing a very latency critical piece of code the performance overhead will be negligable. However, it's worth mentioning there are some best practices when it comes to try / catch blocks. For example, I believe Effective Java advocates creating a try / catch block outside of a loop to avoid creating it on each iteration; e.g.

boolean done = false;

// Initialise loop counter here to avoid resetting it to 0 if an Exception is thrown.
int i=0;    

// Outer loop: We only iterate here if an exception is thrown from the inner loop.
do {
  // Set up try-catch block.  Only done once unless an exception is thrown.    
  try {
    // Inner loop: Does the actual work.
    for (; i<1000000; ++i) {
      // Exception potentially thrown here.
    }

    done = true;
  } catch(Exception ex) {
    ... 
  }
} while (!done);
Adamski
+3  A: 

There is a performance cost but that is not the main issue. Do you really want your code littered with catch blocks like your example? That's horrible.

Usually a web application has a main exception handler where everything uncaught ends up, at least that way when there is a mistake processing gets cut off cleanly. With all this exception-catching going on your process flow is going to be like falling down a couple flights of stairs.

Nathan Hughes
+1 for the analogy!
James
+1  A: 

Creating an exception, throwing an exception (with a stack trace), catching an exception and then garbage-collecting that exception (eventually) is much slower than doing a simple if check.

Ultimately, you can probably argue it down to style, but I think it's very bad style.

Malaxeur
+1  A: 

Null objects is something which may be of help to you. I was reading Martin Fowler's book "Refactoring" the other day and it describes using a specific object which acts in the place of returning a null, saving you from having to check for NULL all the time.

I won't try to explain it here as it is described very well in the book.

Tony
@Tony and @Oscar ReyesNullObjects are interesting, however I need to abort if the User is null, since I will usually do a lot more with the User-object.If I were to use NullObjects, like NullUser, I need to use "user instanceof NullUser" to figure out if the User existed with that name.
corgrath
If you need to abort when it is null, why not just leave it as it is and let the NullPointerException flow all the way to a catch block that aborts the process (when the user is null, or when any other requested object is null... there is no need to populate with more exceptions when there is one that actually means what you want.
David Rodríguez - dribeas
I understand that, but lets say I want to get User and a Vehicle, both could cast NullPointerException - how would you know which went wrong? Is it then not better to throw a UserIsNullException and a VehicleIsNullException? In that case, you can do the appropriate error handing.
corgrath
+4  A: 

Personally, I think that's a bad and obnoxious idea.

The usual way to encourage people to check for null values is to use annotations like @Nullable (and its opposite, @NotNull, for functions that are guaranteed to return non-nulls). By setting up similar annotations on parameters (so that parameter expectations are set), quality IDEs and bug-checkers (like FindBugs) can then generate all the necessary warnings when the code doesn't do enough checking.

Those annotations are available in JSR-305, and apparently there is also a reference implementation.


As far as performance goes, creating the exception is the expensive part (I've read that it's due to the stacktrace-filling, among other things). Throwing the exception is cheap, and is a control-transfer technique used in JRuby.

Chris Jester-Young
Scala also uses this to simulate the 'break' keyword from Java (see Breaks.scala and NoStackTrace.scala here: http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala/util/control )
Ben Lings
If creating an exception is expensive, but throwing is cheap, doesn't that mean that throwing an exception automatically becomes expensive? Since you actually need to create an exception to throw.
corgrath
@corgrath: If you're wanting to throw a real exception, then yes, the cost is there. If you're using exceptions as a control-transfer mechanism, you create one exception object and store it, then throw the same object around. Since it's just used for control-transfer, you don't care about the accuracy of the backtrace information, so this works.
Chris Jester-Young
@corgrath No, the two could be decoupled. For example, in a precise application for some exceptions, we might not care at all about the stack trace. So we could build a store an Exception instance (such as in a static member), and throw it as many times as needed ! :-)
KLE
+1  A: 

In general exceptions are extremely expensive in Java and should not be used for flow control!

The point of exception is to describe something exceptional, for example NumberIsZeroException isn't really that exceptional while PlanesWingsJustDetachedException clearly is something truly exceptional. If it's really exceptional in your software that user is null because there's data corruption or id number doesn't match anything or anything like that then it's alright to use an exception for that.

What exceptions also cause is divergence from "the happy path". While this doesn't apply to your example code, sometimes it's very beneficial to use Null Object instead of returning plain null.

Esko
When Java was young, I tried to ignore array bounds checking on the thought that ArrayIndexOutOfBoundsException would do it for me. The code was roughly 30x faster when I added simple `if (x<0)` logic, even with eight if statements. Memory use was also much lower.I have not done performance testing recently but I suspect you would encounter similar slowdowns these days too.
Alex Feinman
A: 

How would such a design approach effect performance? Do the benefits out-weigh the cost or is it just plain bad coding?

I'd said that there is almost no benefit of this programming style. Exception should be understood as (well...) exception. It should only should happen in a non-normal situation. How do you define 'normal situation' is pretty much arguable thought...

nanda
+1  A: 

There is a performance penalty to throwing an exception, but that's usually acceptable because the exception handling code only executes in exceptional cases. If you start using exceptions for flow control, you're turning the usual case around and making them expected behavior. I'd strongly recommend against it.

Bill the Lizard
A: 

You could forget about exceptions and avoid such a performance concern. This makes your API speak for itself.

int getUserAge(String userName) 
{
    int age = 0;
    UserSearchResult result = getUser(userName);
    if (result.getFoundUser())
    {
        User user = result.getUser();
        age = user.getAge();
    }
    return age;
}
ChaosPandion
A: 

As per your last edit. I think ( as Tony suggested ) using the NullObject pattern would be more useful here.

Consider this third scenario:

class NullUser extends User {

    public static NullUser nullUser = new NullUser();

    private NullUser(){}

    public int getAge() {
        return 0;
    }
}

//Later...
int age;

User user = getUser("adam"); // return nullUser if not found.
age = user.getAge();         // no catch, no if/null check, pure polymorphism
OscarRyz