Sunday 12 March 2017

Creating a Thread & Creating Multiple Threads - Java Tutorials

Creating a Thread

In the most general sense, you create a thread by instantiating an object of type Thread. Java defines two ways in which this can be accomplished:

  • You can implement the Runnable interface.
  • You can extend the Thread class, itself.

The following two sections look at each method, in turn.


Implementing Runnable

The easiest way to create a thread is to create a class that implements the Runnable interface. Runnable abstracts a unit of executable code. You can construct a thread on any object that implements Runnable. To implement Runnable, a class need only implement a single method called run( ), which is declared like this:

  public void run( )

Inside run( ), you will define the code that constitutes the new thread. It is important to understand that run( ) can call other methods, use other classes, and declare variables, just like the main thread can. The only difference is that run( ) establishes the entry point for another, concurrent thread of execution within your program. This thread will end when run( ) returns.

After you create a class that implements Runnable, you will instantiate an object of type Thread from within that class. Thread defines several constructors. The one that we will use is shown here:

  Thread(Runnable threadOb, String threadName)

In this constructor, threadOb is an instance of a class that implements the Runnable interface. This defines where execution of the thread will begin. The name of the new thread is specified by threadName.

After the new thread is created, it will not start running until you call its start( ) method, which is declared within Thread. In essence, start( ) executes a call to run( ). The start( ) method is shown here:

  void start( )

Here is an example that creates a new thread and starts it running:

  // Create a second thread.
  class NewThread implements Runnable {
    Thread t;

    NewThread() {
      // Create a new, second thread
      t = new Thread(this, "Demo Thread");
      System.out.println("Child thread: " + t);
      t.start(); // Start the thread
    }

    // This is the entry point for the second thread.
    public void run() {
      try {
        for(int i = 5; i > 0; i--) {
          System.out.println("Child Thread: " + i);
          Thread.sleep(500);
        }
      } catch (InterruptedException e) {
        System.out.println("Child interrupted.");
      }
      System.out.println("Exiting child thread.");
    }
  }

  class ThreadDemo {
    public static void main(String args[]) {
      new NewThread(); // create a new thread

      try {
        for(int i = 5; i > 0; i--) {
          System.out.println("Main Thread: " + i);
          Thread.sleep(1000);
        }
      } catch (InterruptedException e) {
        System.out.println("Main thread interrupted.");
      }
      System.out.println("Main thread exiting.");
    }
  }

Inside NewThread’s constructor, a new Thread object is created by the following statement:

  t = new Thread(this, "Demo Thread");

Passing this as the first argument indicates that you want the new thread to call the run( ) method on this object. Next, start( ) is called, which starts the thread of execution beginning at the run( ) method. This causes the child thread’s for loop to begin. After calling start( ), NewThread’s constructor returns to main( ). When the main thread resumes, it enters its for loop. Both threads continue running, sharing the CPU, until their loops finish. The output produced by this program is as follows:

  Child thread: Thread[Demo Thread,5,main]
  Main Thread: 5
  Child Thread: 5
  Child Thread: 4
  Main Thread: 4
  Child Thread: 3
  Child Thread: 2
  Main Thread: 3
  Child Thread: 1
  Exiting child thread.
  Main Thread: 2
  Main Thread: 1
  Main thread exiting.

As mentioned earlier, in a multithreaded program, often the main thread must be the last thread to finish running. In fact, for some older JVMs, if the main thread finishes before a child thread has completed, then the Java run-time system may “hang.” The preceding program ensures that the main thread finishes last, because the main thread sleeps for 1,000 milliseconds between iterations, but the child thread sleeps for only 500 milliseconds. This causes the child thread to terminate earlier than the main thread. Shortly, you will see a better way to wait for a thread to finish.


Extending Thread

The second way to create a thread is to create a new class that extends Thread, and then to create an instance of that class. The extending class must override the run( ) method, which is the entry point for the new thread. It must also call start( ) to begin execution of the new thread. Here is the preceding program rewritten to extend Thread:

  // Create a second thread by extending Thread
  class NewThread extends Thread {

    NewThread() {
      // Create a new, second thread
      super("Demo Thread");
      System.out.println("Child thread: " + this);
      start(); // Start the thread
    }
    
    // This is the entry point for the second thread.
    public void run() {
      try {
        for(int i = 5; i > 0; i--) {
          System.out.println("Child Thread: " + i);
          Thread.sleep(500);
        }
      } catch (InterruptedException e) {
        System.out.println("Child interrupted.");
      }
      System.out.println("Exiting child thread.");
    }
  }

  class ExtendThread {
    public static void main(String args[]) {
      new NewThread(); // create a new thread

      try {
        for(int i = 5; i > 0; i--) {
          System.out.println("Main Thread: " + i);
          Thread.sleep(1000);
        }
      } catch (InterruptedException e) {
        System.out.println("Main thread interrupted.");
      }
      System.out.println("Main thread exiting.");
    }
  }

This program generates the same output as the preceding version. As you can see, the child thread is created by instantiating an object of NewThread, which is derived from Thread.

Notice the call to super( ) inside NewThread. This invokes the following form of the Thread constructor:

  public Thread(String threadName)

Here, threadName specifies the name of the thread.


Choosing an Approach

At this point, you might be wondering why Java has two ways to create child threads, and which approach is better. The answers to these questions turn on the same point. The Thread class defines several methods that can be overridden by a derived class. Of these methods, the only one that must be overridden is run( ). This is, of course, the same method required when you implement Runnable. Many Java programmers feel that classes should be extended only when they are being enhanced or modified in some way. So, if you will not be overriding any of Thread’s other methods, it is probably best simply to implement Runnable. This is up to you, of course. However, throughout the rest of this chapter, we will create threads by using classes that implement Runnable.




Creating Multiple Threads

So far, you have been using only two threads: the main thread and one child thread. However, your program can spawn as many threads as it needs. For example, the following program creates three child threads:

  // Create multiple threads.
  class NewThread implements Runnable {
    String name; // name of thread
    Thread t;

    NewThread(String threadname) {
      name = threadname;
      t = new Thread(this, name);
      System.out.println("New thread: " + t);
      t.start(); // Start the thread
    }

    // This is the entry point for thread.
    public void run() {
      try {
        for(int i = 5; i > 0; i--) {
          System.out.println(name + ": " + i);
          Thread.sleep(1000);
        }
      } catch (InterruptedException e) {
        System.out.println(name + "Interrupted");
      }
      System.out.println(name + " exiting.");
    }
  }

  class MultiThreadDemo {
    public static void main(String args[]) {
      new NewThread("One"); // start threads
      new NewThread("Two");
      new NewThread("Three");

      try {
        // wait for other threads to end
        Thread.sleep(10000);
      } catch (InterruptedException e) {
        System.out.println("Main thread Interrupted");
      }

      System.out.println("Main thread exiting.");
    }
  } 

The output from this program is shown here:

  New thread: Thread[One,5,main]
  New thread: Thread[Two,5,main]
  New thread: Thread[Three,5,main]
  One: 5
  Two: 5
  Three: 5
  One: 4
  Two: 4
  Three: 4
  One: 3
  Three: 3
  Two: 3
  One: 2
  Three: 2
  Two: 2
  One: 1
  Three: 1
  Two: 1
  One exiting.
  Two exiting.
  Three exiting.
  Main thread exiting.

As you can see, once started, all three child threads share the CPU. Notice the call to sleep(10000) in main( ). This causes the main thread to sleep for ten seconds and ensures that it will finish last.

The Java Thread Model & The Main Thread - Java Tutorials

The Java Thread Model

The Java run-time system depends on threads for many things, and all the class libraries are designed with multithreading in mind. In fact, Java uses threads to enable the entire environment to be asynchronous. This helps reduce inefficiency by preventing the waste of CPU cycles.

The value of a multithreaded environment is best understood in contrast to its counterpart. Single-threaded systems use an approach called an event loop with polling. In this model, a single thread of control runs in an infinite loop, polling a single event queue to decide what to do next. Once this polling mechanism returns with, say, a signal that a network file is ready to be read, then the event loop dispatches control to the appropriate event handler. Until this event handler returns, nothing else can happen in the system. This wastes CPU time. It can also result in one part of a program dominating the system and preventing any other events from being processed. In general, in a singled-threaded environment, when a thread blocks (that is, suspends execution) because it is waiting for some resource, the entire program stops running.

The benefit of Java’s multithreading is that the main loop/polling mechanism is eliminated. One thread can pause without stopping other parts of your program. For example, the idle time created when a thread reads data from a network or waits for user input can be utilized elsewhere. Multithreading allows animation loops to sleep for a second between each frame without causing the whole system to pause. When a thread blocks in a Java program, only the single thread that is blocked pauses. All other threads continue to run.

Threads exist in several states. A thread can be running. It can be ready to run as soon as it gets CPU time. A running thread can be suspended, which temporarily suspends its activity. A suspended thread can then be resumed, allowing it to pick up where it left off. A thread can be blocked when waiting for a resource. At any time, a thread can be terminated, which halts its execution immediately. Once terminated, a thread cannot be resumed.


Thread Priorities

Java assigns to each thread a priority that determines how that thread should be treated with respect to the others. Thread priorities are integers that specify the relative priority of one thread to another. As an absolute value, a priority is meaningless; a higher-priority thread doesn’t run any faster than a lower-priority thread if it is the only thread running. Instead, a thread’s priority is used to decide when to switch from one running thread to the next. This is called a context switch. The rules that determine when a context switch takes place are simple:
  • A thread can voluntarily relinquish control. This is done by explicitly yielding, sleeping, or blocking on pending I/O. In this scenario, all other threads are examined, and the highest-priority thread that is ready to run is given the CPU.
  • A thread can be preempted by a higher-priority thread. In this case, a lower-priority thread that does not yield the processor is simply preempted—no matter what it is doing—by a higher-priority thread. Basically, as soon as a higher-priority thread wants to run, it does. This is called preemptive multitasking.

In cases where two threads with the same priority are competing for CPU cycles, the situation is a bit complicated. For operating systems such as Windows 98, threads of equal priority are time-sliced automatically in round-robin fashion. For other types of operating systems, threads of equal priority must voluntarily yield control to their peers. If they don’t, the other threads will not run.

Problems can arise from the differences in the way that operating systems context-switch threads of equal priority.


Synchronization

Because multithreading introduces an asynchronous behavior to your programs, there must be a way for you to enforce synchronicity when you need it. For example, if you want two threads to communicate and share a complicated data structure, such as a linked list, you need some way to ensure that they don’t conflict with each other. That is, you must prevent one thread from writing data while another thread is in the middle of reading it. For this purpose, Java implements an elegant twist on an age-old model of interprocess synchronization: the monitor. The monitor is a control mechanism first defined by C.A.R. Hoare. You can think of a monitor as a very small box that can hold only one thread. Once a thread enters a monitor, all other threads must wait until that thread exits the monitor. In this way, a monitor can be used to protect a shared asset from being manipulated by more than one thread at a time.

Most multithreaded systems expose monitors as objects that your program must explicitly acquire and manipulate. Java provides a cleaner solution. There is no class “Monitor”; instead, each object has its own implicit monitor that is automatically entered when one of the object’s synchronized methods is called. Once a thread is inside a synchronized method, no other thread can call any other synchronized method on the same object. This enables you to write very clear and concise multithreaded code, because synchronization support is built in to the language.


Messaging

After you divide your program into separate threads, you need to define how they will communicate with each other. When programming with most other languages, you must depend on the operating system to establish communication between threads. This, of course, adds overhead. By contrast, Java provides a clean, low-cost way for two or more threads to talk to each other, via calls to predefined methods that all objects have. Java’s messaging system allows a thread to enter a synchronized method on an object, and then wait there until some other thread explicitly notifies it to come out.


The Thread Class and the Runnable Interface

Java’s multithreading system is built upon the Thread class, its methods, and its companion interface, Runnable. Thread encapsulates a thread of execution. Since you can’t directly refer to the ethereal state of a running thread, you will deal with it through its proxy, the Thread instance that spawned it. To create a new thread, your program will either extend Thread or implement the Runnable interface.

The Thread class defines several methods that help manage threads. The ones that will be used in this chapter are shown here:

Method                               Meaning

getName                              Obtain a thread’s name.

getPriority                           Obtain a thread’s priority.

isAlive                                 Determine if a thread is still running.

join                                      Wait for a thread to terminate.

run                                       Entry point for the thread.

sleep                                    Suspend a thread for a period of time.

start                                     Start a thread by calling its run method.

Thus far, all the examples in this book have used a single thread of execution. The remainder of this chapter explains how to use Thread and Runnable to create and manage threads, beginning with the one thread that all Java programs have: the main thread.




The Main Thread

When a Java program starts up, one thread begins running immediately. This is usually called the main thread of your program, because it is the one that is executed when your program begins. The main thread is important for two reasons:
  • It is the thread from which other “child” threads will be spawned.
  • Often it must be the last thread to finish execution because it performs various shutdown actions.

Although the main thread is created automatically when your program is started, it can be controlled through a Thread object. To do so, you must obtain a reference to it by calling the method currentThread( ), which is a public static member of Thread. Its general form is shown here:

  static Thread currentThread( )

This method returns a reference to the thread in which it is called. Once you have a reference to the main thread, you can control it just like any other thread. Let’s begin by reviewing the following example:

  // Controlling the main Thread.
  class CurrentThreadDemo {
    public static void main(String args[]) {
      Thread t = Thread.currentThread();

      System.out.println("Current thread: " + t);
      
      // change the name of the thread
      t.setName("My Thread");
      System.out.println("After name change: " + t);

      try {
        for(int n = 5; n > 0; n--) {
          System.out.println(n);
          Thread.sleep(1000);
        }
      } catch (InterruptedException e) {
        System.out.println("Main thread interrupted");
      }
    }
  }

In this program, a reference to the current thread (the main thread, in this case) is obtained by calling currentThread( ), and this reference is stored in the local variable t. Next, the program displays information about the thread. The program then calls setName( ) to change the internal name of the thread. Information about the thread is then redisplayed. Next, a loop counts down from five, pausing one second between each line. The pause is accomplished by the sleep( ) method. The argument to sleep( ) specifies the delay period in milliseconds. Notice the try/catch block around this loop. The sleep( ) method in Thread might throw an InterruptedException. This would happen if some other thread wanted to interrupt this sleeping one. This example just prints a message if it gets interrupted. In a real program, you would need to handle this differently. Here is the output generated by this program:

  Current thread: Thread[main,5,main]
  After name change: Thread[My Thread,5,main]
  5
  4
  3
  2
  1

Notice the output produced when t is used as an argument to println( ). This displays, in order: the name of the thread, its priority, and the name of its group. By default, the name of the main thread is main. Its priority is 5, which is the default value, and main is also the name of the group of threads to which this thread belongs. A thread group is a data structure that controls the state of a collection of threads as a whole. This process is managed by the particular run-time environment and is not discussed in detail here. After the name of the thread is changed, t is again output. This time, the new name of the thread is displayed.

Let’s look more closely at the methods defined by Thread that are used in the program. The sleep( ) method causes the thread from which it is called to suspend execution for the specified period of milliseconds. Its general form is shown here:

      static void sleep(long milliseconds) throws InterruptedException

The number of milliseconds to suspend is specified in milliseconds. This method may throw an InterruptedException.

The sleep( ) method has a second form, shown next, which allows you to specify the period in terms of milliseconds and nanoseconds:

      static void sleep(long milliseconds, int nanoseconds) throws InterruptedException

This second form is useful only in environments that allow timing periods as short as nanoseconds.

As the preceding program shows, you can set the name of a thread by using setName( ). You can obtain the name of a thread by calling getName( ) (but note that this procedure is not shown in the program). These methods are members of the Thread class and are declared like this:

  final void setName(String threadName)
  final String getName( )

Here, threadName specifies the name of the thread.

Java’s Built-in Exceptions, Creating Your Own Exception Subclasses, Chained Exceptions & Using Exceptions - Java Tutorials

Java’s Built-in Exceptions

Inside the standard package java.lang, Java defines several exception classes. A few have been used by the preceding examples. The most general of these exceptions are subclasses of the standard type RuntimeException. Since java.lang is implicitly imported into all Java programs, most exceptions derived from RuntimeException are automatically available. Furthermore, they need not be included in any method’s throws list. In the language of Java, these are called unchecked exceptions because the compiler does not check to see if a method handles or throws these exceptions. The unchecked exceptions defined in java.lang are listed in Table 10-1. Table 10-2 lists those exceptions defined by java.lang that must be included in a method’s throws list if that method can generate one of these exceptions and does not handle it itself. These are called checked exceptions. Java defines several other types of exceptions that relate to its various class libraries.


Java’s Unchecked RuntimeException Subclasses

Exception                                                Meaning

ArithmeticException                               Arithmetic error, such as divide-by-zero.

ArrayIndexOutOfBoundsException        Array index is out-of-bounds.

ArrayStoreException                               Assignment to an array element of an incompatible type.

ClassCastException                                 Invalid cast.

IllegalArgumentException                      Illegal argument used to invoke a method.

IllegalMonitorStateException                 Illegal monitor operation, such as waiting on an 
                                                                 unlocked thread.

IllegalStateException                               Environment or application is in incorrect state.

IllegalThreadStateException                   Requested operation not compatible with current 
                                                                 thread state.

IndexOutOfBoundsException                 Some type of index is out-of-bounds.

NegativeArraySizeException                  Array created with a negative size.

NullPointerException                              Invalid use of a null reference.

NumberFormatException                        Invalid conversion of a string to a numeric format.

SecurityException                                    Attempt to violate security.

StringIndexOutOfBounds                        Attempt to index outside the bounds of a string.

UnsupportedOperationException            An unsupported operation was encountered.


Java’s Checked Exceptions Defined in java.lang

Exception                                                Meaning

ClassNotFoundException                        Class not found.

CloneNotSupportedException                 Attempt to clone an object that does not implement the
                                                                 Cloneable interface.

IllegalAccessException                            Access to a class is denied.

InstantiationException                              Attempt to create an object of an abstract class or interface.

InterruptedException                                One thread has been interrupted by another thread.

NoSuchFieldException                             A requested field does not exist.

NoSuchMethodException                         A requested method does not exist.




Creating Your Own Exception Subclasses

Although Java’s built-in exceptions handle most common errors, you will probably want to create your own exception types to handle situations specific to your applications. This is quite easy to do: just define a subclass of Exception (which is, of course, a subclass of Throwable). Your subclasses don’t need to actually implement anything—it is their existence in the type system that allows you to use them as exceptions.

The Exception class does not define any methods of its own. It does, of course, inherit those methods provided by Throwable. Thus, all exceptions, including those that you create, have the methods defined by Throwable available to them. They are shown in Table 10-3. Notice that several methods were added by Java 2, version 1.4. You may also wish to override one or more of these methods in exception classes that you create.


The Methods Defined by Throwable

Method                                                    Description

Throwable fillInStackTrace( )                  Returns a Throwable object that contains a completed 
                                                                  stack trace. This object can be rethrown.

Throwable getCause( )                             Returns the exception that underlies the current exception. 
                                                                  If there is no underlying exception, null is returned. Added 
                                                                  by Java 2, version 1.4.

String getLocalizedMessage( )                 Returns a localized description of the exception.

String getMessage( )                                 Returns a description of the exception.

StackTraceElement[ ] getStackTrace( )    Returns an array that contains the stack trace, one element 
                                                                   at a time as an array of StackTraceElement. The method 
                                                                   at the top of the stack is the last method called before the 
                                                                   exception was thrown. This method is found in the first 
                                                                   element of the array. The StackTraceElement class gives 
                                                                   your program access to information about each element in 
                                                                   the trace, such as its method name. Added by 
                                                                   Java 2, version 1.4

Throwable initCause(Throwable               Associates causeExc with the invoking exception as 
                                   causeExc)                a cause of the invoking exception. Returns a reference 
                                                                   to the exception. Added by Java 2, version 1.4
                      
void printStackTrace( )                              Displays the stack trace.

void printStackTrace(PrintStream             Sends the stack trace to the specified stream.
                                   stream)

void printStackTrace(PrintWriter              Sends the stack trace to the specified stream.
stream)

void setStackTrace(StackTraceElement    Sets the stack trace to the elements passed in elements.                                         elements[ ])                This method is for specialized applications, not normal 
                                                                    use. Added by Java 2, version 1.4


String toString( )                                        Returns a String object containing a description of 
                                                                    the exception. This method is called by println( ) 
                                                                    when outputting a Throwable object.


The following example declares a new subclass of Exception and then uses that subclass to signal an error condition in a method. It overrides the toString( ) method, allowing the description of the exception to be displayed using println( ).

  // This program creates a custom exception type.
  class MyException extends Exception {
    private int detail;

    MyException(int a) {
      detail = a;
    }

    public String toString() {
      return "MyException[" + detail + "]";
    }
  }

  class ExceptionDemo {
    static void compute(int a) throws MyException {
      System.out.println("Called compute(" + a + ")");
      if(a > 10)
        throw new MyException(a);
      System.out.println("Normal exit");
    }

    public static void main(String args[]) {
      try {
        compute(1);
        compute(20);
      } catch (MyException e) {
        System.out.println("Caught " + e);
      }
    }
  }

This example defines a subclass of Exception called MyException. This subclass is quite simple: it has only a constructor plus an overloaded toString( ) method that displays the value of the exception. The ExceptionDemo class defines a method named compute( ) that throws a MyException object. The exception is thrown when compute( )’s integer parameter is greater than 10. The main( ) method sets up an exception handler for MyException, then calls compute( ) with a legal value (less than 10) and an illegal one to show both paths through the code. Here is the result:

  Called compute(1)
  Normal exit
  Called compute(20)
  Caught MyException[20]




Chained Exceptions

Java 2, version 1.4 added a new feature to the exception subsystem: chained exceptions. The chained exception feature allows you to associate another exception with an exception. This second exception describes the cause of the first exception. For example, imagine a situation in which a method throws an ArithmeticException because of an attempt to divide by zero. However, the actual cause of the problem was that an I/O error occurred, which caused the divisor to be set improperly. Although the method must certainly throw an ArithmeticException, since that is the error that occurred, you might also want to let the calling code know that the underlying cause was an I/O error. Chained exceptions let you handle this, and any other situation in which layers of exceptions exist.

To allow chained exceptions, Java 2, version 1.4 added two constructors and two methods to Throwable. The constructors are shown here.

  Throwable(Throwable causeExc)
  Throwable(String msg, Throwable causeExc)

In the first form, causeExc is the exception that causes the current exception. That is, causeExc is the underlying reason that an exception occurred. The second form allows you to specify a description at the same time that you specify a cause exception. These two constructors have also been added to the Error, Exception, and RuntimeException classes.

The chained exception methods added to Throwable are getCause( ) and initCause( ). These methods are shown in Table 10-3, and are repeated here for the sake of discussion.

  Throwable getCause( )
  Throwable initCause(Throwable causeExc)

The getCause( ) method returns the exception that underlies the current exception. If there is no underlying exception, null is returned. The initCause( ) method associates causeExc with the invoking exception and returns a reference to the exception. Thus, you can associate a cause with an exception after the exception has been created. However, the cause exception can be set only once. Thus, you can call initCause( ) only once for each exception object. Furthermore, if the cause exception was set by a constructor, then you can’t set it again using initCause( ).

In general, initCause( ) is used to set a cause for legacy exception classes which don’t support the two additional constructors described earlier. At the time of this writing, most of Java’s built-in exceptions, such as ArithmeticException, do not define the additional constructors. Thus, you will use initCause( ) if you need to add an exception chain to these exceptions. When creating your own exception classes you will want to add the two chained-exception constructors if you will be using your exceptions in situations in which layered exceptions are possible.

Here is an example that illustrates the mechanics of handling chained exceptions.

  // Demonstrate exception chaining.
  class ChainExcDemo {
    static void demoproc() {
      // create an exception
      NullPointerException e =
        new NullPointerException("top layer");

      // add a cause
      e.initCause(new ArithmeticException("cause"));

      throw e;
    }

    public static void main(String args[]) {
      try {
        demoproc();
      } catch(NullPointerException e) {
        // display top level exception
        System.out.println("Caught: " + e);

        // display cause exception
        System.out.println("Original cause: " + e.getCause());
      }
    }
  }

The output from the program is shown here.

  Caught: java.lang.NullPointerException: top layer
  Original cause: java.lang.ArithmeticException: cause

In this example, the top-level exception is NullPointerException. To it is added a cause exception, ArithmeticException. When the exception is thrown out of demoproc( ), it is caught by main( ). There, the top-level exception is displayed, followed by the underlying exception, which is obtained by calling getCause( ).

Chained exceptions can be carried on to whatever depth is necessary. Thus, the cause exception can, itself, have a cause. Be aware that overly long chains of exceptions may indicate poor design.

Chained exceptions are not something that every program will need. However, in cases in which knowledge of an underlying cause is useful, they offer an elegant solution.




Using Exceptions

Exception handling provides a powerful mechanism for controlling complex programs that have many dynamic run-time characteristics. It is important to think of try, throw, and catch as clean ways to handle errors and unusual boundary conditions in your program’s logic. If you are like most programmers, then you probably are used to returning an error code when a method fails. When you are programming in Java, you should break this habit. When a method can fail, have it throw an exception. This is a cleaner way to handle failure modes.

One last point: Java’s exception-handling statements should not be considered a general mechanism for nonlocal branching. If you do so, it will only confuse your code and make it hard to maintain.