Packages
·
Packages are containers for classes.
They are used to keep the class name space compartmentalized.
·
A package allows you to create a class
named List, which you can store in your own package without concern that it
will collide with some other class named List stored elsewhere.
·
Packages are stored in a hierarchical
manner and are explicitly imported into new class definitions.
Defining a
Package
This
is the general form of the package statement:
packagepkg; // pkg is the name of the package
For example:
packageMyPackage;
packageMyPackage;
Multilevel package statement:
package
pkg1[.pkg2[.pkg3]];
Java
uses file system directories to store packages. For example, the .class files for any classes 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
matchthepackagenameexactly.
Java
provides many levels of protection to allow finegrained control over the
visibility of variables and methods within classes, subclasses, and packages.
Java addresses fourcategories of visibility for class members:
- Subclasses in the same package
- Non-subclasses in the same package
- Subclasses in different packages
- Classes that are neither in the same package nor
- Classes that are neither in the same package nor subclasses
The
three access modifiers, private, public, and protected,
provide a variety of ways to produce the many levels of access required by these categories.
//
A simple package
packageMyPack;
class
Balance {
String name;
doublebal;
Balance(String
n, double b) {
name
= n;
bal
= b;
}
classAccountBalance
{
public
static void main(String args[]) {
Balance current[] = new Balance[3];
current[0]
= new Balance("K. J. Fielding", 123.23);
current[1]
= new Balance("Will Tell", 157.02);
current[2]
= new Balance("Tom Jackson", 12.33);
}
void
show()
{
if(bal<0)
System.out.print(">>
");
System.out.println(name
+ ": $" + bal);
} }
package p1;
class
Derived extends Protection { Derived()
{
System.out.println("derived
constructor");
System.out.println("n
= " + n);
//
class only // class only //
System.out.println("n_pri=
"+ n_pri);
System.out.println("n_pro=
" + n_pro);
System.out.println("n_pub=
" + n_pub);
}
}
package p1;
classSamePackage
{
SamePackage() {
Protection
p = new Protection();
System.out.println("same
package constructor");
System.out.println("n
= " + p.n);
//
class only // class only //
System.out.println("n_pri=
" + p.n_pri);
System.out.println("n_pro=
" + p.n_pro);
System.out.println("n_pub=
" + p.n_pub);
}
}
package p1; // Instantiate the various classes in
p1.
public
class Demo
{
public
static void main(String args[])
{
Protection
ob1 = new Protection();
Protection ob1 = new Protection();
Derived
ob2 = new Derived();
SamePackageob3 = new SamePackage();
}
}
package p1; // Instantiate the various classes in
p1.
public
class Demo
{
public
static void main(String args[])
{
Protection ob1 = new Protection();
Protection
ob1 = new Protection();
Derived
ob2 = new Derived();
SamePackageob3
= new SamePackage();
}
}
Package p2;
classOtherPackage
{
OtherPackage()
{
p1.Protection
p = new p1.Protection();
System.out.println("other
package constructor");
// class or package only //
System.out.println("n
= " + p.n);
// class only //
class only //
System.out.println("n_pri
= " + p.n_pri);
// class, subclass or package only //
System.out.println("n_pro
= " + p.n_pro);
System.out.println("n_pub
= " + p.n_pub);
}
}
//package p2; // Instantiate the
various classes in p2.
public
class Demo1
{
public
static void main(String args[])
{
Protection2 ob1 = new Protection2();
OtherPackageob2
= new OtherPackage();
}
} }
Importing Packages
This
is the general form of the import statement:
import
pkg1 [.pkg2].(classname| *);
Here,
pkg1 is the name of a toplevel package, and pkg2 is the name of a subordinate
package inside the outer package separated by a dot (.). There is no practical
limit on the depth of a package hierarchy, except that imposed by the file
system. Finally, you specify either an explicit classname or a star (*), which
file system. Finally, you specify either an explicit classname or a star (*),
which indicates that the Java compiler should import the entire package. This
code fragmentshowsbothformsinuse:
importjava.util.Date;
import
java.io.*;
java.lang.* is implicitly imported by the compiler for
all programs.
packageMyPack;
/*
Now, the Balance class, its constructor, and its show() method are public. This means that they can be used by nonsubclass code outside their
package. */
public
class Balance {
String
name;
doublebal;
public
Balance(String n, double b) {
name
= n;
name
= n;
bal=
b;
}
public
void show() {
if(bal<0)
System.out.print(">>
");
System.out.println(name
+ ": $" + bal);
}
}
importMyPack.*;
classTestBalance
{
public
static void main(String args[])
{
/*
Because Balance is public, you may use Balance class and call its constructor.
*/ call its constructor. */
Balance
test = new Balance("J. J. Jaspers", 99.88);
test.show();
// you may also call show()
}
}
Interfaces
Interfaces
are syntactically similar to classes, but they lack instance variables, and, as
a general rule, their methods are declared without any body. Any number of
classes can implement an interface. One class can implement any number of
interfaces. To implement an
interface,aclassmustprovidethecompletesetofmethodsrequired
bytheinterface.However,eachclassisfreetodeterminethedetails of its own
implementation. By providing the interface keyword, of its own implementation.
By providing the interface keyword, Java allows you to fully utilize the “one
interface, methods” aspect ofpolymorphism.
Defining an Interface
This
is a simplified general form of an interface:
access
interface name {
return-type
method-name1(parameter-list);
return-type
method-name2(parameter-list);
type
final-varname1 = value;
type
final-varname2 = value; //... return-type
method-nameN(parameter-list);
type
final-varnameN= value;
type
final-varnameN= value;
}
The
methods that are declared have no bodies. They end with a semicolon after the
parameterlist.They are,essentially,abstract methods.Variables are
implicitlyfinaland static, meaning they cannot be changed by the implementing
class. They must also be initialized. All methods and variables are implicitly
public. Each class that includes such an interface must implement all
ofthemethods.
Implementing
Interfaces
Once
an interface has been defined, one
or more classes can implement that
interface. To implement an
interface, include the implements
clause in a class definition, and then create the methods required by the
interface. The general form of a class that includes the implements clause looks like this:
class classname[extends
superclass]
[implements
interface [,interface...]]
{
//
classbody
}
}
If
a class implements more than one interface, the interfaces are separated with a
comma. If a class implements two interfaces that declare the same method, then
the same method will be used by clients of either interface. The methods that
implement an interface must be declared public.
Also, the type signature of the implementing method must match exactly the type
signature specified in the interface
definition.
interface
Callback {
void
callback(intparam);
}
class
Client implements Callback
{
//
Implement Callback's interface
public
void callback(intp) {
System.out.println("callback
called with " + p);
}
} }
classTestIface{
public
static void main(String args[])
{
Callback
c = new Client();
c.callback(42);
}
}
It is both permissible and common for classes that implement
interfaces to define additional members of their own. For example, the
following version of Client implements callback( ) and adds the method
nonIfaceMeth( ):
class
Client implements Callback {
//
Implement Callback's interface
public
void callback(intp)
{
System.out.println("callback
called with " + p);
}
voidnonIfaceMeth()
{
System.out.println("Classes
that implement interfaces " + System.out.println("Classes that
implement interfaces " + "may also define other members, too.");
}
}
classTestIface{
public static void main(String args[])
{
Callback c = new Client();
c.callback(42);
}
}
Although c can be used to access the callback( ) method, it cannot
access any other members of the Client class. An interface reference variable
has knowledge only of the methods declared by its interfacedeclaration.
interface
Callback {
void
callback(intparam);
}
class
Client implements Callback {
// Implement Callback's interface
public
void callback(intp) {
System.out.println("callback
called with " + p);
}
}
//
Another implementation of Callback.
classAnotherClientimplements
Callback {
// Implement Callback's interface
public
void callback(intp) {
System.out.println("Another
version of callback");
System.out.println("p
squared is " + (p*p));
}}
class
TestIface2 {
public
static void main(String args[])
{
Callback
c = new Client();
AnotherClientob
= new AnotherClient();
c.callback(42);
c
= ob;
//
c now refers to AnotherClient object
c.callback(42);
}
}
Partial
Implementations
If
a class includes an interface but does not fully implement the methods required
by that interface, then that class must be declared as abstract.
abstract
class Incomplete implements Callback {
int a,
b;
int a,
b;
void
show() {
System.out.println(a
+ " " + b);
}
//... }
NestedInterfaces
An interface can be declared a member of a class or another
interface. Such an interface is called a member interface or a nested interface. A nested interface can be declared as public, private, or protected. This differs from a
toplevel interface, which must either be declared as public or use the default access level. When a nested interface is used
outside of its enclosing scope, it must be qualified by the name of the class
or interface of which it is qualified by the name of the class or interface
of which it is a member. Thus, outside of the class or interface in which a
nested interface is declared, its name must be fully qualified.
// A nested interface example.
// This class contains a member
interface.
class
A {
//
this is a nested interface public interface
NestedIF{
booleanisNotNegative(intx);
}}
//
B implements the nested interface.
class
B implements A.NestedIF{
publicBoolean
isNotNegative(intx) {
return
x < 0 ? false: true;
}
}
classNestedIFDemo{
public
static void main(String args[])
{
//
use a nested interface reference
A.NestedIFnif=
new B();
if(nif.isNotNegative(10))
System.out.println("10
is not negative");
if(nif.isNotNegative(12))
System.out.println("this
won't be displayed");
}}
interface
Showable{
void
show();
interface
Message{
voidmsg();
}
}
class
Test implements Showable.Message { {
public
void msg()
{
System.out.println("Hello
nested interface");
}
public
static void main(String args[])
{
Showable.Messagemessage=new
Test();
//upcastinghere
message.msg();
}}
Variables in
Interfaces
importjava.util.Random;
interfaceSharedConstants
{
int
NO = 0;
intYES
= 1;
int
MAYBE = 2;
int
LATER = 3;
int
SOON = 4;
int
SOON = 4;
int
NEVER = 5;
}
class
Question implements SharedConstants
{
Random
rand = new Random();
int
ask()
{
intprob
= (int) (100 * rand.nextDouble());
if
(prob< 30)
return
NO; // 30%
else
if (prob< 60)
return
YES; // 30%
else
if (prob< 75)
return
LATER; // 15%
else
if (prob< 98)
return
SOON; // 13%
else
return NEVER; // 2%
}
}
classAskMe
implements SharedConstants {
static
void answer(int result)
{
switch(result)
{
case
NO: System.out.println("No");
break;
case
YES:
System.out.println("Yes");
break;
case
MAYBE: System.out.println("Maybe");
System.out.println("Maybe");
break;
case
LATER: System.out.println("Later");
break;
case
SOON: System.out.println("Soon");
break;
case
NEVER: System.out.println("Never");
Break;}}
public
static void main(String args[])
{
Question
q = new Question();
answer(q.ask());
answer(q.ask());
answer(q.ask());
answer(q.ask());
}
}
Interfaces Can
Be Extended
One
interface can inherit another by use of the keyword extends. The syntax is the
same as for inheriting classes.
// One interface can extend
another.
interface
A {
void
meth1();
void
meth2();
void
meth2();
}
// B now includes meth1() and
meth2() it adds meth3().
interface
B extends A {
void
meth3();
}
// This class must implement all of
A and B
classMyClassimplements
B
{
public
void meth1()
{
System.out.println("Implement
meth1().");
}
public
void meth2() {
System.out.println("Implement
meth2().");
}
public
void meth3() {
System.out.println("Implement
meth3().");
}
} }
classIFExtend{
public
static void main(String arg[]) {
MyClassob
= new MyClass();
ob.meth1();
ob.meth2();
ob.meth3();
}}
Default
Interface Methods
Prior
to JDK 8, an interface could not define any implementation whatsoever. This
meant that for all previous versions of Java, the methodsspecifiedby
aninterfacewereabstract,containingnobody.This is the traditional form of an
interface and is the type of interface that the preceding discussions have
used. The release of JDK 8 has changed this by adding a new capability to interface called the default method.
A default method lets
you define a default implementation for an interface
method.Inotherwords,byuseofadefaultmethod,itisnowpossiblefor an interface
method to provide a body, rather than being abstract.
It
is important to point out that the addition of default methods does not change a key aspect of interface:
Its inability to
maintain state information. Aninterfacestillcannothaveinstancevariables.
Default Method (
JDK 8)
An
interface default method is defined similar to the way a method is defined by a class. The primary difference is that
the declaration is preceded by the keyword default.
public
interface MyIF{
intgetNumber();
default
String getString() {
// This is a default method
return
"Default String";
}}
// Implement MyIF.
classMyIFImpimplementsMyIF{
// Only getNumber() defined by
MyIFneeds to be implemented.
// getString() can be allowed to
default.
publicintgetNumber()
{
return
100;
}
}
// Use the default method.
classDefaultMethodDemo
{
public
static void main(String args[])
{
MyIFImpobj=
new MyIFImp();
// Can call getNumber(), because it
is explicitly
// implemented by MyIFImp:
System.out.println(obj.getNumber());
// Can also call getString(),
because of default // implementation:
System.out.println(obj.getString());
}
}
It
is both possible and common for an implementing class to define its own
implementation of a default method. For example, MyIFImp2 overrides getString( ):
class
MyIFImp2 implements MyIF {
// Here, implementations for both
getNumber( ) and getString( ) are provided.
publicintgetNumber()
{
return
100;
}
}
public
String getString() {
return
"This is a different string.";
}
}
Now, when getString( ) is called, a
different string is returned
MultipleInheritanceIssue
Javadoesnotsupportthemultipleinheritanceofclasses.
Now that an interface can include default methods, you might be wondering if an
interfacecanprovideawayaroundthisrestriction.
Theansweris,essentially,NO.
As there is still a key difference between a class and an interface: a class
can maintainstateinformation(especiallythroughtheuseofinstancevariables),but an
interface cannot. Default methods do offer a bit of what one would normally associatewiththeconceptofmultipleinheritance.Forexample,youmighthavean
associatewiththeconceptofmultipleinheritance.Forexample,youmighthavea class
that implements two interfaces. If each of these interfaces provides default
methods, then some behavior is inherited from both. Thus, to a limited extent,
defaultmethodsdosupportmultipleinheritanceofbehavior.
*Whatifnameconflictwilloccur.
More Points on
Inheritance
IS-A Relationship
class
C1
{
…
}
class
C2 extends C1
{
…..
}
Has-A relationship
class
C1
{
…
}
class
C2
{
C1
obj=new C1();
…..
}
Uses-A relationship
class
C1
{
…
}
class
C2
{
void
display() {
C1 obj=new C1();
}
…..
}
Example on
aggregation Has-A type
class
Operation{
intsquare(intn)
{
return
n*n;
}
}
class
Circle
{
Operation
op;//aggregation
double
pi=3.14;
double
area(intradius)
{
Op=new Operation();
Intrsquare=op.square(radius);
//code reusability (i.e. delegates
the method call).
return
pi*rsquare;
}
public
static void main(String args[])
{
Circle c=new Circle();
double
result=c.area(5);
System.out.println(result);
}
}
Exception Handling
· An exception
is an abnormal condition that arises in a code sequence at runtime. In other words, an exception is a
runtime error.
· In computer languages that do not support exception
handling, errors must be checked and handled manually—typically through the use
of error codes, and soon.
In Java, an exception is an object(either of inbuilt class or of user-defined class)that
describes an exceptional(that is, error) condition that has occurred in a piece
of code. When an exceptional condition arises,an object representing that exception is created and thrown in the method that caused the error.
Java exception
handling is managed via five keywords:
1.
try,
2.
catch,
3.
throw,
4.
throws, and
5.
finally.
This is the general form of an
exceptionhandling block:
try {
//
block of code to monitor for 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
}
Here,
Exception Type is the type of exception that
has occurred.
Uncaught Exceptions
Small program
includes an expression that intentionally causes a dividebyzero error:
class Exc0 {
public static void main(String args[])
{
Int d = 0;
Int a = 42 / d;
} }
Here is the
exception generated when this example is executed:
java.lang.ArithmeticException: / by zero
at Exc0.main(Exc0.java:4)
When the Java run-time system
detects the attempt to divide by zero, it
constructs a new exception object and then throws this exception. This
causes the execution of Exc0 to stop, because once an exception has
been thrown, it must be caught by an exception handler and dealt with
immediately. In this example, we haven’t
supplied any exception handlers of
our own, so the exception is caught by the default handlerprovided by the Java run-time
system.
Any exception that is not caught by
your program will ultimately be processed bythe 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.
Another
version of the preceding program
class Exc1 {
static void subroutine()
{
Intd = 0;
Inta = 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:4)
at Exc1.main(Exc1.java:7)
Using
try and catch
To guard against and handle a
runtime error, simply enclose the code that you want to monitor inside a try block. Immediately following the
try block, includesa catch clause
that specifies the exception type that you wish to catch.
class Exc2 {
public static void main(String
args[]) {
intd, a;
try {
// monitor a block of code.
d = 0;
a = 42 / d;
System.out.println("This will
not be printed.");
}
catch (ArithmeticExceptione) {
//
catch dividebyzero error
System.out.println("Division
by zero.");
}
System.out.println("After
catch statement.");
} }
//
Handle an exception and move on.
import java.util.Random;
classHandleError {
public static void main(String
args[])
{
inta=0, b=0, c=0;
Random r = new Random();
for(inti=0; i<32000; i++)
{
try
{
b = r.nextInt();
c = r.nextInt();
c = r.nextInt();
a = 12345 / (b/c);
}
catch (ArithmeticExceptione)
{
System.out.println("Division
by zero.");
a = 0; // set a to zero and continue
}
System.out.println("a: "
+ a);
} } }
Displaying a Description of an Exception
Throwable
overrides the toString( ) method
(defined by Object) so that it returns a string containing a description of the
exception. You can display this description in a println( ) statement by simply
passing the exception as an argument. For example, the catch block in the
preceding program can be rewrittenlikethis:
catch (ArithmeticExceptione)
{
System.out.println("Exception:
" + e);
a = 0;
//
set a to zero and continue
}
When this version is substituted in
the program, and the program is run, each
divideby zero error displays the following message:
Exception:
java.lang.ArithmeticException: / by zero
Multiple catch Clauses
//
Demonstrate multiple catch statements.
class MultipleCatches{
public static void main(String
args[])
{
Try
{
Inta = args.length;
System.out.println("a =
" + a);
Intb = 42 / a;
Intc[] = { 1 };
c[42] = 99;
}
catch(ArithmeticExceptione)
{
System.out.println("Divide
by 0: " + e);
}
catch(ArrayIndexOutOfBoundsException
e)
{
System.out.println("Array
index oob: " + e);
}
System.out.println("After
try/catch blocks.");
} }
|
Here
is the output generated by running it two different ways:
C:\>java MultipleCatches
a = 0
Divide by 0:
java.lang.ArithmeticException:
/ by zero
After try/catch blocks.
C:\>java MultipleCatchesTestArg
a = 1
Array index oob:
java.lang.ArrayIndexOutOfBoundsExceptio
n:42
After try/catch blocks.
|
/*
This program contains an error. A subclass must come before its superclass in a
series of catch statements. If not, an unreachable code will be created and a
compile-time error will result. */
classSuperSubCatch{
public static void main(String
args[])
{
try
{
inta = 0;
intb = 42 / a;
}
catch(Exception e)
{
System.out.println("Generic
Exception catch.");
} }
/*
This catch is never reached because ArithmeticExceptionis a subclass of
Exception. */ catch(ArithmeticExceptione)
{
//
ERROR –unreachable
System.out.println("This is
never reached.");
} } }
Nested try Statements
The
try statement can be nested. That is, a try statement can be
insidetheblockofanothertry.Eachtimeatrystatementisentered, the context of
that exception is pushed on the stack. If an
inner try statement does not have a
catch handler for a particular exception, thestackisunwoundandthenexttrystatement’scatchhandlersare inspected for a match.
This continues until one of the catch
statements succeeds, or until all of the nested try statements are exhausted. If
no catch statement matches, then the Java runtime systemwillhandlethe
exception.
//
An example of nested try statements.
classNestTry{
public static void main(String
args[])
{ try
{
Inta = args.length;
/*
If no commandlineargsare present, the following statement will generate a
dividebyzero exception. */
Intb = 42 / a;
System.out.println("a = "
+ a);
/* If one commandlineargis used, then a
dividebyzero exception will be generated by the following code. */
try
{
// nested try block i
f(a==1)
a = a/(aa);
// division by zero
/* If two commandlineargsare used, then
generate an outofbounds exception. */
if(a==2)
{
Intc[] = { 1 };
c[42] = 99;
//
generate an outofbounds exception
}}
catch(ArrayIndexOutOfBoundsException
e){
System.out.println("Array
index outofbounds: " + e); }
}
catch(ArithmeticExceptione)
{
System.out.println("Divide by
0: " + e);
}}}
So far, you have only been catching
exceptions that are thrown by the Java runtime system. However, it is possible
for your program to throw an exception
explicitly,using the throw statement.The general form of throw is shown here:
Throw
ThrowableInstance;
Here, ThrowableInstance must be an
object of type Throwable or a
subclass of Throwable. Primitive
types, such as int or char, as well as nonThrowable
classes, such as String and Object, cannot be used as exceptions. There are two
ways you can obtain a Throwable object:
using a parameter in a catch clause or creating one with the new operator.
// Demonstrate throw.
classThrowDemo
{
static void demoproc()
{
try
{
throw new
NullPointerException("demo");
} catch(NullPointerExceptione)
{ System.out.println("Caught
inside demoproc.");
throwe; // rethrowthe exception
} }
public static void main(String
args[])
{
Try
{
demoproc();
}
catch(NullPointerExceptione)
{
System.out.println("Recaught:
" + e);
} } }
What will be the output?
public class TestThrow1
{
static void validate(intage)
{
if(age<18)
throw new ArithmeticException("not
valid");
else
System.out.println("welcome to
vote");
}
public static void main(String
args[])
{
validate(13);
System.out.println("rest of
the code...");
}
}
Throws
If a method is capable of causing an exception
that it does not handle, it must specify this behavior so thatcallers of
themethod can guard themselvesagainst that exception. You do this by including
a throws clause in the method’s declaration. A throws clause lists the types of
exception(s) 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 declaredinthethrowsclause.Iftheyarenot,acompiletimeerror
will result.
This
is the general form of a method declaration that includes a throws clause:
type method-name(parameter-list)
throws exception-list
{
// body of method
}
//
This program contains an error and will not compile.
classThrowsDemo
{
static void throwOne()
{
System.out.println("Inside
throwOne.");
throw new
IllegalAccessException("demo");
} }
public static void main(String
args[])
{
throwOne();
} }
//
This is now correct.
classThrowsDemo
{
static void throwOne() throws
IllegalAccessException
{
System.out.println("Inside
throwOne.");
throw new
IllegalAccessException("demo");
}
public static void main(String
args[])
{
try
{
throwOne();
}
catch (IllegalAccessExceptione)
{
System.out.println("Caught
" + e);
} } }
Here IllegalAccessExceptionis checked Exception so catch is a
must.
What will be the output?
importjava.io.IOException;
class Testthrows1
{
void m()throws IOException{
throw new IOException("device
error");
//checked
exception
}
void n()throws IOException{
m();
}
void p(){
try{
n();
}
catch(Exception e){
System.out.println("exception
handled");
} }
public static void main(String
args[])
{
Testthrows1 obj=new Testthrows1();
obj.p();
System.out.println("normal
flow...");
}
}
finally
·
finallycreatesablockofcodethatwillbeexecutedafteratry/catchblockhas completedandbeforethecodefollowingthetry/catch block.
·
Thefinallyblockwillexecutewhetherornotanexceptionis 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.
// Demonstrate
finally.
classFinallyDemo{
// Throw an exception out of the
method.
static
void procA()
{
Try
{
System.out.println("inside
procA");
throw
new RuntimeException("demo");
}
finally
{
System.out.println("procA'sfinally");
}
}
// Return from within a try block.
static
void procB()
{
Try
{
System.out.println("inside
procB");
return;
}
Finally
{
System.out.println("procB'sfinally");
}}
// Execute a try block normally.
static
void procC()
{
Try
{
System.out.println("inside
procC");
}
finally
{
System.out.println("procC'sfinally");
}}
public
static void main(String args[])
{
Try
{
procA();
}
catch
(Exception e)
{
System.out.println("Exception
caught");
}
procB();
procC();
} }
Some
of Java’s Built-in Exceptions
Exception
|
Meaning
|
ArithmeticException
|
Arithmetic
error, such as dividebyzero.
|
ArrayIndexOutOfBoundsException
|
Array
index isoutofbounds.
|
ArrayStoreException
|
Assignment
to an array element of an incompatible type.
|
IllegalArgumentException
|
Illegal
argument used to invoke a method.
|
NegativeArraySizeException
|
Array
created with a negative size.
|
NumberFormatException
|
Invalid
conversion of a string to a numeric format
|
UnsupportedOperationException
|
An
unsupported operation was encountered.
|
//Example
classMydemo {
public static void main(String
args[])
{
Inta[];
try
{
a= new int[10];
System.out.println("Hello");
throw new
InterruptedException("demo");
} }
catch(NegativeArraySizeExceptione)
{
System.out.println("Negative
array size exception");
}
catch(InterruptedExceptione)
{
System.out.println("InterruptedException");
} } }
Java’sBuilt-inExceptions
The most general of these
exceptions are subclasses of the standard type RuntimeException. In the language of Java, these are called unchecked exceptions because the
compiler does not check to see if a method handles or throws these exceptions. The exceptions defined by java.lang
that must be included in a method’s throws list if that method can generate one
of these exceptions and does not handle it itself.These are called checked
exceptions.
Java’s Checked Exceptions Defined
in java.lang
Creating Your Own Exception Subclasses
This is quite easy to do: just define a subclass of Exception(whichis,
of course, a subclass of Throwable).
Your subclasses don’t need to actually implement anything—it is their existence
in the type systemthat allows you to use them as exceptions.
Exception
defines four public constructors.
1.
Exception(
)
2.
Exception(String
msg)
The first form creates an exception that has no description. The second
form lets you specify a description
of the exception.
//
This program creates a custom exception type.
classMyExceptionextends Exception
{
privateintdetail;
MyException(inta)
{
detail = a;
}
public String toString()
{
return "MyException[" +
detail + "]";
return "MyException[" +
detail + "]";
} }
classExceptionDemo{
static void compute(inta) throws
MyException{
System.out.println("Called
compute(" + a + ")");
if(a > 10)
throw new MyException(a);
System.out.println("Normal
exit");
}
public static void main(String
args[])
{
Try
{
try
{
compute(1);
compute(20);
}
catch (MyExceptione)
{
System.out.println("Caught
" + e);
} } }
ChainedExceptions
Chained
exceptions feature was
incorporated into the exception subsystem JDK 1.4. The chained exception feature allows you to associate another exception
with an exception. This second exception describes the cause of the first
exception. For example, imagine a
situation in which a method throws an ArithmeticException because of an attempt
to divide by zero. However, the actual cause of the problem was that an I/O
error
occurred,whichcausedthedivisortobesetimproperly.
To
allow chained exceptions, two constructors and two methods were added
toThrowable.
Throwable(ThrowablecauseExc)
Throwable(Stringmsg,ThrowablecauseExc)
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 ErrorException,
and RuntimeExceptionclasses.
The
chained exception methods supported byThrowableare getCause(
) and initCause( ).
1.
ThrowablegetCause( )
2.
ThrowableinitCause(ThrowablecauseExc)
ThegetCause() methodreturns theexception thatunderlies the
currentexception. If there is no underlying exception, null is returned. The initCause( ) method associates causeExc
with the invoking exception and returns a reference to the exception. Thus, you
can associate a cause with an exception after the exception has been created.
However, the cause exception can be set
only once. Thus, you cancallinitCause()onlyonceforeachexceptionobject.Furthermore,ifthecause
exceptionwassetbyaconstructor,thenyoucan’tsetitagainusinginitCause().
//
Demonstrate exception chaining.
classChainExcDemo
{
static void demoproc()
{
//
create an exception
NullPointerExceptione = new
NullPointerException("top layer");
//
add a cause
e.initCause(new
ArithmeticException("cause"));
throwe;
}
public static void main(String
args[])
{
try
{
demoproc();
}
catch(NullPointerExceptione)
{
//
display top level exception
System.out.println("Caught:
" + e);
//
display cause exception
System.out.println("Original
cause: " + e.getCause());
} } }
MULTITHREAD PROGRAMMING
A multithreaded program contains two or more parts that can run
concurrently. Each part of such a program is called a thread, and each thread
defines a separate path of execution. Thus, multithreadingisaspecializedformofmultitasking.
Types of multitasking:
1.
Process-based multitasking is the feature that allows your computer to run two
or more programs concurrently. For example, process based multitasking enables
you to run the Java compiler at the same time that you are using a text editor
or visiting a website.
2.
Thread-based multitasking environment, the thread is the smallest unit of
dispatchable code. This means that a single program can perform two or more
tasks simultaneously. For instance, a text editor can format text at the same
time that it is printing, as long as these two actions are being performed by
two separate threads.
Threadlifecycle
Threads exist in several states. Here is a general
description. A threadcan be running.Itcan
be ready to run as soon as it gets
CPU time. A running thread can be suspended, which temporarily halts its activity. Asuspended thread
can then be resumed, allowing it to pickupwhereitleftoff.Athreadcanbeblockedwhenwaitingfora resource. At any
time, a thread can be terminated,
which halts its execution immediately. Once terminated, a thread cannot be
resumed.
ThreadPriorities
Java assigns to each thread a
priority that determines how that thread should be treated with respect to the
others. Thread priorities are integers that specify the relative priority of
one thread to another. As an absolute
value, a priority is meaningless; a higherpriority thread doesn’t run any
faster than a lowerpriority thread if it is the only thread running. Instead,
a thread’s priority is used to decide when to switch from one running thread to
the next. This is called a context
switch. The rules that determine
when a context switchtakesplacearesimple:
• A thread can voluntarily
relinquish control. This is done by explicitly yielding, sleeping, or blocking
on pending I/O. In this scenario, all other threads are examined, and the
highestpriority thread that is ready to run is giventheCPU.
• A thread can be preempted by a
higher-priority thread. In this case, a lowerpriority thread that does not
yield the processor is simply preempted— nomatterwhat itisdoing—bya
higherprioritythread.Basically,as soon asa higherpriority thread wants to
run, it does. This is called preemptive
multitasking.
For operating systems such as Windows, threads of equal priority are timesliced automatically
in roundrobin fashion.
Synchronization
Because multithreading introduces
an asynchronous behavior to your programs, there must be a way for you to
enforce synchronicity when you need it. For example, if you want two
threads to communicate and share a complicated data structure, such as a
linked list, you need some way to ensure
that they don’t conflict with each other. That is, you must prevent one thread from writing data while another
thread is in the middle of reading it. For this purpose, Java implements an
elegant twist on an ageold model of interprocess
synchronization: the monitor. You can think of a monitor as a very small
box that can hold only one thread. Once a thread enters a monitor, all other
threads must wait until that thread exits the monitor. In this way, a monitor
can be used to protect a shared asset from being manipulated by more than one
thread at a time. In Java, there is no
class “Monitor”; instead, each object has its own implicit monitor that is
automatically entered when one of the object’s synchronized methods is called.
Once a thread is inside a synchronized method, no other thread can call any
other synchronized method on the same object. This enables you to write very
clear and concise multithreaded code,
because synchronization support is built into the language.
Messaging
After you divide your program into
separate threads, you need to define how they will communicate with each other.
Java provides a clean, lowcost way for
two or more threads to talk to each other, via calls to predefined methods that
all objects have. Java’s messaging
system allows a thread to enter a synchronized method on an object, and
then wait there until some otherthread explicitlynotifiesittocomeout.
Thread Class and the RunnableInterface
To create a new thread, your
program will either extend Thread or
implement the Runnable interface.
The Thread class defines several
methods that help manage threads. Several of those used in this chapter are
shown here:
Method
|
Meaning
|
getName
|
Obtain a thread’s name
|
getPriority
|
Obtain a thread’s priority
|
isAlive
|
Determine if a thread is still
running
|
join
|
Wait for a thread to terminate.
|
run
|
Entry point for the thread
|
sleep
|
Suspend a thread for a period
of time
|
start
|
Start a thread by calling its
run method
|
Main Thread
When a Java program starts up, one
thread begins running immediately. This is usually called the main thread of your program.
The
main thread is important for two reasons:
• It is the thread from which other “child” threads
will be spawned.
• Often, it must be the last thread to finish
execution because it performs various shutdown actions.
The
main thread can be controlled through a Thread object.
//
Controlling the main Thread.
classCurrentThreadDemo
{
public static void main(String
args[])
{
Thread t = Thread.currentThread();
System.out.println("Current
thread: " + t);
//
change the name of the thread
t.setName("My Thread");
System.out.println("After name
change: " + t);
try {
for(intn = 5; n > 0; n)
{
for(intn = 5; n > 0; n)
{
System.out.println(n);
Thread.sleep(1000);
} }
catch (InterruptedExceptione)
{
System.out.println("Main
thread interrupted");
} } }
A thread group is a data
structure that controls the state of a collection of threads as a whole.
Output
Current thread: Thread[main,5,main]
After name change: Thread[My
Thread,5,main]
5
4
3
2
1
final void setName(String threadName)
final String getName( )
sleep( ) method
The sleep( ) method causes the thread from which it is called to
suspend execution for the specified period of milliseconds. Its general form is shown here:
static void sleep(long
milliseconds) throws InterruptedException
static void sleep(long
milliseconds, intnanoseconds) throws InterruptedException
Creating a Thread
• You can implement the
Runnableinterface.
• You can extend the Thread class,
itself.
Implementing Runnable
i. Create a class that implements
the Runnable
ii. To implement Runnable, a class need only implement a
single method called run() [ public void
run( ) ].
iii. Code in run()constitutes the new
thread.
iv. Instantiate an object of type Thread from within the class using construct or Thread(RunnablethreadOb,
String threadName). Where, threadObis an instance of a class that
implements the Runnable interface.
v. Call start( ) method with the object to initiate the execution of run( )
method.
//
Create a second thread.
classNewThread implements Runnable
{
Thread t;
NewThread() {
t = new Thread(this, "Demo Thread");
// Create a new, second thread
System.out.println("Child
thread: " + t);
t.start();
// Start the thread
} public void run()
// This is the entry point for the
second thread.
{
try
{
try
{
for(int i= 5; i> 0; i)
{
System.out.println("Child
Thread: " + i);
Thread.sleep(500);
} }
catch (InterruptedException e)
{
System.out.println("Child
interrupted.");
}
System.out.println("Exiting
child thread.");
} }
Extending Thread
i. Create a new class that extends Thread
ii. Override the run( ) method,
iii. Create an instance of the class
iv. Call start(
) to begin execution of the new thread.
Using isAlive( ) and join( )
As mentioned, often you will want
the main thread to finish last. In the preceding examples, this is accomplished
by calling sleep( ) within main( ), with a long enough delay to
ensure that all child threads terminate prior to the main thread.
Two
ways exist to determine whether a thread has finished.
First, you can call isAlive( ) on the thread. This method
is defined by Thread, and its general form is shown here:
finalbooleanisAlive(
)
The
isAlive( ) method returns true if the
thread upon which it is called is still running. It returns false otherwise. While isAlive( ) is occasionally useful, the
method that you will more commonly use to wait for a thread to finish is called
join( ), shown here:
final
void join( ) throws InterruptedException
This method waits until the thread
on which it is called terminates. Its name comes from the concept of the
calling thread waiting until the specifiedthreadjoins it.Additional forms of join() allow you to specify a maximum amount of
time that you want to wait for the specified thread toterminate.
//
Using join() to wait for threads to finish.
classNewThreadimplements Runnable{
String name;
//
name of thread
Thread t;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New
thread: " + t);
t.start();
//
Start the thread
}
//
This is the entry point for thread.
public void run()
{
public void run()
{
try
{
for(inti= 5; i> 0; i)
{
System.out.println(name + ":
" + i);
Thread.sleep(1000);
} }
catch (InterruptedExceptione)
{
System.out.println(name + "
interrupted.");
}
System.out.println(name + "
exiting.");
}}
classDemoJoin{
public static void main(String
args[]) {
NewThreadob1 = new NewThread("One");
NewThreadob2 = new
NewThread("Two");
NewThreadob3 = new
NewThread("Three");
System.out.println("Thread One
is alive: “+ ob1.t.isAlive());
System.out.println("Thread Two
is alive: “+ ob2.t.isAlive());
System.out.println("Thread
Three is alive: “+ ob3.t.isAlive()); //
wait for threads to finish
try
{
Try
{
System.out.println("Waiting
for threads to finish.");
ob1.t.join();
ob2.t.join();
ob3.t.join();
}
catch (InterruptedExceptione) {
System.out.println("Main
thread Interrupted");
}
System.out.println("Thread One
is alive: " + ob1.t.isAlive());
System.out.println("Thread Two
is alive: "+ ob2.t.isAlive());
System.out.println("Thread
Three is alive: “+ ob3.t.isAlive());
System.out.println("Main
thread exiting.");
} }
Output
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
Thread One is alive: true
Thread Two is alive: true
Thread Three is alive: true
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Two: 3
Three: 3
One: 2
One: 2
Two: 2
Three: 2
One: 1
Two: 1
Three: 1
Two exiting.
Three exiting.
One exiting.
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread exiting.
Thread Priorities
Thread priorities are used by the
thread scheduler to decide when each thread should be allowed to run.
MIN_PRIORITY (1)
NORM_PRIORITY
(5)
MAX_PRIORITY
(10)
These priorities are defined as static final variables within Thread.
finalintgetPriority( ) //
returns current priority
final void setPriority(intlevel)
level
must be within the range MIN_PRIORITY
(1) and MAX_PRIORITY (10).
SynchronizedMethods
Synchronization is easy in Java,
because all objects have their own implicit monitor associated with them. To
enteran object’s monitor, just call a method that has been modified with the
synchronized keyword. While a thread is inside a synchronized method, all other
threads that try to call it (or any other synchronized method) on the same
instance have to wait. To exit the monitor and relinquish control of the object
to the next waiting thread, the owner of the
monitorsimplyreturnsfromthesynchronizedmethod.
Synchronized
Method
To fix the preceding program, you
must serialize access to call( ).
That is, you must restrict its access to only one thread at a time. To do this,
you simply need to precede call( )’s definition with the keyword synchronized,
as shown here:
classCallme{ synchronized void
call(String msg) { ...
This
prevents other threads from entering call( )
while another thread is using it.
Output
[Hello]
[Synchronized]
[World]
Synchronized Statement
Imagine that you want to synchronize access to objects of a
class that was not designed for multithreaded access. That is, the class does
not use synchronized methods. Further, this class was not created by you, but
by a third party, and you do not have access to the source code. Thus, you
can’t add synchronized to the appropriate methods within the class. How can access to an object of this class
be synchronized? Fortunately, the solution to this problem is quite easy: You simply put calls to the methods defined
by this class inside a synchronizedblock.
This
is the general form of the synchronized statement:
synchronized(objRef) {
// statements to be synchronized
}
Here, objRefis a reference to the
object being synchronized. A synchronized block ensures that a call to a
synchronized method that is a member of objRef’sclass occurs only after the
current thread has successfully entered objRef’smonitor.
InterthreadCommunication
The preceding examples
unconditionally blocked other threads from asynchronous access to certain
methods. This use of the implicit monitors in Java objects is powerful, but
youcan achieve a more subtle level of control through interprocess
communication. Java includes an elegant interprocess communication mechanism
via the wait( ), notify( ), and
notifyAll( ) methods. These methods are implemented as final methods in
Object, so all classes have them. All three methods can be called only from
within a synchronized context.
i.
wait( )
tells the calling thread to give up the monitor and go to sleep until some
other thread enters the same monitor and calls notify( ) or notifyAll( ).
ii.
notify( )
wakes up a thread that called wait( )
on the same object.
iii.
notifyAll( )
wakes up all the threads that called wait( ) on the same object. One of the
threads will be granted access
These methods are declared within Object, as shown here:
final void wait( ) throws
InterruptedException
final void notify( )
final void notify All( ).
Obtaining
A Thread’s State
The current state of a thread can be obtained by calling the getState( ) method defined by Thread.
Thread.StategetState( )
It returns a value of type Thread.Statethat indicates the state of
the thread at the time at which the call was made. State is an enumeration defined by Thread.
Given a Thread instance, you can
use getState( ) to obtain the state
of a thread. For example, the following sequence determines if a thread called
thrd is in the RUNNABLE state at the
time getState( ) is called: Thread.Statets= thrd.getState();
if(ts== Thread.State.RUNNABLE) //….
No comments:
Post a Comment