I am working on an application where the process goes on like this UI-->backend process --> result to UI.
In my code, I have handled my exceptions using try, catch. But in the code I have so many repeated exceptions that may throw same exceptions in different classes.
So, I am planning to do a exception handling strategy so that when exception is thrown it must be redirected to the separate exception handling code (something like separate custom exception handling library class). so that it should not be inside my business logic.
Could anyone suggest me how to implement it and whether its best idea to handle my exceptions? or Could anyone suggest me an exception handling technique to do this other than mine?
Thank you, expecting your reply.
From Effective Java (Joshua Bloch)
Avoid checked exceptions.
http://www.mindview.net/Etc/Discussions/CheckedExceptions http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html
One very important thing to understand is that any piece of code can produce an exception. It is that it is not because a method declares throwing an IOException that it may not throw any other exception. It can throw any other runtime exception (generic or custom). With checked exceptions, developers tend to think the opposite, and think that catching IOException will handle all the exceptional cases, but it is not true!
A compile time feature only
Only the compiler will tell you when you forget to catch or rethrow a checked exception. At runtime, there is no difference.
This means that by using type erasure tricks, you can throw a checked exception without even needing it to be part of the method contract.
You can find examples of this trick as being called SneakyTrow here: https://stackoverflow.com/a/4890489/82609
Lombok also provides a @SneakyThrow annotation to put on methods so that you don't need to declare checked exceptions in the method signature.
Only use checked exceptions when your class client can probably recover from the exception.
This is the Sun recommendation.
Basically, an attempt to connect to the database will throw a checked exception, and the retry strategy code will catch these checked exceptions on connection attemps. When the number of retry is exceeded, the retry strategy will throw an unchecked exception, meaning it is not a recoverable exception since the recovery strategy has already been tried. You can use Spring RetryTemplate for that by the way.
Avoid exception codes
The exception type should be sufficient for flow control decisions. Parsing exceptions or flow control will only create useless code. Add more exception types, as much as you have exception codes.
Fail fast
Let all the non recoverable exceptions being throw up to the IHM layer. If you use a framework that declare checked exceptions and you have no recovery strategy for them, do not hesitate to wrap them into unchecked exceptions.
If you can't recover, then you should not do "catch and log". Or worse, you should not do "catch and return null". This will produce inconsistent software and you will probably have another exception raised a bit later in your program, but you won't be able to understand why. Returning null will only create a NullPointerException later.
The IHM layer technology may have an exception handler/mapper. Web IHM layers have exception mappers so that you can say "this exception produces a 404 error".
The functional approach
For information: in functional languages it is often considered a bad practice to use exceptions for flow control. Instead of throwing exceptions, we usually return "enhanced types", like Either[Error,MyResultType].
The returned instance is either an error or a success, the success being a MyResultType instance returned.
Exceptions are not performant for flow control
Creating an exception has a cost (creating the stacktrace). It costs much more than a normal flow using if, else... Do not use them for flow control if you can avoid them.
Basically, you can mostly always avoid them, but in Java it may be sometimes more convenient to use them for flow control in some situations. In functional languages the Either monad helps again.
Use assertions
If something on your program is assumed to be true by the developer, use assertions so that you guarantee your assertion is true. Take a look at Guava Preconditions: https://code.google.com/p/guava-libraries/wiki/PreconditionsExplained
Or you can use Java native assertions, or some custom code. This helps to fail fast.
If you throw exceptions that are too low-level catch them few calls above, and pack as more general and meaningful exception with user friendly message what went wrong, and throw them once again to highest possible level, where you stop your app and view them somehow (e.g. on label) to user.
from Effective Java (item 61):
It is disconcerting when a method throws an exception that has no apparent connection to the task that it performs. This often happens when a method propagates an exception thrown by a lower-level abstraction. Not only is this disconcerting, but it pollutes the API of the higher layer with implementation details. If the implementation of the higher layer changes in a subsequent release, the exceptions that it throws will change too, potentially breaking existing client programs.
To avoid this problem, higher layers should catch lower-level exceptions and, in their place, throw exceptions that can be explained in terms of the higher-level abstraction. This idiom is known as exception translation:
// Exception Translation try { // Use lower-level abstraction to do our bidding ... } catch(LowerLevelException e) { throw new HigherLevelException(...); }
While exception translation is superior to mindless propagation of exceptions from lower layers, it should not be overused. Where possible, the best way to deal with exceptions from lower layers is to avoid them, by ensuring that lower-level methods succeed. Sometimes you can do this by checking the validity of the higher-level method’s parameters before passing them on to lower layers.
If it is impossible to prevent exceptions from lower layers, the next best thing is to have the higher layer silently work around these exceptions, insulating the caller of the higher-level method from lower-level problems. Under these circumstances, it may be appropriate to log the exception using some appropriate logging facility such as java.util.logging. This allows an administrator to investigate the problem, while insulating the client code and the end user from it.
In summary, if it isn’t feasible to prevent or to handle exceptions from lower layers, use exception translation, unless the lower-level method happens to guarantee that all of its exceptions are appropriate to the higher level. Chaining provides the best of both worlds: it allows you to throw an appropriate higher-level exception, while capturing the underlying cause for failure analysis (Item 63).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With