oiyio
oiyio

Reputation: 5925

Effective use of try-catch blocks & Where should we locate them?

I have one interface class , one implementation class , one exception class and Main class. I'm not sure whether i use try catch blocks in my code effectively or not. I have searched in the web and found similar topics and questions but i cannot find answer of my question.I used try catch in both main and implementation files. Is it senseful? Could you please advise for effectiveness? Is the below logic about try-catch is right, or not ?

Interface Class:

public void createDatabase() throws DatabaseAlreadyCreated;


Implementation Class:

public void createDatabase() throws DatabaseAlreadyCreated
{
try
{
   // Create Database 
       //if database is already exist 
      throw new DatabaseAlreadyCreated();
}         
catch (SQLException e) {e.printStackTrace();} 
catch (ClassNotFoundException e) {e.printStackTrace();}

}

 Exception Class:

 public class DatabaseAlreadyExist extends Exception
 {

    public DatabaseAlreadyExist(String str)
    {
       System.out.println("database exist exception");
    }
 }



 Main Class:

 public static void main(String args[])
 {
       try 
       {
       x = ops.createDatabase();
       } 
       catch (DatabaseAlreadyExist e) 
       {
         e.printStackTrace();
   }
 } 

Upvotes: 0

Views: 1618

Answers (4)

Matt Campbell
Matt Campbell

Reputation: 2227

Easy way to start a religious war in any programming forum is: "What's the best way to handle errors?" :) But it's a perfectly valid question.

In Java, as you may already know, there are two kinds of exceptions: runtime detectable and compile-time detectable. (Another set of labels is "unchecked", for runtime, and "checked", for compile-time.) Compile-time detectable exceptions have thrown exceptions specifically defined for them, the way you're doing with your custom database exception. The big diff betw checked and unchecked exceptions (eg: null pointer or index out of range exceptions) is that checked exceptions are required to be handled if thrown, or delegated out of the method's scope using the "throws" keyword, forcing the calling method to deal with it. Unchecked ones can be handled (via a try/catch block), but it isn't required. Unchecked exceptions also throw only specific exceptions, descended from class RuntimeException, itself a descendent of Exception. (See http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html for the full low-down). While you can use try/catch blocks to catch runtime exceptions, you can't shift these kinds of exceptions into being handled by anything other than their specific runtime exceptions (e.g., a null pointer reference at runtime can only be handled by a NullPointerException object or one of its superclass objects, and nothing else).

So why the "exceptions review lesson"? Because whether an exception ought to be thrown "upward" to the calling method or handled on the spot within the method in which it occurs has in large part to do with the question of whether code following the exception-generating code can "survive" without successful completion of whatever was in the try/catch block. Will subsequent code in essence be left with possible unchecked (runtime) exceptions, like null pointer exceptions? Frequently, that is the case. Or, subsequent code may be executable, but in an unreliable state (e.g.: field values not set as desired, etc.). Or, in the case of things like try/catch blocks around calls to databases to do updates, the database data state may not be correct for what you want done. You need to decide based on context and goals (and dependencies) whether to:

  1. Throw the exception upward without handling or reporting it locally, in essence putting the burden on the calling method to deal with it.
  2. Handle the exception locally and log/report it (possibly), then exit the method using 'return' within the catch () {} block.
  3. Handle the exception locally and log/report it (possibly), then continue executing code in the method.

Which you do, as I said, depends on what you need doing. Personally, I see exception-handling as each given method's problem, to be handled locally. An exception thrown really implies the method failed to complete its intended task-- unless the calling method can make up for its failure, or within the exception-creating method, subsequent code can still fulfill the desired aim. Throwing it to the calling method just means you take one of those two options off the table, and worse yet, it gets thrown immediately when it occurs, so you take away any option of picking up after the exception before exiting the method using 'return' or going on with the method. Now it can sometimes be that you need to use a try/catch to sort of test a condition in your code; i.e., using some method's exception-throwing nature as a means of determining what your code'll do next. However this is generally frowned upon, esp. if a "cleaner" way is available. [There are no purists like Java purists. :) ]

There may be times of course when throwing the exception upward is fine. But IMO, it's when the calling method need not be too concerned with the state of any objects or data affected by the called method's logic. I see it as a more summary way of dealing with less-consequential exceptions that arise. In my own case, I prefer to check for null object references a lot before using a potentially null object. Assigning a returnable object a value of null due to an exception in a method and returning it in the catch () {} block is a very common technique used to let the calling method know that the called method failed to do what it was meant to. E.g.:

public meth1() {
   Object o = meth2();
    if (o != null) {
       ... do what you need to ...
       } else
       {
       ... deal w/ no valid o object ...
       }
     ...
   }

private Object meth2()   {
   Object retnme = new Object();
   ...
   try {
      ... give it yer best ...
   } catch ( Exception e )
   {
      logException(e); // a call to some logging method.
       ... clean up bad karma ...
       return null;
    }
  ...
  return retnme;
}

All that said, re your immediate question abt your code: Based on the foregoing and bear in mind I don't fully know your situation, I don't see why you ought to throw the custom exception you created to the calling method unless you specifically want to use that exception to signal, for whatever reason, to the calling method that the db you're going to create already exists. If however knowing this is of no specific use to the calling method-- no need to do it. Part of this decision hinges on whether you expect to use any class that implements your interface to need to know whether the database exists or not. A way to avoid using such a strategy however is to edit your interface and class files so the method returns a boolean instead of void. If it returns 'true', the db was created. If 'false', it was not for some reason. You can also have it return an int and depending on its value, it indicates whether the db creation was successful. E.g., a value of 0 might mean success, while values 1..n could represent failure reasons, one value of course representing the fact that the db already exists.

Really, the sky's the limit. :) Hope this has been of some help.

Upvotes: 1

rolfl
rolfl

Reputation: 17707

The code is somewhat broken.... Unless you have very specific reasons, you should never directly extend the Throwable class but should extend Exception instead (or a descendant of Exception like RuntimeException).

With the code like it is you are not likely going ot be able to catch the exception unless you catch it explicitly with catch (DatabaseAlreadyExistsException e)

Apart from that, you have a number of issues with error handling that are not recommended... doing a 'printStackTrace' is not an effective way to handle a problem, but I am not sure whether you are doing this just to show that you have handling for it, or not (i.e. does your real code just do a printStackTrace?).....


EDIT: Updated after comment...

OK, I understand what you are asking now more than I did before. Using mechanisms described in other answers and comments, I would recommend doing something like:

public boolean checkDatabaseExists(...) {
    try {
        ... do the things you need to check the database exists.
        return true;
    } catch (Exception e) {
        return false;
    }
}

Then, in your main method, you can:

if (!checkDatabaseExists(...)) {
    createDatabase(...);
}    

Upvotes: 1

RooKie-
RooKie-

Reputation: 1413

In general try/catch blocks are more expensive then using if/else blocks.

So only use try/catch actual errors might happen, for instance when communicating with servers or database, a try/catch block would be appropriate.

If a variables should be tested for if it's "null", it's way to expensive to use try/ctach. In these situations, you should use logic like if/else for instance.

Upvotes: 1

SQB
SQB

Reputation: 4078

In general, you only throw an exception if you can't handle an error on the level you're now on, and you only catch an error you can handle at that level.

Upvotes: 0

Related Questions