Friday, 5 June 2015

Java Exception Handling Construct

Java exception/error handling is managed via five keywords: try, catch, throw, throws, and finally.

The general form of an exception-handling block is:

try

{

//block of code to be monitored for errors.

}

catch(ExceptionType1 exOb1)

{

//exception handler for ExceptionType1

}

catch(ExceptionType2 exOb2)

{

//exception handler for ExceptionType1

}

.

.

.

finally

{

//block of code to be executed before try block ends

}

The code, which is to be monitored for run-time errors, is put inside a try block. The try block must be enclosed between braces even if there is only one statement in it. There can be zero or more catch statements and zero or one finally statement. Both catch and finally blocks are optional but either one catch block or one finally block is must.

The code in the try block is executed like any other Java code. If the code inside the try block executes successfully then the control goes to finally block if it is present and then the execution continues from the statement just after the end of finally block (i.e. after the end of try statement). If the finally block is not present then the execution continues from the statement just after the last catch block (i.e. after the end of try statement).

If some run-time error occurs while executing the code in try block then JVM throws an Exception/Error. This means an object of type Exception/Error or one of its sub-classes is created depending on the type of the run-time error. This is then compared with the Exception/Error types of the catch blocks in top to bottom order. If a matching catch block is found then the exception/error is handled i.e. program will not terminate. The execution continues with the first statement in the catch block. On completion of the catch block, excution continues with the statement just after the end of try statement. At the most one catch block is executed irrespective of the number of catch blocks. On completion of the catch block, excution continues with the statement just after the end of try statement. At the most one catch block is executed irrespective of the number of catch blocks.

If exception/error does not match with exception/error type of any of the catch blocks, then we say that it is not handled. The execution will immediately return from try block. The code in the finally block will be executed even if the exception/error is not handled. The exception/error will then be handled by outer try block if there is one otherwise it must be handled in the method which called the current method. The exception/error percolates up the hierarchy till it is handled or it is passed to JVM unhandled if not handled even in the main() method which is the first method from which the execution starts. The JVM then simply terminates the program and displays the exception/error details on the monitor/console.



Java Hierarchy of Exception Classes

  • Exceptions/Errors are also objects in Java.
  • Root class of all exception/error classes is the Throwable class, which is an immediate sub-class of the Object class.
  • Methods are defined in Throwable class to retrieve error message associated with the error/exception and to print the stack trace showing where the error/exception occurs.
  • There are two immediate sub classes of class Throwable:
            o Error
            o Exception
  • Sub classes of Exception have the suffix Exception.
  • Sub classes of Error have the suffix Error (normally).

Error

The sub classes of Error class are basically used for signaling abnormal system conditions like:
  • OutOfMemoryError signals that the Java VM has run out of memory and that the garbage collector is unable to claim any free memory.
  • StackOverflowError signals a stack overflow in the interpreter.

The errors are, in general, unrecoverable and should not be handled.

Exception

The sub classes of Exception class are, in general recoverable. For example, EOFException signals that a file you have opened has no more data for reading. FileNotFoundException signals that a file you want to open does not exist in the file system.

Hierarchy of common Exceptions




Java Exception Handling

An exception/error is an abnormal condition that breaks/disrupts the normal program flow. The abnormal condition occurs at run-time i.e. during code execution.

For example, a C program gets terminated when division by zero is encountered at the run-time as this is not a defined operation and results in run-time error. The other familiar example in case of C-language is that of null pointer exception, which occurs when we try to access a memory location through an un-initialized pointer. The program gets terminated in this case also.

Java has a separate construct for exception/error handling like C++. It is possible to recover from an exception/error at run-time and continue the program execution using the exception-handling construct.

A Java exception/error is an object of class Exception/Error or one of its sub-classes. JVM creates an object of class Exception/Error or one of their sub-classes whenever exception/error occurs at the run-time. The exception/error object contains details about the exception/error, which can be accessed using the public methods provided for this purpose.

Traditional Approach of Exception/Error Handling:

Use of if(), goto and return codes for propagating error back to calling method.

Advantage of Exception/Error Handling

  • Error-handling code is separated from the normal program flow to increase the

    readability and maintainability.

    We can easily say where the exception/error will be handled. Exceptions/Errors
    propagate up the call stack at runtime- first up the enclosing try blocks and then back to the calling method- until an exception handler catches them.
     
  • The location of the exception/error is known exactly as entire stack trace is available to the user. This is very helpful in debugging.
     
  • Programmer gets a chance to recover from the error/abnormal condition.
     
  • With Java, it is not must to test if an exception/error condition happens. Adding more error/exception handlers simply requires adding more catch clauses, but the original program flow need not be touched.

When Exceptions/Errors can occur?

There are many cases where abnormal conditions occur during program execution, such as:

  • The class file you want to load may be missing or in the wrong format.
  • Integer division by zero.
  • Array index is not in the valid range (i.e. from 0 to length-1).
  • The file you are trying to open may not exist.
  • The String, which you want to convert to a number, is having invalid characters so that it cannot be converted to a number.
  • You want to create an object but no more memory is available.

Java Interface Examples

Example: This example is covered when discussing abstract classes. The example is modified such that instead of declaring Shape class as an abstract class it is declared as an interface. We cannot have any implementation in the Shape interface. The interface declares two methods, which must be implemented by all sub-classes of this interface. This would duplicate the code of
method calCost() in all the implementing classes.

interface Shape

{

double puCost = 100;

double area();

double calCost();

}

class Triangle implements Shape

{

double s1,s2,s3;

Triangle(double a, double b, double c)

{

}

public double calCost()

{

}

public double area()

{

s1 = a; s2 = b; s3 = c;

return puCost * area();

double s = (s1+s2+s3)/2;

return Math.sqrt(s*(s-s1)*(s-s2)*(s-s3));

}

}

class Rectangle implements Shape

{ double s1,s2;

Rectangle(double a, double b)

{

}

public double calCost()

{

}

public double area()

{

}

}

class Square implements Shape

{ double s;

Square(double a)

{ s = a;

}

public double calCost()

{

}

public double area()

{ return s * s;

s1 = a; s2 = b;

return puCost * area();

return s1 * s2;

return puCost * area();

}

}

class ShapeTest2

{ static public void main(String args[])

{ Shape s1 = new Triangle(3,4,5);

Shape s2 = new Rectangle(3,4);

Shape s3 = new Square(3);

System.out.println(s1.area());

System.out.println(s2.area());

System.out.println(s3.area());

System.out.println(s1.calCost());

System.out.println(s2.calCost());

System.out.println(s3.calCost());

}

}

Output:

6.0

12.0

9.0

600.0

1200.0

900.0

Example: This example improves the previous one by introducing additional sub-class AbstractShape between interface Shape and its sub-classes. This sub-class can contain the generic code for method calCost().

interface Shape

{
double area();

double calCost();

}

abstract class AbstractShape implements Shape

{ double puCost;

AbstractShape(double puCost)

{ this.puCost = puCost;

}

public double calCost()

{ return puCost * area();

}

}

class Triangle extends AbstractShape

{ double s1,s2,s3;

Triangle(double a, double b, double c, double puCost)

{ super(puCost);

}

public double area()

{ double s = (s1+s2+s3)/2;

}

}

class Rectangle extends AbstractShape

{ double s1,s2;

Rectangle(double a, double b, double puCost)

{ super(puCost);

}

public double area()

{ return s1 * s2;

}

}

class Square extends AbstractShape

{ double s;

Square(double a, double puCost)

{ super(puCost); 

}

public double area()

{ return s * s;

}

}

s1 = a; s2 = b; s3 = c;

return Math.sqrt(s*(s-s1)*(s-s2)*(s-s3));

s1 = a; s2 = b;

s = a;

class ShapeTest3

{ static public void main(String args[])

{ Shape s1 = new Triangle(3,4,5,10);

Shape s2 = new Rectangle(3,4,100);

Shape s3 = new Square(3,1000);

System.out.println(s1.area());

System.out.println(s2.area());

System.out.println(s3.area());

System.out.println(s1.calCost());

System.out.println(s2.calCost());

System.out.println(s3.calCost());

}

}

Output:
6.0
12.0
9.0
60.0
1200.0
9000.0

Example: The following example demonstrates that interface of the stack could be kept separate from its implementation by abstracting it using the interface StackInterface.

interface StackInterface

{ void push(int x);

int pop();

}

class Stack implements StackInterface

{ int top = -1; int a[] = new int[10];

public void push(int x)

{ if(top == 9)

{ System.out.println("Stack Full");

return;

}

top = top + 1; a[top] = x;

}

public int pop()

{ if(top ==  -1)

{ System.out.println("Stack Empty");

return -1; //assuming that -1 is not a valid data

}

int x = a[top]; top = top - 1; return x;

}

}

class StackTest

{ public static void main(String args[])

{ Stack st1=new Stack();

Stack st2=new Stack();

for(int i=1;i<5;i++)

{ st1.push(i);

}

for(int i=1;i<5;i++)

{ st2.push(i+10);

}

for(int i=1;i<5;i++)

{ System.out.println(st1.pop());

}

for(int i=1;i<5;i++)

{ System.out.println(st2.pop());

}

}

}

Output:
4
3
2
1
14
13
12
11

Example: This example demonstrates that an interface can be extended. This example also illustrates that a class implementing the extended interface must implement methods in base interface as well as methods in the extended interface.

interface ExtStackInterface extends StackInterface

{ public boolean isStackEmpty();

public boolean isStackFull();

public void display();

}

class ExtStack implements ExtStackInterface

{ int top = -1; int a[] = new int[10];

public void push(int x)

{ if(top == 9)

{ System.out.println("Stack Full"); return;

}

top = top + 1; a[top] = x;

}

public int pop()

{ if(top ==  -1)

{ System.out.println("Stack Empty");

return -1; //assuming that -1 is not a valid data

}

}

public void display()

{ for(int i = top; i >= 0; i--)

int x = a[top]; top = top - 1; return x;

{ System.out.println(a[i]);

}

}

public boolean isStackEmpty()

{ if(top == -1)

return(true);

else

return(false);

}

public boolean isStackFull()

{ if(top == 9)

return(true);

else

return(false);

}

}

Example: This example demonstrates that a class implementing the interface can also extend a base class. The implementing class must provide the implementation of all the methods in the interface. But the methods defined in the super-class need not be implemented as their definition is inherited from the super-class.

class ExtStack extends Stack implements ExtStackInterface

{ public void display()

{ for(int i = top; i >= 0; i--)

{ System.out.println(a[i]);

}

}

public boolean isStackEmpty()

{ if(top == -1)

return(true);

else

return(false);

}

public boolean isStackFull()

{ if(top == 9)

return(true);

else

return(false);

}

}

Thursday, 4 June 2015

Java Interface Characteristics

  1. Interface can be declared as abstract but it is superfluous and seldom done.
  2. Since interfaces are meant to be implemented by classes, interface members implicitly have public accessibility and the public modifier is omitted.
  3. The methods in an interface are all implicitly abstract and public. A method prototype has the same syntax as an abstract method. However, only the modifiers abstract and public are allowed, but these are normally omitted.
  4. A class can neither narrow the accessibility of an interface method nor specify new exceptions in method’s throws clause; as attempting to do so would amount to altering the interfaces contract, which is illegal. The criteria for overriding methods also apply when implementing interface methods.
  5. Interface methods cannot be declared as static. They are always implemented as instance methods.
  6. Regardless of how many interfaces a class implements directly or indirectly, it only provides a single implementation of a method that might have multiple declarations in the interfaces.
  7. Method prototype declarations can also be overloaded as in the case of classes.
  8. An interface can also define named constants. Such constants are defined by field declarations and are considered to be public, static and final. These modifiers are usually omitted from the declaration. Such a constant must be initialized with an initializer expression.
  9. An interface constant can be accessed by any client (a class or interface) using its fully qualified name, regardless of whether the client extends or implements its interface.
    However, if a client is a class that implements this interface or an interface that extends this interface, then the client can also access such constants directly without using the fully qualified name. Such a client inherits the interface constants.
  10. In the case of multiple inheritance of interface constants, any name conflicts can be resolved using fully qualified names for the constants involved.