What is the purpose of multiple "catch" blocks in exception handling - exception

Why we need multiple "catch" blocks even though we can write one generic
exception?
Is that important to know all the exception types and their purposes to make a good piece of code?
I googled a lot but still have confusions in exception handling. Any good example?
Generic Exception:
try{
//some code
}
catch(Exception e){
//print e
}
//that's it.
Multiple catches
try{
//some code
}
catch(IOException e){
}
catch(SQLException e){
}

There are several advantages of using multiple exceptions:
General exceptions will not let you know the exact root cause of the issue especially if many steps/checks involved in a method implementation. Also, If the exception occurs due to various reasons, you need to throw the different types of exceptions from your caller method implementation.
Eg: You can throw custom exceptions.
Here is your service code:
public void Login(string username, string password)
{
if(string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
{
throw InvalidUserNameException();
}
if(!IsInternetAvaialable())
{
throw NoInternetAvailableException()
}
else
{
//Implement though your login process and if need use various custom exceptions or throw the exception if occurs.
}
}
public class InvalidUserNameException : Exception
{
public InvalidUserNameException()
{
}
public InvalidUserNameException(string message)
: base(message)
{
}
public InvalidUserNameException(string message, Exception inner)
: base(message, inner)
{
}
}
Caller Method:
try {
...
} catch(InvalidUserNameException e) {
// Show Alert Message here
} catch(NoInternetAvaibleException e) {
// Show Alert Message with specific reason
}
catch(Exception e) {
// Other Generic Exception goes here
}
Reference:
https://learn.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions

1. Why we need multiple "catch" blocks even though we can write one generic exception?
Sometimes you might need to specify what causes the problem.
For example,
try {
...
} catch(IOException e) {
// Print "Error: we cannot open your file"
} catch(SQLException e) {
// Print: "Error: we cannot connect to the database"
}
With different errors, users can understand what went wrong easily.
If we go with
try {
...
} catch(Exception e) {
// Print "Error: " + e.
}
It's harder for the users to figure out what went wrong.
Also, we can send the users to different pages accordingly to the error if we use multiple catch-es.
2.Is that important to know all the exception types and their purposes to make a good piece of code?
Personally, I would go with important exceptions such as IO, DB, etc. that can cause serious trouble. For others, I would catch with general exception.

Related

Use exceptions rather than return codes: unused value

In the clean code book is an example about using exceptions rather than return codes:
You either set an error flag or returned an error code.
public class DeviceController {
...
public void sendShutDown() {
DeviceHandle handle = getHandle(DEV1);
// Check the state of the device
if (handle != DeviceHandle.INVALID) {
// Save the device status to the record field
retrieveDeviceRecord(handle);
// If not suspended, shut down
if (record.getStatus() != DEVICE_SUSPENDED) {
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
} else {
logger.log("Device suspended. Unable to shut down");
}
} else {
logger.log("Invalid handle for: " + DEV1.toString());
}
}
...
}
Unfortunately, it's easy to forget. For this reason, it is better to throw an exception when you encounter an error. The calling code is cleaner. Its logic is not obscured by error handling.
public class DeviceController {
...
public void sendShutDown() {
try {
tryToShutDown();
} catch (DeviceShutDownError e) {
logger.log(e);
}
}
private void tryToShutDown() throws DeviceShutDownError {
DeviceHandle handle = getHandle(DEV1);
DeviceRecord record = retrieveDeviceRecord(handle);
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
}
private DeviceHandle getHandle(DeviceID id) {
...
throw new DeviceShutDownError("Invalid handle for: " + id.toString());
...
}
...
}
The code is better because two concerns that were tangled, the algorithm for device shutdown and error handling, are now separated. You can look at each of those concerns and understand them independently.
Now my question is not so much about the whether to use exceptions or return codes but I am wondering about the unused DeviceRecord in the second "good example", which uses exceptions.
Wouldn't it be enough to just call retrieveDeviceRecord(handle); to save the device status to the record field as in the "bad example code" but change the method to also throw an exception in case anything goes wrong during retrieveDeviceRecord(handle);? Or is there a purpose of returning DeviceRecord but not using it?

Where can I get the exception throwed within the subscribe() method?

I'm using rxAndroid.
I've read many documents, but still not found the solution, and maybe I missed it,
so please give me a guide.
Here I created an observable that might throw an exception in subscribe method.
return Observable.create(new ObservableOnSubscribe<Project>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Project> e) throws Exception {
e.onNext(projectRepository.readDetails(project.getId()));
e.onComplete();
}
});
I use repository pattern to get the project details,
but the problem is all of the repository methods might throw an exception,
projectRepository.readDetails(project.getId())
And I couldn't find anyway to handle the exception throwed in the method subscibe(), Observer's onError() will not get any notification of it.
Thanks.
When creating an observable manually, you have to catch any exception and pass them to the onError() manually:
return Observable.create(new ObservableOnSubscribe<Project>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Project> e) throws Exception {
try {
e.onNext(projectRepository.readDetails(project.getId()));
e.onComplete();
}
catch (Exception ex) {
e.onError(ex);
}
}
});
Alternatively you should be able to use fromCallable() to avoid having to create the observable manually:
Observable.fromCallable(() -> projectRepository.readDetails(project.getId()));
This will signal onError() if the call should fail.

Continue is not inside a loop

I was writing a method for TCPServer. I've written a code as below:
// thread run
protected void threadRun(){
// continue running. don't stop
while(true){
try{
try{
}
catch(Exception e1){
try{
} catch(Exception e2){}
finally{
// skip
continue;
}
}
}
catch(Exception e3){
}
}
}
Content is not important. There were codes to accept client etc, but I have removed them to make sure about that it is not about details. Anyway, when I try to compile this code, compiler says for that continue line:
Error: continue is not inside a loop
By thinking that maybe I know it wrong, I've written the complete same code in Java as seen below:
class test{
public static void main(String[] args){
while(true){
try{
try{
}
catch(Exception e1){
try{
} catch(Exception e2){}
finally{
continue;
}
}
}
catch(Exception e3){
}
}
}
}
As I expected, java compiler doesn't give any error message and compiles successfully. What exactly can the problem be?
Apparently, continue (and break) can't break out of a finally block. Compiling this:
void run() {
loop:
while (true) {
try {}
catch (Exception e) {}
finally {
continue loop;
}
}
}
will give you this (omitting the label gives the same error you got):
Error: cannot continue out of finally block
I haven't yet found a justification or explanation of this restriction (edit: see ratchet freak's comment below). However, I can't imagine it's a super-common use case. You probably want to look at other options.

In languages with try-catch-finally, is it somehow possible to perform an action for all exception-handlers?

Is there any language that supports something like the below construct, or is there a good way to achieve this using the ubiquitous try-catch-finally?
try
{
} catch(Exception1 e)
{ .... }
catch(Exception2 e)
{ .... }
catch-finally
{
//Perform action, such as logging
}
finally
{
//This always occurs but I only want to log when an exception occurs.
}
I understand this depends on the particular language, but is there some such support in Java, C#, C++, PHP etc?
Put a "global" try/catch in your main program or high-level method. This catches all exceptions that are not caught elsewhere.
try
{
// Main method, or higher level method call
}
catch (Exception ex)
{
// Log exception here
}
Then, in your subordinate try/catch clauses, just handle your exceptions in the usual way, and then rethrow. The rethrown exception will bubble up to your main try/catch and be logged.
try
{
// Do your thing
}
catch(SomeException ex)
{
// Handle exception here
// rethrow exception to logging handler
throw;
}
I don't think so as the behaviour you describe can be easily modelled as:
boolean success = false;
try {
...
success = true;
} catch (Exception_1 e) {
...
}
...
} catch (Exception_N e) {
...
} finally {
if (success) {
// your "finally"
} else {
// your "catch-finally"
}
}
You can easily accomplish that in C#. A simple way would be to save the exception in your catch blocks, then in your finally block, log if the exception object is not null.
Exception ex;
try
{
}
catch (ExceptionType1 type1)
{
ex = type1;
}
catch (ExceptionType2 type2)
{
ex = type2;
}
finally
{
if (ex != null)
{
//Log
}
}
Visual Basic has a construct that can be used for this. This isn't really "finally" in the sense of [almost] never failing to execute, but it'll support the case when you only want to log the exceptions that you're handling, and you have access to the exception object within the shared code. You've also got the flexibility of having the shared code execute before or after the individual exception type code.
Try
...
Catch ex As Exception When TypeOf(ex) Is Type1 OrElse TypeOf(ex) Is Type2
...
If TypeOf(ex) Is Type1 Then
...
ElseIf TypeOf(ex) Is Type2 Then
...
End If
End Try
Something like this, as long as the language has throw with no parameters to rethrow a caught exception:
try
{
} catch(Everything) {
try {
throw;
} catch (Exception1 e) {
....
} catch (Exception2 e) {
....
} finally {
//Perform action, such as logging
}
} finally {
//This always occurs but I only want to log when an exception occurs.
}
That's if you want to log whenever an exception occurs - if you only want to log the ones you actually catch, then don't put the "Perform action" in a finally block, just put it after the end of the inner try-catch.

Retry after Spring throws DataAccessException not working

I am facing a very peculiar situation. I am using hibernate template with spring 3.0.5 for DB operations. When I try to insert a User model the first time, a DataAccessException is thrown, which I catch. Now I wish to retry the same DB operation for say 3 times. The second time when it, no exception is thrown.
Here is the code:
package com.user.profile.dao;
#Repository("userProfileDAOImpl")
public class UserProfileDAOImpl implements IUserProfileDAO {
#Autowired
private HibernateTemplate hibernateTemplate;
public Long insertUserProfileData(User user) throws AppNonFatalException {
Long id = null;
int retryCount = 0;
while (retryCount < 3) {
try {
id = (Long)hibernateTemplate.save(user);
}
catch (DataAccessException e) {
e.printStackTrace();
retryCount++;
System.out.println("Retry Count = " + retryCount);
if (retryCount > 3) {
throw new AppNonFatalException(e.getLocalizedMessage(), "10000", e.getMessage(), e);
}
}
catch (Exception e) {
/* not coming inside this block too second time onwards */
System.out.println("Pure Exception");
}
}
return id;
}
}
I read that RuntimeExceptions should not be caught. Then how do I retry the operation. Should I retry at the service layer? Am I missing something? Any help is appreciated.
From https://community.oracle.com/docs/DOC-983543:
Unchecked exceptions are exceptions
that do not need to be declared in a
throws clause. They extend
RuntimeException. An unchecked
exception indicates an unexpected
problem that is probably due to a bug
in the code.
Since DataAccessException is a RuntimeException, you might want to check what is the real cause of the exception and fix it instead of catching it and retry the operation.