سؤال

From a good design/practice point of view, when should we create and use custom Java exception classes instead of the ones already predefined in Java?

In some applications I see almost custom exception classes created, they make an effort to always use native Java exceptions. On the other hand, there are some applications that define custom exceptions for (almost) everything.

هل كانت مفيدة؟

المحلول

From Best Practices for Exception Handling:

Try not to create new custom exceptions if they do not have useful information for client code.

What is wrong with the following code?

public class DuplicateUsernameException extends Exception {}

It is not giving any useful information to the client code, other than an indicative exception name. Do not forget that Java Exception classes are like other classes, wherein you can add methods that you think the client code will invoke to get more information.

We could add useful methods to DuplicateUsernameException, such as:

public class DuplicateUsernameException
    extends Exception {
    public DuplicateUsernameException 
        (String username){....}
    public String requestedUsername(){...}
    public String[] availableNames(){...}
}

The new version provides two useful methods: requestedUsername(), which returns the requested name, and availableNames(), which returns an array of available usernames similar to the one requested. The client could use these methods to inform that the requested username is not available and that other usernames are available. But if you are not going to add extra information, then just throw a standard exception:

throw new IllegalArgumentException("Username already taken");

نصائح أخرى

from a good design/practice point of view, when should we create and use custom java exception classes instead of the ones already predefined in java?

When the existing exception names don't cover your need.

Another design concern is to extend the "good" exception class; for instance, if you raise an exception related to I/O, you should ideally inherit IOException; if the exception indicates a programmer error, you should inherit RuntimeException (ie, make your exception unchecked).

Raising custom exceptions also allows you to treat exceptions in a more precise manner; for instance, if you have defined FooException inheriting IOException, then you can have a special treatment for it:

try { ... }
catch (FooException e) { ... } // Catch it _before_ IOException!
catch (IOException e) { ... }

Also, exceptions are classes like any other, so you can add custom methods etc; for instance, Jackson defines JsonProcessingException which inherits IOException. If you catch it, you can obtain location information of the parse error using .getLocation().

certainly when you expect to be able to programmatically handle an exception - ie it's easy to create separate catch statements for different exception types, ie:

try{    
  buyWidgets();
}
catch(AuthenticationException ex)
{
  promptForLogin();
}
catch(InsufficientFundsException ex)
{
  promptToRefillAccount();
}
//let other types of exceptions to propagate up the call stack

On whether the above constitutes inappropriate use of exception for flow control

While exceptions are more CPU-expensive than if-else statements (mainly due to cost of constructing a stack trace), cost is relative and should be assessed in the context of particular use case. Not every piece of code needs to be web-scale fast and some people find reading and testing conditionals more cumbersome. For example pretty much all transaction managers implement commit-rollback-retry idioms using exceptions. (Try writing a transaction retry aspect without catching an exception)

Separately, one should adhere to separation of concerns principle: not every piece of code needs to deal with every possible condition. Whether not being logged in while buying widgets is an exceptional case really depends on the app and particular place in the app code base. For example, you could have a Service with operations for logged-in users. It makes no sense for methods in that service to deal with authentication - instead these methods would expect code earlier in the call chain to ensure user is authenticated, and thus simply throw exceptions if that is not so. Thus, for those methods being not logged in IS an exceptional case.

You do so when using your own exception adds value to your code base.

It is that simple. Value could be:

  • catching on a higher level might be easier, for example when all your exception have a common base type
  • your exception carry addition data (we include NLS keys in our own exceptions, so that a higher layer knows how to give messages to human users taking I18N into account)

I often create custom Exceptions if there is more information that I need to convey instead of just an error message.

For example particular error codes or actual vs expected values. these can also have their own getters so you can programically retrieve these fields without having to parse the String message which could break if you ever change the text of the message. (Or translate it into a different language)

If you make your own Exceptions, I would recommend extending the common JDK built in exceptions so your API can say throws IOException but it really throws MycustomIOException. that way users of your API don't have to know about your own custom versions unless they want to.

Its good to have custom exceptions in your application, one may be a top level custom exception for applications, others at the module/package levels. If you have some specific function/operation in app and you need let the user know if any exception occurred during the operation then better to add custom exception for that operation. It will be easy to debug/investigate the issues.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top