Thursday, December 3, 2009

Java Exception


What Exceptions Are

Download Sample SouceCode :Exception.zip

Exceptions are objects that describe any error caused by an external resource not being available or an internal processing problem. They are passed to exception handlers written by the programmer to enable graceful recovery. If the handler has not been written, the program will terminate with a display of the Exception class. There are many exception classes such as IOException and NumberFormatException.

Exception Handling

Exception handling is a method of trapping or coping with anticipated errors (system, data entry or calculation) and handling or dealing with them in a graceful manner. The Exception class of objects offers a rich group of subclasses to trap specific errors and recover from them.
A thread is the flow of execution of a single set of program statements. Multithreading consists of multiple sets of statements which can be run in parallel. With a single processor only one thread can run at a time but strategies are used to make it appear as if the threads are running simultaneously. Depending on the operating system, either timeslicing or interrupt methods will move the processing from one thread to the next.


Checked and Unchecked Exceptions

  • Two kinds of exceptions, checked and unchecked.
  • Anything from a runtime exception is an unchecked exception. Meaning you don't have to provided a try/catch block. Subclasses of Error or RuntimeException.

try/catch block

The code that might throw an exception is enclosed in the try block. One or more catch clauses can be provided to handle different exception types:
 
  try 
  {
    // code that might throw exceptions
  }
  catch(Exception e)
  { 
    //code to handle the exception 
  }

finally block

The finally block can also be provided to perform any cleanup operation. If an exception is thrown, any matching catch clauses are executed, then control comes to the finally block, if one is provided. The syntax of the finally block is as follows:
 
  try 
  {
    // code that throws exceptions
  }
  catch(Exception e)
  {
    // handle exception
  }
  finally
  {
    // cleanup code
  }

The finally block is executed even if no exception is thrown. The only case in which this does not happen is when System.exit() is invoked by the try or catch blocks. A try block should have either a catch block or a finally block, but it's not required to have both.

Example
/**
*
* @author Arunkumar Subramaniam
*
*/
public class Test {
public static void main(String s[]){
try{ int i=0;
i=10/i;
}catch(Exception e){
System.out.println(e);
}
}
}

or

/**
*
* @author Arunkumar Subramaniam
*
*/
public class Test {
public static void main(String s[]){
try{
int i=0;
i=10/i;
}catch(ArithmeticException e){
System.out.println(e);
}catch(Exception e){
System.out.println(e);
}
}
}


Throws And Throw

throw is used to throw an exception manually, where as throws is used in the case of checked exceptions, to reintimate the compiler that we have handled the exception. so throws is to be used at the time of defining a method and also at the time of calling that function, which rises an checked exception.

/**
*
* @author Arunkumar Subramaniam
*
*/
public class Test {
void hello() throws ArithmeticException ,Exception {
try{
int i=0;
i=10/i;
}catch(ArithmeticException e){
throw new ArithmeticException();
}

}

void altHello() throws ArithmeticException ,Exception{
int i=0;
i=10/i;

}

public static void main(String s[]){
Test t=new Test();

try {
t.altHello();

} catch (ArithmeticException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

try {
t.hello();
} catch (ArithmeticException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

}
}


User Defined Exception

Programmers could also create user-defined exceptions, specific to their business. Let's say you are in business selling bikes and need to validate a customers order. Create a new class TooManyBikesException that is derived from the class Exception or Throwable, and if someone tries to order more bikes than you can ship - just throw this exception:

/**
*
* @author Arunkumar Subramaniam
*
*/

public class ArunException extends Exception{

public ArunException(Exception e){
super(e);
}


}

/**
*
* @author Arunkumar Subramaniam
*
*/
public class TestException {

void hello()throws ArunException{
try{
int i=0;
i=10/i;
}catch(ArithmeticException e){
throw new ArunException(e);
}
}

void altHello()throws Exception{

int i=10;
i=10/i;
if(i==1){
throw new ArunException(new Exception("by mi2arun"));
}
}


public static void main(String str[]){
TestException t=new TestException();
try {
t.hello();
} catch (ArunException e) {
e.printStackTrace();
}
try {
t.altHello();
} catch (ArunException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

output :

ArunException: java.lang.ArithmeticException: / by zero
at TestException.hello(TestException.java:9)
at TestException.main(TestException.java:26)
Caused by: java.lang.ArithmeticException: / by zero
at TestException.hello(TestException.java:7)
... 1 more
ArunException: java.lang.Exception: by mi2arun
at TestException.altHello(TestException.java:18)
at TestException.main(TestException.java:31)
Caused by: java.lang.Exception: by mi2arun
... 2 more

Java Collections & Maps


Interfaces

>The symbols shown in the figure above define interfaces. They can only be used as attribute definition, not as instantiation class names:

Collection xx = null;
xx = new Collection ( ); // error !
Set yy = null;
SortedSet zz = null;

The figure also provides the directions of the dependencies.

xx = yy;
xx = zz;
yy = xx; // error !

Corresponding Implementations

Implementations
Hash Table
Resizable Array
Balanced Tree
Linked List
Interfaces
Collection
HashSet
ArrayList
TreeSet
LinkedList
Set
HashSet
TreeSet
SortedSet
TreeSet
List
ArrayList
LinkedList
Map
HashMap
TreeMap
SortedMap
TreeMap

The table above defines the implementations that correspond to the interfaces shown in the previous figure. An object defined by an interface must be instantiated by means of a class lying on the same line as the interface :

Collection xx1 = new HashSet ( ); // HashSet on the same line as Collection
Collection xx2 = new ArrayList ( );

SortedSet yy = new TreeSet ( );

Of course each collection can also be instantiated under its proper class:

ArrayList al = new ArrayList ( );

Main Characteristics of the Collections and Maps

All collections are used in a very similar way. What changes is the way in which the elements are stored in the collection:

ordered, with duplicates, with an access based on a key...

Moreover, some accesses may be more efficient in a collection or another one:

an ArrayList is created with an extra capacity, it must not be reallocated each time it grows
a LinkedList and an ArrayList can be used to create a fifo (list.add() / list.remove(0))
a TreeMap and a TreeSet are ordered (and thus need comparators)
a Set and a Map cannot contain duplicates
a Map contains pairs of (key;object). the elements are ordered and can be accessed by the key
the elements of some collections can be addressed by index
the collections can be walked through sequentially (iterator)
to walk through a Map, a collection must first be extracted

(see details below).

Storing Objects in a Collection or a Map

The basic methods to insert objects into a collection are given below:

HashSet, TreeSet

set.add(object);

add somewhere, in the order of the elements

LinkedList

list.add(object);
list.add(index, object);

adds at the end
adds at index and shifts the previous
elements from index towards the end

ArrayList

list.add(object)
list.add(index, object);
list.set(index,object);

adds at the end
adds at index and shifts the previous elements
overwrite the value at index

The basic methods to insert objects into a map are indicated below:

HashMap
TreeMap

map.put(key,value);

both key and value are Objects
in the tree maps, keys are put in order of the keys

Note: the aggregations that store the objects in an ordered manner (TreeSet and TreeMap) must know how to compare the inserted objects (respectively keys). There are two ways to do that:

  • have the objects (respectively keys) that are inserted in the tree aggregation implement Comparable

  • provide a Comparator in the parameters of the instantiation of the aggregation

  • Retrieving and Managing Objects in a Collection or a Map

    Some methods are known by all aggregations:

    clear( ); size( ); remove (object);

    Some of the methods defined in a collection are given below:

    LinkedList

    obj = c.get(index);

    obj = c.remove(index);

    bool = c.contains(obj);

    objArr = c.toArray( );

    ArrayList

    obj = c.get(index);

    obj = c.remove(index);

    bool = c.contains(obj);

    objArr = c.toArray( );

    HashSet

    -

    see 1 inch above

    bool = c.contains(obj);

    objArr = c.toArray( );

    TreeSet

    -

    see 1 inch above

    bool = c.contains(obj);

    objArr = c.toArray( );

    Some of the methods defined in a map are defined below (Object obj, key;) :

    HashMap
    TreeMap

    obj = m.get (key);

    obj = m.remove (key);

    bool = m.containsKey (key);
    bool = m.containsValue( key);

    collection = m.values( );
    set = m.keySet( );

    The operations of the last column return collections of elements. These collections can be used to walk through the trees.

    Transformations

    Passing from one aggregation type to another one can be used to sort the elements, eliminate the duplicates, create an array, and so on.

    A collection of any type can be transformed to another one:

    Set set = new HashSet ( );
    .... fill in the set ....
    SortedSet ss = new TreeSet ( set );

    Parameter available for the instantiation:

    LinkedList

    ( )

    (Collection)

    ArrayList

    ( )

    (Collection)

    (initialCapacity)

    HashSet

    ( )

    (Collection)

    (initialCapacity)

    (initialCapacity, loadFactor)

    HashMap

    ( )

    (Map)

    (initialCapacity)

    (initialCapacity, loadFactor)

    TreeSet

    ( )

    (Collection)

    (Comparator)

    (SortedSet)

    TreeMap

    ( )

    (Map)

    (Comparator)

    (SortedMap)

    The maps return collections containing only the objects (keys are dropped)

    Collection col = tm.values();

    which can used as parameter in the instantiation of a collection.

    A collection can be transformed into an array with:

    Object [] obj = collection.toArray();

    Java Inner Class


    What are Nested/Inner classes.

    Download SampleCode:Outter.java

    Up until the introduction of Jdk 1.1, the java language only supported top-level classes. Top level classes are classes that are defined as members of a package. But with Jdk 1.1, sun introduced the concept of nested/inner classes in java. Nested/inner classes are classes within classes. Inner/Nested classes makes it much easier for developer to connect object together, since classes can be defined closer to the objects. First of all before you go any further, you must know that this feature of java is only limited to the compiler. In other words to compile java code that contains nested/inner classes, you will need Jdk 1.1 or later but the compiled code can be executed on any jvm. You've probably used inner classes already in java without noticing it. A typical example of the usage of an inner class is when creating an adapter class to listen to events in a GUI. Nested/inner classes gives a developer lots of power, but when they are not properly use or understood, they can be very confusing. Here is the main difference between Nested and Inner classes

    Nested class

    A nested class has the same behavior as any static member of a class. You can have access to it without initializing the parent class, and they can access the parent class static methods and variables also. Nested classes are always define with the keyword static (and we will see later that this is what differentiate them from the inner classes). An access tag (i.e. : public, protected or private) can be defined, but by default a nested class takes the default package access. Sun considers nested classes to be top-level classes (I find this at times to be confusing). Here is an example of how to define a nested class MyInner in the class enclosing class MyOuter.

    class MyOuter {

    public static class MyInner {
    //...
    public void function1() {}
    //more function (static and more)
    }
    }

    Notice that when you compile this code, you will have two .class file as the output :

    MyOuter.class : being the enclosing class.

    MyOuter$MyInner.class : being the inner class. Since class MyInner is a static member of MyOuter, it can be access from anywhere in your code using MyOuter.MyInner (The same way that you access classes in packages, you can even use the import statement with nested classes : import MyOuter.MyInner).

    Example :

    Here is the code to call the constructor of class MyInner anywhere in your code :

     public MyInner myclass = MyOuter.MyInner();

    However, if the class MyOuter was define in the package my.package you will write :


    MyInner myclass = my.package.MyOuter.MyInner();

    As you can see you do not have to create an instance of class MyOuter to use class MyInner. Class MyOuter serves a package for class MyInner. Personally I would recommend not using Nested classes (unless you really think that no classes outside the scope your object would ever want to use the nested classes), most of the time, it is much easier and cleaner to define the class in a separate .java file instead.

    Inner Class

    Inner class differ very much from nested class because it does not have a static tag, as a matter of fact you can never write an inner class with the static tag (when you add the static tag it automatically becomes a nested class). Unlike a nested class, every instance of an inner class requires an instance of the enclosing class, and an enclosing class can have multiple instance of the inner class. Without going into too much details, here are the three types of inner class:

    Member inner classes

    This type of inner class is defined as members of the enclosing class, they are defined on the same level as function and variables of a class, and have the same behavior and properties.

    Example :
    class MyOuter
    {
    private float variable = 0;
    public void donothing() { //do your stuff }
    private class MyInner
    {
    public void innerfunction() {//do your stuff }
    public void function()
    {
    //Do your stuff
    //Here is how you call a function with the
    same name
    //from the enclosing class
    MyOutter.this.donothing();
    }
    }
    }

    The inner class MyInner class is a Member inner class. Notice in the example above, I had a name conflict with the enclosing class MyOuter when trying to call the function donothing(), that is why I added the line MyOuter.this.donothing(). This forces the compiler to get take the current instance of the enclosing class function instead.

    Local inner classes

    This type of inner class is defined inside a bloc of code. However, like any object they can live beyond the scope of the bloc of code inside witch they are defined, this depends on what you do with them.

    Example :
    Interface MyInterface
    {
    public String getInfo();
    }
    class MyOuter
    {
    MyInterface current_object;
    public void setInterface(String info)
    {
    class MyInner implement MyInterface
    {
    private String info;
    public MyInner(String inf) {info=inf;}
    public string getInfo() {return info;}
    }
    current_object = new MyInner(info);
    }
    }
    In the example above, the class MyInner is a local inner class.

    Anonymous inner classes

    This is a very special type of inner class. An anonymous inner class usually does not have a name. You probably used anonymous inner classes before. They are often used in GUI development to implement listeners. Here is an example of the most frequent use of anonymous inner class in java.

    Example :

    class Outer extends java.awt.Frame
    {
    public Outer()
    {
    java.awt.Button button = new java.awt.Button
    ("Click on me");
    button.addActionListener(new ActionListener()
    {
    public void actionPerformed(ActionEvent e)
    {
    System.out.println("You clicked");
    }
    });
    }
    }
    In the code above the class ActionListener is an anonymous class.

    Advantages of using Nested/Inner class

    Inner class be very powerful;l development tools when you know how to use them. Here are a just a few advantages that nested/inner classes can give you.

    Blocs of codes.

    One of the main reasons sun introduced Nested/Inner classes in java is to give developers the ability to implement blocs of codes, that can be used to realize special functions inside a given object (pointers to methods). Using inner classes you can integrate blocs of code inside your object to perform special task pretty much like you have method pointers in C.

    Integrate object in objects

    By giving the developers the ability to integrate blocs of code in objects via inner class, developer now have the ability to integrate objects in objects, this is a very big advantage since your code can now have a more object oriented design. You can create special objects as part of another object. In a way your code can become much easier to read, and also your code is more object oriented. Now it is possible to separate the logic in your objects in inner objects. Example if you have a class Engine, and you define an interface EnginePower in the same package. You can create a inner object that implement the interface EnginePower inside the class Engine for a specific type of engine (i.e. JetEngine). This is a pretty efficient method of coding since you know that the inner class EnginePower is tightly linked to the enclosing class Engine and the user would only want to access the EnginePower interface

    Callbacks.

    Inner class are also very useful when you want to implement callbacks. A very good example of the advantage of using an inner class for callbacks is when implementing GUI event listeners (see example above). If you try to implement the callback procedure mention in the example for anonymous inner class without inner class, then you will have to implement the ActionLlistener interface in a class and this would force you to use a bunch of if and else if to figure out on which object the event occurred. Using inner classes allows you to efficiently have a separate bloc of code to do handle the actionPerformed function for every graphic component object.

    Java Reference Type Casting


    In java one object reference can be cast into another object reference. The cast can be to its own class type or to one of its subclass or superclass types or interfaces. There are compile-time rules and runtime rules for casting in java. The casting of object references depends on the relationship of the classes involved in the same hierarchy. Any object reference can be assigned to a reference variable of the type Object, because the Object class is a superclass of every Java class.

    There can be 2 types of casting

    · Upcasting
    · Downcasting

    When we cast a reference along the class hierarchy in a direction from the root class towards the children or subclasses, it is a downcast.
    When we cast a reference along the class hierarchy in a direction from the sub classes towards the root, it is an upcast. We need not use a cast operator in this case.


    The compile-time rules are there to catch attempted casts in cases that are simply not possible. This happens when we try to attempt casts on objects that are totally unrelated (that is not subclass super class relationship or a class-interface relationship)
    At runtime a ClassCastException is thrown if the object being cast is not compatible with the new type it is being cast to.

    Below is an example showing when a ClassCastException can occur during object casting

        

    //X is a supper class of Y and Z which are sibblings.

    public class RunTimeCastDemo{
    public static void main(String args[]){
    X x = new X();
    Y y = new Y();
    Z z = new Z();

    X xy = new Y(); // compiles ok (up the hierarchy)
    X xz = new Z(); // compiles ok (up the hierarchy)
    // Y yz = new Z(); incompatible type (siblings)

    // Y y1 = new X(); X is not a Y
    // Z z1 = new X(); X is not a Z

    X x1 = y; // compiles ok (y is subclass of X)
    X x2 = z; // compiles ok (z is subclass of X)

    Y y1 = (Y) x; // compiles ok but produces runtime error
    Z z1 = (Z) x; // compiles ok but produces runtime error
    Y y2 = (Y) x1; // compiles and runs ok (x1 is type Y)
    Z z2 = (Z) x2; // compiles and runs ok (x2 is type Z)
    // Y y3 = (Y) z; inconvertible types (siblings)
    // Z z3 = (Z) y; inconvertible types (siblings)

    Object o = z;
    Object o1 = (Y)o; // compiles ok but produces runtime error

    }
    }


    Casting Object References: Implicit Casting using a Java Compiler


    In general an implicit cast is done when an Object reference is assigned (cast) to:

    • A reference variable whose type is the same as the class from which the object was instantiated.
      An Object as Object is a super class of every Java Class.
    • A reference variable whose type is a super class of the class from which the object was instantiated.
    • A reference variable whose type is an interface that is implemented by the class from which the object was instantiated.
    • A reference variable whose type is an interface that is implemented by a super class of the class from which the object was instantiated.


    Consider an interface Vehicle, a super class Car and its subclass Ford. The following example shows the automatic conversion of object references handled by the java compiler


       interface Vehicle {
    }
    class Car implements Vehicle {
    }

    class Ford extends Car {
    }



    Let c be a variable of type Car class and f be of class Ford and v be an vehicle interface reference. We can assign the Ford reference to the Car variable:
    I.e. we can do the following

    Example 1
    c = f; //Ok Compiles fine

    Where c = new Car();
    And, f = new Ford();
    The compiler automatically handles the conversion (assignment) since the types are compatible (sub class - super class relationship), i.e., the type Car can hold the type Ford since a Ford is a Car.


    Example 2
    v = c; //Ok Compiles fine
    c = v; // illegal conversion from interface type to class type results in compilation error

    Where c = new Car();
    And v is a Vehicle interface reference (Vehicle v)

    The compiler automatically handles the conversion (assignment) since the types are compatible (class – interface relationship), i.e., the type Car can be cast to Vehicle interface type since Car implements Vehicle Interface. (Car is a Vehicle).

    Casting Object References: Explicit Casting

    Sometimes we do an explicit cast in java when implicit casts don’t work or are not helpful for a particular scenario. The explicit cast is nothing but the name of the new “type” inside a pair of matched parentheses. As before, we consider the same Car and Ford Class


    class Car {
    void carMethod(){
    }
    }

    class Ford extends Car {
    void fordMethod () {
    }
    }

    We also have a breakingSystem() function which takes Car reference (Superclass reference) as an input parameter.
    The method will invoke carMethod() regardless of the type of object (Car or Ford Reference) and if it is a Ford object, it will also invoke fordMethod(). We use the instanceof operator to determine the type of object at run time.

    public void breakingSystem (Car obj) {
    obj.carMethod();
    if (obj instanceof Ford)

    ((Ford)obj).fordMethod ();
    }

    To invoke the fordMethod(), the operation (Ford)obj tells the compiler to treat the Car object referenced by obj as if it is a Ford object. Without the cast, the compiler will give an error message indicating that fordMethod() cannot be found in the Car definition.

    The following java shown illustrates the use of the cast operator with references.

    Note: Classes Honda and Ford are Siblings in the class Hierarchy. Both these classes are subclasses of Class Car. Both Car and HeavyVehicle Class extend Object Class. Any class that does not explicitly extend some other class will automatically extends the Object by default. This code instantiates an object of the class Ford and assigns the object's reference to a reference variable of type Car. This assignment is allowed as Car is a superclass of Ford.
    In order to use a reference of a class type to invoke a method, the method must be defined at or above that class in the class hierarchy. Hence an object of Class Car cannot invoke a method present in Class Ford, since the method fordMethod is not present in Class Car or any of its superclasses. Hence this problem can be colved by a simple downcast by casting the Car object reference to the Ford Class Object reference as done in the program.
    Also an attempt to cast an object reference to its Sibling Object reference produces a ClassCastException at runtime, although compilation happens without any error.

     class Car extends Object{
    void carMethod() {
    }
    }

    class HeavyVehicle extends Object{

    }

    class Ford extends Car {
    void fordMethod () {
    System.out.println("I am fordMethod defined in Class Ford");
    }
    }

    class Honda extends Car {
    void fordMethod () {
    System.out.println("I am fordMethod defined in Class Ford");
    }
    }




    public class ObjectCastingEx{
    public static void main(
    String[] args){
    Car obj = new Ford();
    // Following will result in compilation error
    // obj.fordMethod(); //As the method fordMethod is undefined
    for the Car Type
    // Following will result in compilation error
    // ((HeavyVehicle)obj).fordMethod(); //fordMethod is undefined in
    the HeavyVehicle Type
    // Following will result in compilation error

    ((Ford)obj).fordMethod();

    //Following will compile and run
    // Honda hondaObj = (Ford)obj; Cannot convert as they are sibblings

    }
    }

    One common casting that is performed when dealing with collections is, you can cast an object reference into a String.

      import java.util.Vector;

    public class StringCastDemo{
    public static void main(String args[]){
    String username = "asdf";
    String password = "qwer";
    Vector v = new Vector();
    v.add(username);
    v.add(password);


    // String u = v.elementAt(0); Cannot convert from object to String
    Object u = v.elementAt(0); //Cast not done
    System.out.println("Username : " +u);


    String uname = (String) v.elementAt(0); // cast allowed
    String pass = (String) v.elementAt(1); // cast allowed

    System.out.println();
    System.out.println("Username : " +uname);
    System.out.println("Password : " +pass);
    }
    }

    Output

    Username : asdf

    Username : asdf
    Password : qwer

    Java Abstract Class


    Abstract classes are used to declare common characteristics of subclasses. An abstract class cannot be instantiated. It can only be used as a superclass for other classes that extend the abstract class. Abstract classes are declared with the abstract keyword. Abstract classes are used to provide a template or design for concrete subclasses down the inheritance tree.

    Like any other class, an abstract class can contain fields that describe the characteristics and methods that describe the actions that a class can perform. An abstract class can include methods that contain no implementation. These are called abstract methods. The abstract method declaration must then end with a semicolon rather than a block. If a class has any abstract methods, whether declared or inherited, the entire class must be declared abstract. Abstract methods are used to provide a template for the classes that inherit the abstract methods.

    Abstract classes cannot be instantiated; they must be subclassed, and actual implementations must be provided for the abstract methods. Any implementation specified can, of course, be overridden by additional subclasses. An object must have an implementation for all of its methods. You need to create a subclass that provides an implementation for the abstract method.

    A class abstract Vehicle might be specified as abstract to represent the general abstraction of a vehicle, as creating instances of the class would not be meaningful.

        abstract class Vehicle {
    int numofGears;
    String color;
    abstract boolean hasDiskBrake( );
    abstract int getNoofGears( );
    }

      abstract class Vehicle {
    int numofGears;
    String color;
    abstract boolean hasDiskBrake( );
    abstract int getNoofGears( );
    }

    We can also implement the generic shapes class as an abstract class so that we can draw lines, circles, triangles etc. All shapes have some common fields and methods, but each can, of course, add more fields and methods. The abstract class guarantees that each shape will have the same set of basic properties. We declare this class abstract because there is no such thing as a generic shape. There can only be concrete shapes such as squares, circles, triangles etc.

     public class Point extends Shape {
    static int x, y;
    public Point( ) {
    x = 0;
    y = 0;
    }

    public double area( ) {
    return 0;
    }

    public double perimeter( ) {
    return 0;
    }

    public static void print( ){
    System.out.println ( "point: " + x + "," + y );
    }

    public static void main(String args[]){
    Point p = new Point();
    p.print();
    }

    }

    Output

    point: 0, 0

    Notice that, in order to create a Point object, its class cannot be abstract. This means that all of the abstract methods of the Shape class must be implemented by the Point class.

    The subclass must define an implementation for every abstract method of the abstract superclass, or the subclass itself will also be abstract. Similarly other shape objects can be created using the generic Shape Abstract class.

    A big Disadvantage of using abstract classes is not able to use multiple inheritance. In the sense, when a class extends an abstract class, it can’t extend any other class.

    Java Interface


    In Java, this multiple inheritance problem is solved with a powerful construct called interfaces. Interface can be used to define a generic template and then one or more abstract classes to define partial implementations of the interface. Interfaces just specify the method declaration (implicitly public and abstract) and can only contain fields (which are implicitly public static final). Interface definition begins with a keyword interface. An interface like that of an abstract class cannot be instantiated.

    Multiple Inheritance is allowed when extending interfaces i.e. one interface can extend none, one or more interfaces. Java does not support multiple inheritance, but it allows you to extend one class and implement many interfaces.

    If a class that implements an interface does not define all the methods of the interface, then it must be declared abstract and the method definitions must be provided by the subclass that extends the abstract class.

    Below is an example of a Shape interface

       interface Shape {
    public double area( );
    public double volume( );
    }

    Below is a Point class that implements the Shape interface.

      public class Point implements Shape {
    static int x, y;
    public Point( ) {
    x = 0;
    y = 0;
    }

    public double area( ) {
    return 0;
    }

    public double volume( ) {
    return 0;
    }

    public static void print( ){
    System.out.println ( "point: " + x + "," + y );
    }

    public static void main(String args[]){
    Point p = new Point();
    p.print();
    }

    }

    Similarly, other shape objects can be created by interface programming by implementing generic Shape Interface.

    Below is a java interfaces program showing the power of interface programming in java

    Listing below shows 2 interfaces and 4 classes one being an abstract class.
    Note: The method toString in class A1 is an overridden version of the method defined in the class named Object. The classes B1 and C1 satisfy the interface contract. But since the class D1 does not define all the methods of the implemented interface I2, the class D1 is declared abstract.
    Also,
    i1.methodI2() produces a compilation error as the method is not declared in I1 or any of its super interfaces if present. Hence a downcast of interface reference I1 solves the problem as shown in the program. The same problem applies to i1.methodA1(), which is again resolved by a downcast.

    When we invoke the toString() method which is a method of an Object, there does not seem to be any problem as every interface or class extends Object and any class can override the default toString() to suit your application needs. ((C1)o1).methodI1() compiles successfully, but produces a ClassCastException at runtime. This is because B1 does not have any relationship with C1 except they are "siblings". You can't cast siblings into one another.

    When a given interface method is invoked on a given reference, the behavior that results will be appropriate to the class from which that particular object was instantiated. This is runtime polymorphism based on interfaces and overridden methods.

    interface I1{
    void methodI1(); //public static by default
    }

    interface I2 extends I1{
    void methodI2(); //public static by default
    }

    class A1{
    public String methodA1(){
    String strA1 = "I am in methodC1 of class A1";
    return strA1;
    }

    public String toString(){
    return "toString() method of class A1";
    }
    }
    class B1 extends A1 implements I2{
    public void methodI1(){
    System.out.println("I am in methodI1 of class B1");
    }

    public void methodI2(){
    System.out.println("I am in methodI2 of class B1");
    }
    }

    class C1 implements I2{
    public void methodI1(){
    System.out.println("I am in methodI1 of class C1");
    }

    public void methodI2(){
    System.out.println("I am in methodI2 of class C1");
    }
    }

    // Note that the class is declared as abstract as it does not
    //satisfy the interface contract
    abstract class D1 implements I2{
    public void methodI1() {
    }

    //This class does not implement methodI2() hence declared abstract.

    }
    public class InterFaceEx{
    public static void main(String[] args){
    I1 i1 = new B1();
    i1.methodI1(); //OK as methodI1 is present in B1
    // i1.methodI2(); Compilation error as methodI2 not present in I1

    // Casting to convert the type of the reference from type I1 to type I2
    ((I2)i1).methodI2();

    I2 i2 = new B1();
    i2.methodI1(); //OK
    i2.methodI2(); //OK

    // Does not Compile as methodA1() not present in interface reference I1
    // String var = i1.methodA1();

    //Hence I1 requires a cast to invoke methodA1

    String var2 = ((A1)i1).methodA1();
    System.out.println("var2 : "+var2);
    String var3 = ((B1)i1).methodA1();
    System.out.println("var3 : "+var3);
    String var4 = i1.toString();
    System.out.println("var4 : "+var4);
    String var5 = i2.toString();
    System.out.println("var5 : "+var5);

    I1 i3 = new C1();
    String var6 = i3.toString();
    System.out.println("var6 : "+var6);
    //It prints the Object toString() method

    Object o1 = new B1();
    // o1.methodI1(); does not compile as Object class
    does not define methodI1()
    //To solve the probelm we need to downcast o1 reference.
    We can do it in the following 4 ways
    ((I1)o1).methodI1(); //1
    ((I2)o1).methodI1(); //2
    ((B1)o1).methodI1(); //3

    /*
    * B1 does not have any relationship with C1 except they are "siblings".
    * Well, you can't cast siblings into one another.
    */
    // ((C1)o1).methodI1(); Produces a ClassCastException



    }
    }


    Output

    I am in methodI1 of class B1
    I am in methodI2 of class B1
    I am in methodI1 of class B1
    I am in methodI2 of class B1
    var2 : I am in methodC1 of class A1
    var3 : I am in methodC1 of class A1
    var4 : toString() method of class A1
    var5 : toString() method of class A1
    var6 : C1@190d11
    I am in methodI1 of class B1
    I am in methodI1 of class B1
    I am in methodI1 of class B1

    Polymorphism

    Polymorphism means one name, many forms. There are 3 distinct forms of Java Polymorphism; Method overloading (Compile time polymorphism) Method overriding through inheritance (Run time polymorphism) Method overriding through the Java interface (Run time polymorphism) Polymorphism allows a reference to denote objects of different types at different times during execution. A super type reference exhibits polymorphic behavior, since it can denote objects of its subtypes.
        interface Shape {
    public double area( );
    public double volume( );
    }

    class Cube implements Shape {
    int x= 10;

    public double area( ) {
    return (6 * x * x);
    }

    public double volume( ) {
    return (x * x * x);
    }
    }

    class Circle implements Shape {
    int radius = 10;

    public double area( ) {
    return (Math.PI * radius * radius);
    }

    public double volume( ) {
    return 0;
    }

    }

    public class PolymorphismTest{
    public static void main(String args[]){
    Shape[] s = {new Cube(), new Circle()};

    for( int i = 0; i< s.length; i++){
    System.out.println("The area and volume of "+s[i].getClass()
    + " is "+s[i].area()+" , "+s[i].volume());
    }
    }
    }

    Output

    The area and volume of class Cube is 600.0 , 1000.0
    The area and volume of class Circle is 314.1592653589793 , 0.0

    Java Wrapper Class


    Wrapper classes correspond to the primitive data types in the Java language. These classes represent the primitive values as objects. All the wrapper classes except Character have two constructors -- one that takes the primitive value and another that takes the String representation of the value. For instance:

        Integer i1 = new Integer(50);    Integer i2 = new Integer("50");  

    The Character class constructor takes a char type element as an argument:

        Character c = new Character('A');  

    Wrapper objects are immutable. This means that once a wrapper object has a value assigned to it, that value cannot be changed.

    The valueOf() method

    All wrapper classes (except Character) define a static method called valueOf(), which returns the wrapper object corresponding to the primitive value represented by the String argument. For instance:
        Float f1 = Float.valueOf("1.5f");  

    The overloaded form of this method takes the representation base (binary, octal, or hexadecimal) of the first argument as the second argument. For instance:

        Integer I = Integer.valueOf("10011110",2);  

    Converting wrapper objects to primitives

    All the numeric wrapper classes have six methods, which can be used to convert a numeric wrapper to any primitive numeric type. These methods are byteValue, doubleValue, floatValue, intValue, longValue, and shortValue. An example is shown below:
        Integer i = new Integer(20);    byte b = i.byteValue();  

    Parser methods

    The six parser methods are parseInt, parseDouble, parseFloat, parseLong, parseByte, and parseShort. They take a String as the argument and convert it to the corresponding primitive. They throw a NumberFormatException if the String is not properly formed. For instance:
        double d = Double.parseDouble("4.23");  

    It can also take a radix(base) as the second argument:

        int i = Integer.parseInt("10011110",2);  

    Base conversion

    The Integer and Long wrapper classes have methods like toBinaryString() and toOctalString(), which convert numbers in base 10 to other bases. For instance:
        String s = Integer.toHexString(25);  

    Java Input & Output


    The following is a learning tool designed to explain the basic use of select classes from the java.io package, as well as classes used in conjunction with input and output. The following classes will be covered:
    1. System
    2. InputStreamReader
    3. BufferedReader
    4. File
    5. BufferedWriter
    6. String Tokenizer
    7. FileReader
    8. FileWriter

    Each in turn will be explained with coding examples and written explanations. In order to use the Java classes, we must import the Java input/output package (java.io). Links to JavaTM 2 Platform, Standard Edition, v1.2.2 API Specification outline further methods not covered. import java.io.*;

    System Class

    [1]: The System class is used to perform I/O using the system window.

    Standard input is envoked: System.in
    Standard output is envoked: System.out

    Create a new project, set the location, click on java2 and chose java application. Write the following code and run the application. Hit any key and push return.

      import java.io.*;
    public class TrivialApplication {
    public TrivialApplication ( ) throws IOException{
    int ch;
    ch = System.in.read(); //reads one byte as an integer from the system window
    System.out.println((char)ch); // converts the int to a charater value
    //not converting the value would give the character value as an integer
    }; // constructor
    public static void main ( String args[] ) throws IOException { new TrivialApplication(); };
    } // Application

    Remove the char cast, run the appplication, hold alt button down, push enter the number 255 with the number pad on the right hand side and release the alt key. Push enter. Repeat this with various numbers between 0 -255.

    General System.in use includes coupling with read(). int ch = System.in.read() // reads in one byte, returns -1(end). It is important to note that the read process in this case is limited to one byte.

    Generall System.out use includes coupling with println( ) allowing output to the system window. The print methods allow any combination of types to be printed within the same print statement.

    Example:

    char A = 'c';
    double B = 2.5;
    String C = "Dave"
    System.out.println( "Hello " + C + ", the answer to " + A + " equals " + B);
    //This has output to the system window: Hello Dave, the answer to c equals 2.5.

    The ln forces a new line ('/n') charcter to be written to the system window, moving cursor to following line.

    Change the first program to output the above example, or something similar. note: There are other methods available in the class.

    InputStreamReader

    [2]: InputStreamReader is a bridge from byte streams to character streams. It reads bytes and translates them into characters. Each invocation of one of an InputStreamReader's read( ) methods may cause one or more bytes to be read from the underlying byte-input stream and is declared:

    InputStreamReader input = new InputStreamReader(System.in);
    In this case InputStreamReader accepts data from System.in and declares input as a reference to the data.

    The functionality of InputStreamReader is not much different than System.in.

    Write the following code and run it. You'll find it is really not much different than a previous excercise in terms of functionality.

    import java.io.*;
    public class TrivialApplication {
    public TrivialApplication ( ) throws IOException{
    InputStreamReader input = new InputStreamReader(System.in);
    int ch;
    String st;
    System.out.println("enter a character and push enter");
    ch = input.read();
    System.out.println("Character value " +(char) ch);
    }; // constructor
    public static void main ( String args[] ) throws IOException { new TrivialApplication(); };
    } // Application

    Write the following code and run it. This code read a line of characters and stores it in an array. This can be done using System.in as well. Try it!

    import java.io.*;
    public class TrivialApplication {
    private static final int MAX = 10;
    public TrivialApplication ( ) throws IOException{
    InputStreamReader input = new InputStreamReader(System.in);
    int i;
    int ch[ ];
    ch = new int [MAX];
    System.out.println("write a line of length " + MAX + " push enter");
    for (i = 0 ; i < ch.length ; i++){
    ch[i] = input.read();
    System.out.print((char) ch[i]); // write out the array of characters.
    }
    }; // constructor
    public static void main ( String args[] ) throws IOException { new TrivialApplication(); };
    } // Application

    Write the following code and run it. This uses a different read method which reads bytes and stores them in a given array.

    import java.io.*;
    public class TrivialApplication {
    private static final int MAX = 10;
    public TrivialApplication ( ) throws IOException{
    int i;
    byte ch[ ];
    ch = new byte [MAX];
    System.out.println("write a line of length " + MAX + " push enter");
    System.in.read(ch );
    for (i = 0 ; i < ch.length ; i++){
    System.out.print((char) ch[i]); // write out the array of characters.
    }
    }; // constructor
    public static void main ( String args[] ) throws IOException { new TrivialApplication(); };
    } // Application

    Buffered reader

    [3]: Creating an instance of BufferedReader allocates memory storage for data input. The primary need for BufferedsReader is that it makes data input, which could be a very inefficient process into a more efficient process. "In general, each read request made of a Reader causes a corresponding read request to be made of the underlying character or byte stream." This could lead to many reading steps, and reading is one of the slowest aspects of computer processing. The Buffered reader allows for one reading step by providing data input storage which can then be accessed efficiently. "The buffer size may be specified, or the default size may be used. The default is large enough for most purposes."

    InputStreamReader dave = new InputStreamReader(System.in);
    BufferedReader br = new BufferReader(dave);

    The buffered reader accepts input from the InputStreamReader by including the dave variable, declares the location to store input from System.in and declares br as the access variable to the memory location storing this input. One can wrap an InputStreamReader within a BufferedReader for efficiency.

    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

    We will concentrate on reading files into a buffer and then accessing the info in the buffer. Examples of using a buffer with a file will follow.

    File Class

    [4]: Creating an instance of File, designates a filename to be the location for character input or output of an object file. The pathname to the current working directory can be specified. The pathname can be either be an absolute (or complete) pathname in that no other information is required to locate the file hat it denotes or a relative pathname which must be interpreted in terms of some other information taken from some other pathname. An abstract pathname has two components. Firstly, an optional system-dependent prefix string, such as a disk-drive specifier, "/ " for the UNIX root directory, or " \\ " for a Win32UNC pathname. The other one is there is a sequence of zero or more string names. This representation varies from operating system to operating system. Here are some examples: UNIX: " /home/users/2p92/file1 " DOS: " C:\home\users\2p92\file1 " MacOS: " Macintosh HD:home:users:2p92:file1 " All three examples reference a file called "file1" on the primary hard drive in the "2p92" directory which exists in the "users" directory which is in the "home" directory. One obvious difference is the path separator character.

    File inputFile = new File("testFile.txt");
    File outputFile = new File("/home/users/2p92/outFile.txt");

    The above decalrations creates a two file objects, one called inputFile which designates testFile.txt, the other called outputFile which designates outFile.txt

    BufferedWriter

    [5]: Creating an instance of BufferedWriter allocates memory storage for data output. The primary need for BufferedsWritter is that it makes data ouput, which could be a very inefficient process into a more efficient process. In general, each read request made of a FileWriter causes a corresponding write request to be made of the underlying character or byte stream." This could lead to many writing steps, and writing is one of the slowest aspects of computer processing. The BufferedWritter allows for one writing step by providing data output storage which can then be outputted efficiently. "The buffer size may be specified, or the default size may be used. The default is large enough for most purposes." File outputFile = new File("output.dat"); FileWriter fwr = new FileWriter(outputFile); BufferedWriter out = new BufferedWriter(fwr); The above example designates output.dat, the output File to be referenced by out by including outputFile within FileWritter declaration and in turn including fwr in BufferedWriter declaration. Thus allowing a large amount of character data stored in a memory location to be outputted into a file. Further examples of BufferedWriter will be shown later.

    String Tokenizer

    [6]: The StringTokenizer class contained in the java.util package will be explained in brief as it is useful in applications using java.io to manipulate strings. StringTokenizer is a Java utility built in method(it does not have to be imported). It's used to separate a string into tokens (generally individual words) in an application by recognizing delimiters, the white space and comment characters (less the skip comment) and procuring substrings or tokens between delimiters. The procedure to implement StringTokenizer could involve buffering string input using BufferedReader or simply declaring a string within the application. The string is then declared to be a tokenizable object. The application can then apply methods contained in the string tokenizer package to this tokenizable object.

    StringTokenizer st = new StringTokenizer( " this is a test " );
    While (st.hasMoreTokens ()) { Println(st.nextToken( ) ); }

    The above code prints the following output: this is a test The stringTokenizer utilizes a variety of methods to enable the tokenization of strings. A select few are listed below:

    countTokens( ) Calculates the number of tokens contained in a tokenizable string from the current token.

    nextToken (String delim) Returns the next string Token from a tokenizable string. Counting tokens after calling next token would reduce the token count by one. The current token has been advanced by one.

    hasMoreTokens( ) Tests if a tokenizable string has more tokens.

    nextElement( ) Returns the next object Token from a tokenizable string

    FileReader

    [7]: Creating an instance of FileReader allows an application to gain access to character input specified of file type. To implement FileReader an application would first create an object file, ex input file. The inputfile would then be specified as file that can be read.
    File inputFile = new File("test.dat");
    File Reader Joe = new FileReader(inputFile);
    Int c;
    While ((c = joe.read() !=-1){
    System.out.println("Joe" + c); } joe.close();

    In this case the application reads directly from the file. This would be very inefficient if the application had to read many times and thus a buffered reader could be used. The following example combines much of what has been discussed so far.

    Input could consist of:

    joe blow has a dog
    joe blow has a log
    joe blow has a pig
    joe blow has a fig

    This example also embeds the FileReader declaration into the buffered reader. The method readLine() reads a string line from the buffered reader, this line would consist of a line of input shown above. Note: a BufferedReader will accept any character input-Stream and a FileReader is just such a stream.

    A) Create a new java application and add the following code.

    import java.io.*;
    import java.util.*;
    /** This application reads input from the File test.dat, stores it in
    ** a memory location for efficient access, tokenizes a line of input data
    ** at a time allowing the application to use methods from the StringTokenizer
    ** class on these lines (or strings).
    **
    ** @author A.Muir
    **
    ** @version 1.0 (date here) */

    public class Application {
    public Application ( ) throws IOException{
    File inputFile = new File("test.dat");
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    int temp;
    StringTokenizer st;
    String c;
    System.out.println("Joe Blow" + st.countTokens());
    while(true){
    if((c = br.readLine()) == null){ break; }
    st = new StringTokenizer(c);
    temp = st.countTokens();
    for (int i = 0 ; i < temp ; i++){
    System.out.println(" "+ st.nextToken());
    } //for
    } //while
    }; // constructor
    public static void main ( String args[] ) throws IOException { new Application(); };
    } // Application );

    B) Create a data file:

    1) create a new text file.

    2)Add the following strings and save it as test.dat .

    joe blow has a dog
    joe blow has a log
    joe blow has a pig
    joe blow has a fig
    joe blow likes a tree
    joe blow likes his tea
    joe blow has no toes
    joe blow smiles at me

    C) Run the application and figure out how the code works. What would happen if you removed temp and simply wrote st.countTokens() directly in the for loop?

    Use string tokenizers to write out the last two tokens only (eg a dog| a tree...)

    FileWriter

    [8]: Creating an instance of FileWriter allows an application to place character output specified of file type. To implement FileReader an application would first create an object file, ex input file. The inputfile would then be specified as file that can be read.
    File inputFile = new File("test.dat");
    File Reader Joe = new FileReader(inputFile);
    File outputFile = new File("out.dat");
    FileWriter out = new FileWriter(outputFile);
    int c;
    While ((c = joe.read() !=-1){
    out.write(c);
    }
    joe.close();
    out.close();

    In this case the application writes directly to the file. This would be very inefficient if the application had to write many times and thus a BufferedWriter could be used.

    public class Application {
    public Application ( ) throws IOException{

    BufferedReader br = new BufferedReader(new FileReader(new File("test.dat")));
    BufferedWriter out = new BufferedWriter(new FileWriter(new File("output.dat")));
    StringTokenizer st;
    String c="";
    out.write("Joe Blow");
    out.newLine();
    while(true){
    if( (c=br.readLine()) == null) break;
    st = new StringTokenizer(c);
    for(int i = 0; i < st.countTokens(); i++){
    if(i==1){
    out.write(" " + st.nextToken());
    out.newLine();
    }
    else{
    st.nextToken();
    }
    } //for
    } //while
    out.flush();
    in.close();
    fwr.close();
    }; // constructor

    The Structure of Java Source Files


    There are two types of files you will work with in Java. The Java source file (.java) is created by programmers and contains human-readable instructions. The second file is the Java classfile (.class). The Java classfile contains binary instructions called bytecode that are executed by the Java Virtual Machine (JVM).

    Each .java source file contains, at most, one top-level public class definition. If a public class is present, the class name must match the unextended filename. For example, if a source file contains a definition for a public class BusinessReport, then the source file must be named BusinessReport.java. A source file may contain any number of non-public class definitions.

    When your .java file is compiled, a matching .class file is generated with an identical name. For example, BusinessReport.java will be compiled into BusinessReport.class.

       C:\source>javac BusinessReport.java  

    Classfiles are read by the Java Virtual Machine when the java command is invoked.

        C:\source>java -cp . BusinessReport  

    Each Java source file may contain any of the following three top-level elements. None of these elements are strictly required by the compiler.

    1. package declaration: If included, the package declaration must be the first statement in the file. The package keyword is followed by a package name. The package name is a series of elements separated by periods. Each period separated element must correspond to a filesystem subdirectory under which the classfile is located. For example, if a class was declared to be in the com.taylor.gui package, it would be located in the com/taylor/gui/ subdirectory. Only one package declaration is allowed per .java file.
    2. import statements: Imports are similar to package declarations in structure. Import statements point to classes or packages that should be made available for use witin the current class. For example, in order to use the java.applet.Applet class in a Java file, the class would have to be imported via the import java.applet.Applet; or import java.applet.*; statement. Import statements are not recursive, so import java.*; does not import all classes in subpackages of java.
    3. class definition: The class definition contains both the class visibility and the class name. It may in turn contain any number of child elements wrapped by curly braces. Remember that each source file must, at the most, one public class.

    A class can contain several different types of elements in addition to the three top-level elements listed above. The two most important of these are attributes and methods. Attributes are variables that have a visibility, type, and value, such as public and integer and 33, or private and String and "Hi, Mom!". Methods are class behaviors that accept data as method parameters, perform some operation on the data, and return a value. Methods have a visibility, return type, name, and list of parameters.

      package arunsoft;

    import java.lang.System;

    /**
    * Do not enter the line numbers
    *
    * The OnePlusOne class adds 1 + 1
    */
    public class OnePlusOne {

    private static int one = 1;

    public static void main(String args[]) {
    System.out.println(one + one);
    }
    }

    Type the above source code into a file named OnePlusOne.java and save the file in a subdirectory named mysource. Then compile and execute the code. Make sure you are in the immediate parent directory of mysource.

     C:\source> javac arunsoft/OnePlusOne.java
    C:\source> java arunsoft.OnePlusOne
    2

    In OnePlusOne.java above, line 1 contains the package declaration. Line 3 imports the System class so that it can be used to print out the results of the addition operation on line 15. Line 10 declares the OnePlusOne public class. Line 12 declares the public static int variable, one. Line 14 declares the main method. Line 15 prints out to the computer's standard output stream the result of adding 1 + 1.

    Additional syntax notes:

    • Class and method bodies are enclosed by curly braces.
    • All statements are ended with a semicolon.
    • Whitespace is ignored unless it is between quotation marks or single quotes.

    Java Thread


    What is a thread?

    A thread is a path of execution through code; in other words, a thread is a single sequential flow of control within a program. What does that mean? In Java, objects are not "alive", rather threads are "alive". Threads run through your code (ie, the methods in your objects). When you invoke the main() method in your class, the Java Virtual Machine (JVM) creates a thread for you that actually runs the code in this method. Another thread that is always running in the JVM is the garbage collector thread (which makes sure to reclaim memory for objects that are no longer referenced by any other objects).

    For example, let's say you have a class, called MyClass.java, that has a main() and print() method, shown in Figure 1. When you run this class, by typing java MyClass at the command prompt, the JVM creates a thread to run through the main() method. At the same time during which the thread is running through your object, the JVM has a garbage collection thread running, ie, they are running concurrently

    Java threads

    Java allows you to create your own threads that can be run through any class that you write. Threads are lightweight processes (if you're familiar with UNIX processes). By allowing you to spawn any number of threads in a single (JVM) process, you can have your objects perform concurrent tasks. This is very important for network programming, in a distributed environment, where your objects might be waiting for data from objects on other hosts (ie, remote objects). By being multithreaded, your objects can do something else while they wait; for example, they can service a large number of requests from other remote objects. Threads are used heavily in the Servlet API, EJB, RMI and just about any server framework.

    There is more than one way to use threads. Sometimes you have to create "threaded" classes (ie, classes that create and manage their own threads to perform concurrent tasks), but most of the time you have to make sure that your classes will handle multiple threads trampling through them (for example, Servlet classes).

    In the advanced thread tutorial you will see how to make complex "threaded" classes. In this tutorial you will learn how to:

    1. make simple "threaded" classes (classes that create and manage their own threads)
    2. create classes that can handle multiple threads trampling through them (for example, Servlet classes).

    Implementing Runnable vs. extending Thread

    There are two ways of creating your own "threaded" classes, you can:
    1. implement the java.lang.Runnable interface
    2. extend the java.lang.Thread class.
    These two ways of creating threads have slightly different semantics, in the way in which a thread runs through your objects. However, there are similarities in using either of the two ways, you must have a run() method. Your thread will execute this run() method, once the thread has been instantiated and started.

    Choosing to implement Runnable

    In fact, the Runnable interface only has one method, which is public void run(). The way to use Runnable is as follows:
    1. Create a class that implements Runnable and be sure to implement the run() method
    2. In order to make this run() method come "alive", you have to create a Thread object and pass it the Runnable implementation class as a parameter (to the constructor).
    3. Then you have to invoke the start() method on this Thead object.
    Your Runnable object (the threaded class) is not a thread itself. However, you can use the Thread class (in Java everything is represented as a class, even threads) to run your Runnable object (concurrently). So you have separate Thread objects, potentially all running through the same instance of your Runnable object. You can choose not to do this, but you can do this if you want to, since you have to give the Thread constructor a reference to the Runnable object in order to instantiate the Thread object. Don't forget to start() the Thread object, in order to make your Runnable object come "alive".

    The Servlet API, for example, chooses to have Servlets implement the Runnable interface rather than extending the Thread class. The end result of this is that there is one instance of the each Servlet class, and the Servlet container creates a new thread for each HTTP request that comes in (for that Servlet) and attaches it to the same Servlet object. This is the Singleton pattern, where only the same (single) instance of a class is used anywhere that an object of that class is required. Now, you can override this default behaviour of Servlets, by having your Servlet extend SingleThreadedModel. This starts to emulate the behavior that you would get by extending Thread. When you extend SingleThreadedModel, a new Servlet object is created for every thread that is created to service each HTTP request. This behavior is illustrated inFigure 2. Please refer to the source code example below on the details of implementing Runnable.

    Choosing to extend Thread

    Another way of creating "threaded classes" is by extending the Thread class directly. This might seem simpler than implementing the Runnable interface, but its the same amount of work. In fact, sometimes it is not possible to extend Thread, becuase your threaded class might have to extend something else. The only difference between implementing Runnable and extending Thread is that by extending Thread, each of your threads has a unique object associated with it, whereas with Runnable, many threads share the same object instance. This behaviour is also illustrated in Figure 2. Please refer to the source code example for details of extending Thread.

    Source code examples

    Two implementations of the ThreadedClass class are shown below, created once by implementing Runnable, and again by extending Thread. You can correlate the source code to Figure 2.

    The code to implement Runnable is shown below:

    //Implementing Runnable
    public class ThreadedClass
    implements Runnable
    {
    int data;

    public ThreadedClass(){
    data = 0;
    }

    public void run(){
    //this method runs when start() is invoked on the thread
    System.out.println( data );
    }

    public Thread getNewThread(){
    Thread t = new Thread( this );
    return t;
    }

    public static void main( String[] args ){
    ThreadedClass threadedClass = new ThreadedClass();
    Thread t1 = threadedClass.getNewThread();
    t1.start();

    Thread t2 = threadedClass.getNewThread();
    t2.start();
    }
    }

    In the main() method of the code above, only one instance of ThreadedClass is created. This one instance is used to spawn a multitude of threads (each executing the run() method of the same object). This is analogous to what happens with RMI or Servlets. This is how you can share instance variables of a Servlet across multiple threads of the same Servlet running in the Servlet container. If you wish to create a new instance of a Servlet per thread, then your Servlet has to extend SingleThreadModel.

    The code to extend Thread is shown below:

    //Extend Thread
    public class ThreadedClass
    extends Thread
    {
    int data;

    public ThreadedClass(){
    data = 0;
    }

    public void run(){
    //this method runs when start() is invoked on the thread
    System.out.println( data );
    }

    public static void main( String[] args ){
    ThreadedClass t1 = new ThreadedClass();
    t1.start();

    ThreadedClass t2 = new ThreadedClass();
    t2.start();
    }
    }

    Notice the difference between the Runnable and Thread versions? In the Runnable version you just created one ThreadedClass object and then created a bunch of Thread objects based on this Runnable object. These threads were all running through the same Runnable object (the ThreadedClass object). In the "extends Thread" version, you actually have to create a new ThreadedClass object per thread that you want to start.

    Depending on the problem you have to solve, you have to choose the appropriate method in your design. The 2 methods have their diffrerences, and by understanding these differences you can take advantage of them in your threaded classes.

    The synchronized keyword

    In Java, when the synchronized keyword is used in a method, the JVM guarantees that only one thread will be able to run through that method at any given time, ie, there is no concurrent thread access to that block of code. These blocks of code are also known as critical sections. You can synchronize entire methods by using the synchronized keyword in the mehod declaration, or you can just mark certain lines of code as synchronized. When you use the latter, approach, you have to use an object to synchronze "on". I will explain this in detail in the advanced tutorial, but for now, just use "this" to synchronize code blocks. Here is an example of how to use the synchronize keyword to make an entire method mutually exclusive, or thread-safe:
    public synchronized void someMethod() {..}
    Now, in order to make just a few lines of code thread-safe, use:
    ..
    synchronized( this ){
    //critical section
    };
    ..
    Why would you want to make only a section of your method thread-safe? Code that is thread-safe (ie, protected by synchronized) is slower than code that isn't. For better performance, you should only make those lines of your code thread-safe, that absolutely need to be. In the advanced thread tutorial, you will see why the code is slower, and what exactly the synchronized keyword does (it has something to do with object level monitors). However, if this tutorial satisfies your needs, then you can save time by not going through the advanced tutorial :).

    Thread-safe vs. threaded classes

    When you make thread-safe classes, you have to keep in mind that multiple threads could be trampling through the methods of your class. This requires special care in designing and coding these classes, becuase there is no way of knowing what thread will invoke what method (and in what sequence) on an object of this class. You have to take into account all possible scenarios or design in such a way that the number of possible states that your object can reach is minimized. I prefer to use the smart solution and design in such a way that the number of states my object can reach is minimized, that way I don't have to think about too many possibilities of what might happen when multiple threads are trampling through the same instance of my class.

    In order to make thread-safe classes there are a few simple rules to follow:

    • Mutator method access to any shared objects must be synchronized.
    • Accessor method access to any shared objects need not be synchronized.
      • There is an exception to this rule however. When your shared object's value fluctuates very frequently (like stock prices), then it is necessary to synchronize the accessor too, in order to report the correct value of the object rather than some intermediate (and inaccurate) value of the object. There are more advanced techniques to get around making your accessors synchronized which I will show you in the advanced thread tutorial. But for now, be sure to synchronize everything!

    Example Problem

    I will illustrate the problem by using a bank account example. Lets say that I have a bank account object (this is not thread-safe) which is accessed by a bunch of threads. My bank account object has a method that adds a given amount of money and removes that same amount and returns (ie, after the method returns my bank balance is still the same). Then I have another main class that simply spawns a lot of threads and lets them loose on my bank account object.

    Now, you might think that this example shouldn't even have any problems because that method in my bank account object doesn't do anything. Well, adding money and then removing it from a bank account are NOT atomic operations; an atomic operation is one that the JVM guarantees will occur without any interruptions (for example updating a register in a processor). When many threads are trampling through my (not thread-safe) bank account object, the bank balance does change! This is because other threads mess with my bank balance before each thread gets done using it; so as one thread adds money, and is just about to remove it, another thread could go in and remove more money, and my bank balance is negative for an instant! There are an infinite number of possibilities (most of which are undesirable) when a lot of threads are let loose on this poor object.

    Here is some code for a design that is not thread-safe (and messes up my bank balance with multiple threads):

    /BankAcct - NOT thread safe
    class BankAcct{
    int bal;

    public BankAcct( int i ){
    bal = i;
    }

    void doNothing(){
    addRemove( 10 );
    addRemove( 20 );
    addRemove( 30 );
    }

    void addRemove( int m ){
    bal+=m;
    Util.sleepRandom();
    bal-=m;
    }

    int get(){
    return bal;
    }
    }//end BankAcct class
    \


    //TestUnsafe - creates threads and tramples through BankAcct
    public class TestUnsafe extends Thread{
    //data members for this thread
    private String name;
    BankAcct ba;

    //start this method
    public static void main( String[] args ){
    BankAcct ba = new BankAcct( 0 );
    new TestUnsafe( "** " , ba ).start();
    new TestUnsafe( " ++ " , ba).start();
    new TestUnsafe( " == " , ba ).start();
    new TestUnsafe( " //" , ba ).start();
    }

    //constructor
    public TestUnsafe( String n , BankAcct ba ){
    this.ba = ba;
    name = n;
    }

    //extending Thread
    public void run(){
    doWork();
    }

    //simply displays the bank balance before and after this thread
    //messes with the bankaccount
    public void doWork(){
    System.out.println( name+" :doWork() - start : account bal = "+ba.get() );

    ba.doNothing();

    System.out.println( name+" :doWork() - end : account bal = "+ba.get() );
    }

    }//end TestUnsafe class

     

    If you compile, and then run TestUnsafe.java at a command prompt/console (by typing java TestUnsafe), you will notice, from the output, that the bank balance is changing quite a bit. You will see that the bank balance figure changes as the program runs, however, at the end the bank balance is zero. Now, the problem is the fluctuations as the program runs; it should be zero, because the doNothing() method of BankAcct, should not affect the bank balance. However, due to TestUnsafe threads trampling through the BankAcct, it messes everything up.

    Solution (design)

    Obviously the solution to this problem would be to synchronize the method in the BankAcct object that messes with the bank balance. This would guarantee that only one thread was trampling through it at any given time.

    Also it is necessary to synchrnonize the accessor method too! Why? Well, the methods to add and remove money from the account are so fast that when I use get() it sometimes returns the value of my bank balance in the middle of doNothing(). So one thread is in the middle of executing doNothing() at which point my bank balance is non-zero. At this same instant, another thread calls get() an gets a non-zero value of my bank account. Ooops! The way to solve this is to synchronize the get() method too, in order to ensure that my real bank balance is returned. On the other hand, if you wish to monitor the state of this object at all times, then you might want to leave the get() unsynchronized. It all depends on what you want to do.

    The code below contains the thread-safe solution for this bank account problem:

    Code

    Here is the source code for the solution
    //BankAcct - thread safe version
    class BankAcct{
    int bal;

    public BankAcct( int i ){
    bal = i;
    }

    void doNothing(){
    addRemove( 10 );
    addRemove( 20 );
    addRemove( 30 );
    }

    synchronized void addRemove( int m ){
    bal+=m;
    Util.sleepRandom();
    bal-=m;
    }

    public synchronized int get(){
    return bal;
    }
    }

    The TestSafe class hasn't changed much from TestUnsafe: only the main() method is different, it creates TestSafe objects, rather than TestUnsafe ones. When you run this code (by compiling and running TestSafe.java) you will see that the bank balance is always 0. Don't forget to compile TestSafe, before running it (due to namespace conflicts with TestUnsafe's BankAcct class). Now if you make the get() method unsynchronized you will see some fluctuations in the bank balance, but this is because the get() method might be getting the value of the balance just as its changing. At the end of each method run, the value is still 0 though. This is a very interesting effect.

    Why?

    You don't really have a choice, all your code should be thread-safe and re-entrant. Re-entrant means that once a method is called on your object, it should be possible for someone else to call that method. For an example of something that's non-re-entrant (try typing that fast 3 times in a row :) the IBM XML Parser (version 1.x) comes to mind. When certain methods are called on the IBM DOM parser, and exceptions are thrown the entire object becomes frozen and no one can call any more methods on that object. This is an example of non-reentrant code. The parser code was probably not even tread-safe. I hope they have fixed these problems in the newer versions.
     

    JAVA INTRODUCTION Blak Magik is Designed by productive dreams for smashing magazine Bloggerized by Ipiet © 2008