Performance cost of coding “exception driven development” in Java?

自作多情 提交于 2019-12-18 02:34:47

问题


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;
}

回答1:


"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.




回答2:


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.




回答3:


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.

Some exceptions are very special cases that you expect and can handle. However, in general exceptions pop up when something unexpected or uncontrollable went wrong. From that point your objects are likely to be in a bad state, because subsequent steps will expect things to be there that didn't happen due to the exception, and trying to proceed will only trigger more exceptions. It's much better to let unexpected exceptions go so they can be caught by a central handler.




回答4:


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.




回答5:


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.




回答6:


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.




回答7:


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.




回答8:


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);



回答9:


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.




回答10:


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.




回答11:


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...




回答12:


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;
}



回答13:


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



回答14:


Exceptions cost a lot because each time an exception is thrown, the stack trace must be created and populated.

Imagine a balance transfer operation which fails in 1% of cases due to lack of funds. Even with this relatively little rate of failures, performance may be severely impacted. See here for the source code and benchmark results.



来源:https://stackoverflow.com/questions/2184935/performance-cost-of-coding-exception-driven-development-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!