Thursday 23 March 2017

Observable, Timer and TimerTask & Currency - Java Tutorials

Observable

The Observable class is used to create subclasses that other parts of your program can observe. When an object of such a subclass undergoes a change, observing classes are notified. Observing classes must implement the Observer interface, which defines the update( ) method. The update( ) method is called when an observer is notified of a change in an observed object.

An object that is being observed must follow two simple rules. First, if it has changed, it must call setChanged( ). Second, when it is ready to notify observers of this change, it must call notifyObservers( ). This causes the update( ) method in the observing object(s) to be called. Be careful—if the object calls notifyObservers( ) without having previously called setChanged( ), no action will take place. The observed object must call both setChanged( ) and notifyObservers( ) before update( ) will be called.


The Methods Defined by Observable

void addObserver(Observer obj):  Add obj to the list of objects observing the invoking object.

protected void clearChanged( ):  Calling this method returns the status of the invoking object to “unchanged.”

int countObservers( ):  Returns the number of objects observing the invoking object.

void deleteObserver(Observer obj):  Removes obj from the list of objects observing the invoking object.

void deleteObservers( ):  Removes all observers for the invoking object.

boolean hasChanged( ):  Returns true if the invoking object has been modified and false if it has not.

void notifyObservers( ):  Notifies all observers of the invoking object that it has changed by calling update( ). A null is passed as the second argument to update( ).

void notifyObservers(Object obj):  Notifies all observers of the invoking object that it has changed by calling update( ). obj is passed as an argument to update( ).

protected void setChanged( ):  Called when the invoking object has changed.


Notice that notifyObservers( ) has two forms: one that takes an argument and one that does not. If you call notifyObservers( ) with an argument, this object is passed to the observer’s update( ) method as its second parameter. Otherwise, null is passed to update( ). You can use the second parameter for passing any type of object that is appropriate for your application.


The Observer Interface

To observe an observable object, you must implement the Observer interface. This interface defines only the one method shown here:

      void update(Observable observOb, Object arg)

Here, observOb is the object being observed, and arg is the value passed by notifyObservers( ). The update( ) method is called when a change in the observed object takes place.


An Observer Example

Here is an example that demonstrates an observable object. It creates an observer class, called Watcher, that implements the Observer interface. The class being monitored is called BeingWatched. It extends Observable. Inside BeingWatched is the method counter( ), which simply counts down from a specified value. It uses sleep( ) to wait a tenth of a second between counts. Each time the count changes, notifyObservers( ) is called with the current count passed as its argument. This causes the update( ) method inside Watcher to be called, which displays the current count. Inside main( ), a Watcher and a BeingWatched object, called observing and observed, respectively, are created. Then, observing is added to the list of observers for observed. This means that observing.update( ) will be called each time counter( ) calls notifyObservers( ).

  /* Demonstrate the Observable class and the
     Observer interface.
  */

  import java.util.*;

  // This is the observing class.
  class Watcher implements Observer {
    public void update(Observable obj, Object arg) {
      System.out.println("update() called, count is " +
                         ((Integer)arg).intValue());
    }
  }                       

  / This is the class being observed.
  class BeingWatched extends Observable {
    void counter(int period) {
      for( ; period >=0; period--) {
        setChanged();
        notifyObservers(new Integer(period));
        try {
          Thread.sleep(100);
        } catch(InterruptedException e) {
          System.out.println("Sleep interrupted");
        }
      }
    }
  
  }

  class ObserverDemo {
    public static void main(String args[]) {
      BeingWatched observed = new BeingWatched();
      Watcher observing = new Watcher();

      /* Add the observing to the list of observers for
         observed object. */
      observed.addObserver(observing);

      observed.counter(10);
    }
  }

The output from this program is shown here:

  update() called, count is 10
  update() called, count is 9
  update() called, count is 8
  update() called, count is 7
  update() called, count is 6
  update() called, count is 5
  update() called, count is 4
  update() called, count is 3
  update() called, count is 2
  update() called, count is 1
  update() called, count is 0

More than one object can be an observer. For example, the following program implements two observing classes and adds an object of each class to the BeingWatched observer list. The second observer waits until the count reaches zero and then rings the bell.

  /* An object may be observed by two or more
     observers.
  */

  import java.util.*;

  // This is the first observing class.
  class Watcher1 implements Observer {
    public void update(Observable obj, Object arg) {
      System.out.println("update() called, count is " +
                         ((Integer)arg).intValue());
    }
  }

  // This is the second observing class.
  class Watcher2 implements Observer {
    public void update(Observable obj, Object arg) {
      // Ring bell when done
      if(((Integer)arg).intValue() == 0)
        System.out.println("Done" + '\7');
    }
  }

  // This is the class being observed.
  class BeingWatched extends Observable {
    void counter(int period) {
      for( ; period >=0; period--) {
        setChanged();
        notifyObservers(new Integer(period));
        try {
          Thread.sleep(100);
        } catch(InterruptedException e) {
          System.out.println("Sleep interrupted");
        }
      }
    }
  }

  class TwoObservers {
    public static void main(String args[]) {
      BeingWatched observed = new BeingWatched();
      Watcher1 observing1 = new Watcher1();
      Watcher2 observing2 = new Watcher2();

      // add both observers
      observed.addObserver(observing1);
      observed.addObserver(observing2);

      observed.counter(10);
    }
  }

The Observable class and the Observer interface allow you to implement sophisticated program architectures based on the document/view methodology. They are also useful in multithreaded situations.




Timer and TimerTask

Java 2, version 1.3 added an interesting and useful feature to java.util: the ability to schedule a task for execution at some future time. The classes that support this are Timer and TimerTask. Using these classes you can create a thread that runs in the background, waiting for a specific time. When the time arrives, the task linked to that thread is executed. Various options allow you to schedule a task for repeated execution, and to schedule a task to run on a specific date. Although it was always possible to manually create a task that would be executed at a specific time using the Thread class, Timer and TimerTask greatly simplify this process.

Timer and TimerTask work together. Timer is the class that you will use to schedule a task for execution. The task being scheduled must be an instance of TimerTask. Thus, to schedule a task, you will first create a TimerTask object and then schedule it for execution using an instance of Timer.

TimerTask implements the Runnable interface; thus it can be used to create a thread of execution. Its constructor is shown here:

      TimerTask( )

Notice that run( ) is abstract, which means that it must be overridden. The run( ) method, defined by the Runnable interface, contains the code that will be executed. Thus, the easiest way to create a timer task is to extend TimerTask and override run( ).


The Methods Defined by TimerTask

boolean cancel( ):  Terminates the task. It returns true if an execution of the task is prevented. Otherwise, false is returned.

abstract void run( ):  Contains the code for the timer task.

long scheduledExecutionTime( ):  Returns the time at which the last execution of the task was scheduled to have occurred.


Once a task has been created, it is scheduled for execution by an object of type Timer. The constructors for Timer are shown here.

      Timer( )

      Timer(boolean DThread)

The first version creates a Timer object that runs as a normal thread. The second uses a daemon thread if DThread is true. A daemon thread will execute only as long as the rest of the program continues to execute.


The Methods Defined by Timer

void cancel( ):  Cancels the timer thread.

void schedule(TimerTask TTask, long wait):  TTask is scheduled for execution after the period passed in wait has elapsed. The wait parameter is specified in milliseconds.

void schedule(TimerTask TTask, long wait, long repeat):  TTask is scheduled for execution after the period passed in wait has elapsed. The task is then executed repeatedly at the interval specified by repeat. Both wait and repeat are specified in milliseconds.

void schedule(TimerTask TTask, Date targetTime):  TTask is scheduled for execution at the time specified by targetTime.

void schedule(TimerTask TTask, Date targetTime, long repeat):  TTask is scheduled for execution at the time specified by targetTime. The task is then executed repeatedly at the interval passed in repeat. The repeat parameter is specified in milliseconds.

void scheduleAtFixedRate(TimerTask TTask, long wait, long repeat):  TTask is scheduled for execution after the period passed in wait has elapsed. The task is then executed repeatedly at the interval specified by repeat. Both wait and repeat are specified in milliseconds. The time of each repetition is relative to the first execution, not the preceding execution. Thus, the overall rate of execution is fixed.

void scheduleAtFixedRate(TimerTask TTask, Date targetTime, long repeat):  TTask is scheduled for execution at the time specified by targetTime. The task is then executed repeatedly at the interval passed in repeat. The repeat parameter is specified in milliseconds. The time of each repetition is relative to the first execution, not the preceding execution. Thus, the overall rate of execution is fixed.


Once a Timer has been created, you will schedule a task by calling schedule( ) on the Timer that you created. As Table 16-9 shows, there are several forms of schedule( ) which allow you to schedule tasks in a variety of ways.

If you create a non-daemon task, then you will want to call cancel( ) to end the task when your program ends. If you don’t do this, then your program may “hang” for a period of time.

The following program demonstrates Timer and TimerTask. It defines a timer task whose run( ) method displays the message “Timer task executed.” This task is scheduled to run once very half second after an intial delay of one second.

  // Demonstrate Timer and TimerTask.

  import java.util.*;

  class MyTimerTask extends TimerTask {
    public void run() {
      System.out.println("Timer task executed.");
    }
  }

  class TTest {
    public static void main(String args[]) {
      MyTimerTask myTask = new MyTimerTask();
      Timer myTimer = new Timer();

      /* Set an initial delay of 1 second,
         then repeat every half second.
      */
      myTimer.schedule(myTask, 1000, 500);

      try {
        Thread.sleep(5000);
      } catch (InterruptedException exc) {}

      myTimer.cancel();
    }
  }




Currency

Java 2, version 1.4 adds the Currency class. This class encapsulates information about a currency. It defines no constructors. The following program demonstrates Currency.

  // Demonstrate Currency.
  import java.util.*;

  class CurDemo {
    public static void main(String args[]) {
      Currency c;
      c = Currency.getInstance(Locale.US);

      System.out.println("Symbol: " + c.getSymbol());
      System.out.println("Default fractional digits: " +
                         c.getDefaultFractionDigits());
    }
  }

The output is shown here.

  Symbol: $
  Default fractional digits: 2


The Methods Defined by Currency

String getCurrencyCode( ):  Returns the code (as defined by ISO 4217) that describes the invoking currency.

int getDefaultFractionDigits( ):  Returns the number of digits after the decimal point that are normally used by the invoking currency. For example, there are 2 fractional digits normally used for dollars.

static Currency getInstance(Locale localeObj):  Returns a Currency object for the locale specified by localeObj.

static Currency getInstance(String code):  Returns a Currency object associated with the currency code passed in code.

String getSymbol( ):  Returns the currency symbol (such as $) for the invoking object.

String getSymbol(Locale localeObj):  Returns the currency symbol (such as $) for the locale passed in localeObj.

String toString( ):  Returns the currency code for the invoking object.


The java.util.zip Package

The java.util.zip package provides the ability to read and write files in the popular ZIP and GZIP file formats. Both ZIP and GZIP input and output streams are available. Other classes implement the ZLIB algorithms for compression and decompression.


The java.util.jar Package

The java.util.jar package provides the ability to read and write Java Archive (JAR) files. You will see in Chapter 25 that JAR files are used to contain software components known as Java Beans and any associated files.

No comments:

Post a Comment