5

This question already has an answer here:

I'm developing a Java web application. It is a three layered architecture:

web > service > repository.

I'm thinking of creating many exceptions - each specific to each individual error and in the service layer where my business logic resides I want to throw specific exceptions that is tied to the business error.
And in the web layer (further up the stack where it is closer to the front end) is where I'm catching it and handling with them accordingly.

Someone said to me, don't do it this way because it is bad practice and advised me to just throw one single generic business exception instead - and he was adamant he was right. When I heard this, my reaction was that it goes against all the stuff I learned in university, past experiences, and the stuff I read in common tech books.

marked as duplicate by gnat, user53019, Community Nov 7 '15 at 17:35

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 3
    Can we have specific examples please. If Software design issues could be decided in the general case without context or nuance it would be too easy. A particular allergy to multiple exception types in Java might come from checked exceptions. – Nathan Cooper Nov 6 '15 at 21:44
  • 3
    There is a rule of thumb: for libraries, you want a rich hierarchy of exception types that can be handled meaningfully by client code. For application code, exceptions cannot be handled meaningfully. Instead, log the error for developers, and display a generic error message to the users – they aren't helped by any details. Since the type of the exception is irrelevant for the handling of the error, a single business exception suffices. Add a debug-friendly error message, a stack trace, and maybe an error code to the log. – amon Nov 6 '15 at 22:47
7

Is it bad practice to throw multiple custom exceptions in Java?

No. It is good practice.

The only situation where multiple exceptions might be a (slightly) bad idea is if there is absolutely no possibility (ever!) of catching individual exceptions; i.e. the fine-grained exceptions won't serve any functional purpose. However, my opinion is that if you can make that assertion, then there is probably something wrong with the way that you / your team is using Java. And the counter-argument is that sensible use of multiple custom exceptions will help you to document the APIs ... even if you are never going to do more than catch-log-and-bail-out at runtime.

This is not to say that lots of custom exceptions will always be good:

  • If you go overboard and create a separate exception for everything, then you are probably adding unnecessary complexity. (In a lot of cases, different exception messages are sufficient.)

  • If you don't have a sensible inheritance hierarchy for your custom exceptions, then you may end up regretting it. (A well-designed hierarchy allows you to catch "classes" of exceptions, or declare methods as throwing them. It can make your code simpler.)

  • "Catch log bail" over time will at the very least indicate problem areas that should be addressed, and having very specific exceptions to log the issue makes fixing it much easier. – Chris Cirefice May 9 '16 at 5:28
  • 1
    Yes ... but often a specific >>message<< is more immediately useful than a specific exception class. – Stephen C May 9 '16 at 15:06
7

Is it bad practice to throw multiple custom exceptions in Java?

Generally speaking: No. Why should it?

As with everything: Abstraction is your friend.

Is it necessarry to have a CustomerNotFound Exception and a ProductNotFound Exception? Or are your requirements just a more abstract NotFoundException? The context could help to determine, what was missing. Having different exceptions for the sake of having them is nonsense.

Is it necessary, each layer of your application having custom exceptions? Exceptions are a way to report, that an intended action failed due to some reason.

  • Say, you have a controller which asks the service-layer to retrieve data, which in turn asks the DA-layer to read values from the DB. The resultset is empty. The service gets the empty resultset and throws a NotFoundException the service communicates, the failure of the action due to a missing result.

  • Say, the controller needs the service to do the payrolls for employees. And the service is asked to do the payroll for the employee with ID 123456, and in turn asks a service to retrieve the employee - but no emloyee could be found.

There are two ways to deal with that:

1) You throw a NotFound exception in the DA-Layer, catch it in the payroll-service and rethrow a PayrollServiceException wrapping the NotFoundException with the message Exmployee could not be found

2) You throw a NotFound exception in the DA-Layer and do not catch it in the payroll service and catch it instead a layer above.

I would go for (2), since in (1) the information, that the action failed because of a missing employee is redundant.

4

I'm looking at the Spring application that I've got sitting here, and there are a few dozen custom exceptions. Much of this is because with Spring, the exceptions can bubble all the way out to the framework layer and then be nicely translated by the framework into the corresponding HTTP status code.

  • Missing rows are their own class structure - MissingRowException is an abstract class. There's also a place for the corresponding wrapped SQLException.
    • Foo row not found? That's a FooMissingException that becomes a 404.
    • Bar row not found in the database? That's a BarMissingException that also becomes a 404.
  • Validation errors are their own exception class structure
  • System errors are another exception class structure (there's one here named DatabaseBorkedException - that's a 500 error)
  • And so on
  • I don't even want to think about how many of the little fiddly exceptions that are private inner classes to the controllers because they're only used within that controller (bail out, there's no reason to go further, send a nice custom page).

You will note that there are trees of exceptions. These do happen to have a common root, and I can just throw the top level GenericBusinessException (which isn't abstract). Note that doing that exception logs an info message about who did it and also has a pmd warning when you look at it with static analysis - but sometimes you need to cut the corners and take on a bit of technical debt and just throw the simple exception now to get it out the door rather than all the other work for the other exceptions.

If the entirety of the handling of the exception is just log it, one may consider that writing all these exceptions is a waste of time. And in some situations, I'd agree. However, if you have different handling for each exception at some level, your alternative is tossing an enum in a field of the exception or stringly type the GenericBusinessException and not really doing anything about it.

Custom exceptions add meaning and allow the coder to more clearly express the intent of the code. It allows a maintainer to (if the exceptions are used in a way that can be reasoned about) to more quickly follow the flow of an application. To this extent, they are quite good and beneficial.

1

Do recall that an exception is after all just a class, that can have instance fields and methods of their own while they extend some flavor of Exception or implement Throwable.

I say this because I think having an exception defined for each and every error condition may be an inappropriate level of specificity for a class, when really what might serve you better is to have a small handful of exceptions that cover distinct categories of failure types, and that let you include details that provide the specificity.

Generally, you create an exception type for each different way that you'll handle thrown exceptions.

  • yes indeed. that was the point i was trying to explain. Sorry for not being clear with my English. i was meaning having separate exception classes covering different categories of failure types and also have the ability to provide extra info in them - as you said, they are just classes after all. – SoftwareDeveloper Nov 6 '15 at 22:36
  • whereas the other option i was presenting was having just 1 single exception. And the point i was trying to convey across was that this option is no much different than using the already there Exception.java class. And that i was leaning towards the small handful of separate exceptions option... – SoftwareDeveloper Nov 6 '15 at 22:39
1

In my experience (I am a Java developer for 10+ years now) it is bad practice. Not that it is a code smell, but it most often hinders you in your daily work.

Think of an application that tries to read a file and probably throws an FileNotReadableException. After a while you realize, that the file may not be readable due to insufficient access-rights. What do you do? Change the name of the exception - no, it may be still in use. Add a subtype FileNotReadableBecauseOfAccessRightsException? Well, this is rather 2 errors - not readable + access rights, but the root cause is the rights thing. So you add an InsufficientAccessRightsException somewhere else in the class tree. When doing so you also need to change the code where the original exception was caught since its 2 different types now (a violation of the open-closed-principle). And so on... And what's the gain? ... in contrast to an exception with a message? Static type safety. In the context of exceptions it is only useful to prevent typos. A developer could still use a wrong exception type (e.g. EntryNotFoundException instead of FileNotReadableException).

As said by dwoz: an exception is just a class.

My experience is that a few exceptions are sufficient. What you want to express are error-messages - for several messages you only need 1 (runtime) exception with a String field. All exceptions should be caught by a default error-handler at the highest possible layer (or earlier if necessary).

Besides the usual message, you sometimes need to store more information, like a filesystem-path, a username, a device-id, a uuid to more easily trace the error in a distributed system, etc. for those purposes I suggest to create custom exception classes.

As said by amon, a rule of thumb should be: for libraries use (some) exceptions, for (web-) applications us as few as possible

Not the answer you're looking for? Browse other questions tagged or ask your own question.