4.1 Packages: 4.1.1 Defining A Package
4.1 Packages: 4.1.1 Defining A Package
4.1 Packages: 4.1.1 Defining A Package
1
Notes for Programming in Java (Open Elective - 15CS561)
MODULE 4
Syllabus:
Packages: Packages, Access Protection, Importing Packages
Interfaces
Exception Handling: Exception-Handling Fundamentals, Exception Types, Uncaught Exceptions, Using try and
catch, Multiple catch Clauses, Nested try Statements, throw, throws, finally, Java’s Built-in Exceptions, Creating
Your Own Exception Subclasses, Chained Exceptions, Using Exceptions.
4.1 Packages
When we have more than one class in our program, usually we give unique names to classes. In a real-
time development, as the number of classes increases, giving unique meaningful name for each class will
be a problem. To avoid name-collision in such situations, Java provides a concept of packages. A
package is a collection of classes. The package is both a naming and a visibility control mechanism.
You can define classes inside a package that are not accessible by code outside that package. You can
also define class members that are only exposed to other members of the same package. This allows
your classes to have intimate knowledge of each other, but not expose that knowledge to the rest of the
world.
Java uses file system directories to store packages. For example, the .class file for any class you
declare to be part of MyPackage must be stored in a directory called MyPackage. Remember that case
is significant, and the directory name must match the package name exactly. More than one file can
include the same package statement. The package statement simply specifies to which package the
classes defined in a file belong. It does not exclude other class in other files from being part of that same
package.
One can create a hierarchy of packages. To do so, simply separate each package name from the one
above it by use of a period. The general form of a multileveled package statement is shown here:
package pkg1[.pkg2[.pkg3]];
A package hierarchy must be reflected in the file system of your Java development system. For example,
a package declared as package java.awt.image; needs to be stored in java\awt\image in a
Windows environment. You cannot rename a package without renaming the directory in which the
classes are stored.
By: Dr. Chetana Hegde, Associate Professor, RNS Institute of Technology, Bangalore – 98
Email: [email protected]
This document can be downloaded from www.chetanahegde.in with most recent updates. 2
Notes for Programming in Java (Open Elective - 15CS561)
By default, Java run-time uses current working directory as a starting point. So, if our package
is in a sub-directory of current working directory, then it will be found.
We can set directory path using CLASSPATH environment variable.
We can use –classpath option with javac and java to specify path of our classes.
Assume that we have created a package MyPackage. When the second two options are used, the class
path must not include MyPackage. It must simply specify the path to MyPackage. For example, in a
Windows environment, if the path to MyPackage is
C:\MyPrograms\Java\MyPackage
package MyPackage;
class Test
{
int a, b;
Test(int x, int y)
{
a=x; b=y;
}
void disp()
{
System.out.println("a= "+a+" b= "+b);
}
}
class PackDemo
{
public static void main(String args[])
{
Test t=new Test(2,3);
t.disp();
}
}
Even a class has accessibility feature. A class can be kept as default or can be declared as public.
When a class is declared as public, it is accessible by any other code. If a class has default access, then
it can only be accessed by other code within its same package. When a class is public, it must be the
only public class declared in the file, and the file must have the same name as the class
Accessibility of members of the class can be better understood using the following table.
In a Java source file, import statements occur immediately following the package statement (if it exists)
and before any class definitions. The general form of the import statement is:
import pkg1[.pkg2].(classname|*);
For example,
import java.util.Date;
import java.io.*;
The star form may increase compilation time—especially if you import several large packages. For this
reason it is a good idea to explicitly name the classes that you want to use rather than importing whole
packages. However, the star form has absolutely no effect on the run-time performance or size of your
classes.
All of the standard Java classes included with Java are stored in a package called java. The basic
language functions are stored in a package inside of the java package called java.lang. Normally, you
have to import every package or class that you want to use, but since Java is useless without much of the
functionality in java.lang, it is implicitly imported by the compiler for all programs. This is equivalent to the
following line being at the top of all of your programs:
import java.lang.*;
If a class with the same name exists in two different packages that you import using the star form, the
compiler will remain silent, unless you try to use one of the classes. In that case, you will get a compile-
time error and have to explicitly name the class specifying its package.
The import statement is optional. Any place you use a class name, you can use its fully qualified name,
which includes its full package hierarchy. For example,
import java.util.*;
Can be written as –
class MyDate extends java.util.Date
{ …}
4.2 Interfaces
Interface is an abstract type that can contain only the declarations of methods and constants. Interfaces
are syntactically similar to classes, but they do not contain instance variables, and their methods are
declared without any body. Any number of classes can implement an interface. One class may
implement many interfaces. By providing the interface keyword, Java allows you to fully utilize the “one
interface, multiple methods” aspect of polymorphism. Interfaces are alternative means for multiple
inheritance in Java.
interface ICallback
{
void callback(int param);
}
class TestIface
{
public static void main(String args[])
{
ICallback c = new Client();
c.callback(42);
// c.test() //error!!
}
}
Here, the interface ICallback contains declaration of one method callback(). The class Client
implementing this interface is defining the method declared in interface. Note that, the method callback()
is public by default inside the interface. But, the keyword public must be used while defining it inside the
class. Also, the class has its own method test(). In the main() method, we are creating a reference of
interface pointing to object of Client class. Through this reference, we can call interface method, but not
method of the class.
The true polymorphic nature of interfaces can be found from the following example –
interface ICallback
{
void callback(int param);
}
class TestIface
{
public static void main(String args[])
{
ICallback x[]={new Client(), new Client2()};
for(int i=0;i<2;i++)
x[i].callback(5);
}
}
Output:
callback called with 5
Another version of ICallBack
p squared 25
In this program, we have created array of references to interface, but they are initialized to class objects.
Using the array index, we call respective implementation of callback() method.
Note: Interfaces may look similar to abstract classes. But, there are lot of differences between them as
shown in the following table:
Abstract Class Interface
Can have instance methods that implements Are implicitly abstract and cannot have
a default behavior. implementations.
interface SharedConst
{
int FAIL=0; //these are final by default
int PASS=1;
}
Result(double m)
{
mr=m;
}
int res()
{
if(mr<40)
return FAIL;
else return PASS;
}
}
class Exam extends Result implements SharedConst
{
Exam(double m)
{
super(m);
}
public static void main(String args[])
{
Exam r = new Exam(56);
switch(r.res())
{
case FAIL:
System.out.println("Fail");
break;
case PASS:
System.out.println("Pass");
break;
}
}
}
interface A
{
void meth1();
void meth2();
}
interface B extends A
{
void meth3();
}
Exceptions can be generated by the Java run-time system, or they can be manually generated by your
code. Exceptions thrown by Java relate to fundamental errors that violate the rules of the Java language
or the constraints of the Java execution environment. Manually generated exceptions are typically used
to report some error condition to the caller of a method.
try
{
// block of code to monitor errors
}
catch (ExceptionType1 exOb)
{
// exception handler for ExceptionType1
}
catch (ExceptionType2 exOb)
{
// exception handler for ExceptionType2
}
...
….
finally
{
// block of code to be executed after try block ends
}
Throwable
Exception Error
Exception class is used for exceptional conditions that user programs should catch. We can inherit from
this class to create our own custom exception types. There is an important subclass of Exception, called
RuntimeException. Exceptions of this type are automatically defined for the programs that you write and
include things such as division by zero and invalid array indexing.
Error class defines exceptions that are not expected to be caught under normal circumstances by our
program. Exceptions of type Error are used by the Java run-time system to indicate errors having to do
with the run-time environment, itself. Stack overflow is an example of such an error.
Any un-caught exception is handled by default handler. The default handler displays a string describing
the exception, prints a stack trace from the point at which the exception occurred, and terminates the
program. Here is the exception generated when above example is executed:
java.lang.ArithmeticException: / by zero
at Exc0.main(Exc0.java:6)
The stack trace displays class name, method name, file name and line number causing the exception.
Also, the type of exception thrown viz. ArithmeticException which is the subclass of Exception is
displayed. The type of exception gives more information about what type of error has occurred. The stack
trace will always show the sequence of method invocations that led up to the error.
class Exc1
{
static void subroutine()
{
int d = 0;
int a = 10 / d;
}
public static void main(String args[])
{
Exc1.subroutine();
}
}
The resulting stack trace from the default exception handler shows how the entire call stack is displayed:
java.lang.ArithmeticException: / by zero
at Exc1.subroutine(Exc1.java:6)
at Exc1.main(Exc1.java:10)
To handle run-time error, we need to enclose the suspected code within try block.
class Exc2
{
public static void main(String args[])
{
int d, a;
try
{
d = 0;
a = 42 / d;
System.out.println("This will not be printed.");
} catch (ArithmeticException e)
{
System.out.println("Division by zero.");
}
System.out.println("After catch statement.");
}
}
Output:
Division by zero.
After catch statement.
The goal of most well-constructed catch clauses should be to resolve the exceptional condition and then
continue on as if the error had never happened.
import java.util.Random;
class HandleError
{
public static void main(String args[])
{
int a=0, b=0, c=0;
Random r = new Random();
The output of above program is not predictable exactly, as we are generating random numbers. But, the
loop will execute 10 times. In each iteration, two random numbers (b and c) will be generated. When their
division results in zero, then exception will be caught. Even after exception, loop will continue to execute.
class MultiCatch
{
public static void main(String args[])
{
try
{
int a = args.length;
System.out.println("a = " + a);
int b = 42 / a;
int c[] = { 1 };
c[42] = 99;
} catch(ArithmeticException e)
{
System.out.println("Divide by 0: " + e);
} catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("Array index oob: " + e);
}
System.out.println("After try/catch blocks.");
}
}
class SuperSubCatch
{
public static void main(String args[])
{
try
{
int a = 0;
int b = 42 / a;
} catch(Exception e)
{
System.out.println("Generic Exception catch.");
}
catch(ArithmeticException e) // ERROR - unreachable
{
System.out.println("This is never reached.");
}
}
}
The above program generates error “Unreachable Code”, because ArithmeticException is a subclass of
Exception.
class NestTry
{
public static void main(String args[])
{
try
{
int a = args.length;
int b = 42 / a;
try
{
if(a==1)
a = a/(a-a);
if(a==2)
{
int c[] = { 1 };
} c[10] = 99;
}catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("Array index out-of-bounds: " + e);
}
}catch(ArithmeticException e)
{
System.out.println("Divide by 0: " + e);
}
}
}
When a method is enclosed within a try block, and a method itself contains a try block, it is considered to
be a nested try block.
class MethNestTry
{ static void nesttry(int a)
{ try
{
if(a==1)
a = a/(a-a);
if(a==2)
{
int c[] = { 1 };
c[42] = 99;
}
}catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("Array index out-of-bounds: " + e);
}
}
class ThrowDemo
{
static void demoproc()
{
try
{
throw new NullPointerException("demo");
} catch(NullPointerException e)
{
System.out.println("Caught inside demoproc: " + e);
}
}
Here, new is used to construct an instance of NullPointerException. Many of Java’s built-in run-time
exceptions have at least two constructors:
– one with no parameter and
– one that takes a string parameter
When the second form is used, the argument specifies a string that describes the exception. This string is
displayed when the object is used as an argument to print() or println(). It can also be obtained by a call
to getMessage(), which is defined by Throwable.
4.3.8 throws
If a method is capable of causing an exception that it does not handle, it must specify this behavior so
that callers of the method can guard themselves against that exception. You do this by including a
throws clause in the method’s declaration. A throws clause lists the types of exceptions that a method
might throw. This is necessary for all exceptions, except those of type Error or RuntimeException, or
any of their subclasses. All other exceptions that a method can throw must be declared in the throws
clause. If they are not, a compile-time error will result.
The general form of a method declaration that includes a throws clause:
type method-name(parameter-list) throws exception-list
{
// body of method
}
Here, exception-list is a comma-separated list of the exceptions that a method can throw.
class ThrowsDemo
{
static void throwOne() throws IllegalAccessException
{
System.out.println("Inside throwOne.");
throw new IllegalAccessException("demo");
}
public static void main(String args[])
{
try
{
throwOne();
} catch (IllegalAccessException e)
{
System.out.println("Caught " + e);
}
}
}
4.3.9 finally
When exceptions are thrown, execution in a method takes a rather abrupt, nonlinear path that alters the
normal flow through the method. Sometimes it is even possible for an exception to cause the method to
return prematurely. This could be a problem in some methods. For example, if a method opens a file
upon entry and closes it upon exit, then you will not want the code that closes the file to be bypassed by
the exception-handling mechanism. The finally keyword is designed to address such situations.
The finally clause creates a block of code that will be executed after a try/catch block has completed
and before the next code of try/catch block. The finally block will execute whether or not an exception is
thrown. If an exception is thrown, the finally block will execute even if no catch statement matches the
exception. Any time a method is about to return to the caller from inside a try/catch block, via an
uncaught exception or an explicit return statement, the finally clause is also executed just before the
method returns. The finally clause is optional. However, each try statement requires at least one catch
or a finally clause.
class FinallyDemo
{
static void procA()
{
tr
y
{ System.out.println("inside procA");
throw new RuntimeException("demo");
} finally {
}
}
System.out.println("procA's finally");
Output:
inside procA
procA’s finally
Exception caught
inside procB
procB’s finally
inside procC
procC’s finally
4.3.10 Java’s Built-in Exceptions
Inside the standard package java.lang, Java defines several exception classes. The most general of
these exceptions are subclasses of the standard type RuntimeException. These exceptions need not be
included in any method’s throws list. Such exceptions are called as unchecked exceptions because the
compiler does not check to see if a method handles or throws these exceptions. Java.lang defines few
checked exceptions which needs to be listed out by a method using throws list if that method generate
one of these exceptions and does not handle it itself. Java defines several other types of exceptions that
relate to its various class libraries.
Method Description
Throwable fillInStackTrace( ) Returns a Throwable object that contains a completed
stack trace. This object can be re-thrown.
Throwable getCause( ) Returns the exception that underlies the current exception.
If there is no underlying exception, null is returned.
void setStackTrace( Sets the stack trace to the elements passed in elements.
StackTraceElement This method is for specialized applications, not normal
elements[ ]) use.
We may wish to override one or more of these methods in exception classes that we create. Two of the
constructors of Exception are:
Exception( )
Exception(String msg)
Though specifying a description when an exception is created is often useful, sometimes it is better to
override toString( ). The version of toString( ) defined by Throwable (and inherited by Exception) first
displays the name of the exception followed by a colon, which is then followed by your description. By
overriding toString( ), you can prevent the exception name and colon from being displayed. This makes
for a cleaner output, which is desirable in some cases.
MyException (int m)
{
marks=m;
}
System.out.println("Normal exit");
}
public static void main(String args[])
{
try{
test(45);
test(-2);
}
catch (MyException e)
{
System.out.println("Caught " + e);
}
}
}
To allow chained exceptions, two constructors and two methods were added to Throwable. The
constructors are shown here:
– Throwable(Throwable causeExc)
– Throwable(String msg, Throwable causeExc)
In the first form, causeExc is the exception that causes the current exception. That is, causeExc is the
underlying reason that an exception occurred. The second form allows you to specify a description at the
same time that you specify a cause exception. These two constructors have also been added to the
Error, Exception, and RuntimeException classes.
Chained exceptions can be carried on to whatever depth is necessary. Thus, the cause exception can,
itself, have a cause. Be aware that overly long chains of exceptions may indicate poor design. Chained
exceptions are not something that every program will need. However, in cases in which knowledge of an
underlying cause is useful, they offer an elegant solution.
Note that Java’s exception-handling statements should not be considered a general mechanism for
nonlocal branching. If you do so, it will only confuse your code and make it hard to maintain.
Question Bank:
1. What do you mean by a package? How do you use it in a Java program? Explain with a program.
2. How do you import a package? Explain.
3. Write a note on access protection in Java.
4. Define an interface. Explain how to define and implement an interface with an example.
5. Differentiate abstract base class and an interface.
6. How do you define variables inside interface? List out the the characteristics of such variables.
7. Define an exception. What are the key terms used in exception handling? Explain.
8. Demonstrate working of nest try block with an example.
9. Write a program which contains one method which will throw IllegalAccessException and use
proper exception handles so that exception should be printed.
10. Write a note on:
a. Java’s built-in exception
b. Uncaught Exceptions
11. How do you create your own exception class? Explain with a program.