2.
Animation - Threads And Exceptions
Introduction
In the previous
chapter, we introduced you to the methods paint() and repaint() which are the
foundation of graphical display in Java. These methods allow your Java programs
to display images, shapes, colors etc. We saw how it can be used to draw a
simple line. In this chapter, we will introduce you to Animation using Java.
Animation has many uses, from dramatic web pages to exciting games. Java
animation is superior to things like animated GIF files because it provides
dynamic interaction instead of just a static performance. Here, you will learn
how to animate image files. This chapter also introduces the concept of threads
and exceptions.
But before we get down
to animation, there are a few more functions that you need to learn.
The following program
introduces a new function called getCodeBase.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
System.out.println(getCodeBase());
}
}
The init function
calls System.out.println. Here, instead
of passing a string we are giving a function- getCodeBase as a parameter.
getCodeBase already exists within the Applet class as a function. getCodeBase
returns the location of the applet class i.e. the sub directory which contains
the code of the applet.
C:\javaprg>javac zzz.java
C:\javaprg>appletviewer a.html
file:/C:/javaprg/
We once came across
graffiti that said, “You can’t fool me, I’m too stupid!!” But we intend no
folly here!
Let’s understand the
output.
Our applet is based on
our local machine and hence it says file: We are on a windows machine in C:
drive within the javaprg subdirectory. This is the location from where the
applet code has been picked up. Had the applet been picked up from another
site, getCodeBase would have returned a url (uniform resource locater). A url
or a uri (uniform resource identifier) identifies some resource.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
java.util.Date d;
d = new java.util.Date();
System.out.println(d);
}
}
In the previous
programs, when we declared a variable int ii, we were actually creating an
object ii that looked like an int. In this program, java.util.Date d will
create a variable called d that looks like java.util.Date. We decided not to
have the import statement for Date, hence the longish name. You can rewrite the
code with Date and the line import java.util.* on the top.
There is a difference
between saying Date d and int i. A variable gets created as an object if its
data type is int, char or long. These data types are built into programming
languages like C and C++. In such a case the object is created at the time of
its declaration. Anything other than the basic data types must be explicitly
created. Java implements the same rules.
Thus when we say d
looks like Date, we are not creating an object that looks like Date. Here the
object is declared to be of Date type and will be created in the future.
Let’s understand how
we can create objects ourselves.
To create an object
other than the basic types, languages like C++ utilized the word new. Java
follows the same route and uses new as well. The next line in our program uses
new to create the object d. The keyword new requires the name of the class
which in this case is java.util.Date.
d now becomes an
instance or an occurrence of the class Date. Date is given with the round
brackets because that is part of Java’s syntax. The println function with d as
a parameter will display the current date and time at which we ran the applet.
C:\javaprg>javac zzz.java
C:\javaprg>appletviewer a.html
Fri Apr 28 19:52:31 GMT+05:30 2000
In the previous
chapter, we used the paint function extensively. We also had g that looked like
Graphics and if you recollect we did not use new Graphics() anywhere. The
reason for this is that whoever called paint had already created an instance of
Graphics and passed it as a parameter. Hence we were spared effort of doing so
ourselves.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
Image n;
public void init()
{
n = getImage(getCodeBase(),”T1.gif”);
}
public void paint(Graphics g)
{
g.drawImage(n,10,40,this);
}
}
This program
introduces an additional class called Image. n looks like Image. Every class has
code as does Image which has its own code and its own set of variables. This
class handles images. getImage is a function that requires a location from
where the image file can be picked up. So the first parameter is the location
and the second parameter is the name of the graphics file. The function
getCodeBase returns the location of the applet.
For this program, you
need a gif file called T1.gif which must be placed in the same directory as
that of the applet. T1.gif comes with the Java development kit. T1.gif can be
found by doing the following: go to the jdk1.2.2 subdirectory, there you will
find many directories one of which is named demo. From demo, go to applets,
which will take you to animator. One of the subdirectories here is named
images, which has beans and within beans lies T1.gif. The T series starts from
T1 and goes up to T10. We recommend you copy all of them to your current
directory, which in our case is c:\javaprg.
getImage returns an
image which is stored in n. That means this function internally performs a new
Image and returns an object that looks like Image. In our current program, n
represents an image T1.gif. Just as drawLine and drawString are functions in
the Graphics class and to call them we
say g.drawString and g.drawLine, the same applies to the drawImage
function. It is also to be found within the Graphics class. drawImage takes 4
parameters. The dot separates the name of the object from the name of the
function.
The first parameter to
the drawImage function is an image, the second is the x coordinate, the third
is the y coordinate and the last one is a instance of an object. n in our
program represents the image T1.gif which is to be displayed. The next two are
the locations on the screen where we want the image to appear and finally we
have the word ‘this’.
‘this’ is a reserved
word; it is a part of the Java programming language. In our code it stands for
two things, either zzz or applet. ‘this’ stands for the current class or the class that you are extending from. So if
Applet has been extended from two or three or more classes then it stands for
them too. drawImage requires an instance of a class i.e. an object and hence we provide it as the last parameter by saying ‘this’; which means zzz or Applet.
After running the
applet you will see the image T1.gif displayed in the appletviewer.
The next program is
similar to the earlier one. This program proves that strings and images are all
treated in the same manner. This may seem strange at first, but you’ll soon get
used to the idea.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
Image n;int x = 19,y=76;
public void init()
{
n = getImage(getCodeBase(),”T1.gif”);
}
public void paint(Graphics g)
{
g.drawImage(n,x,y,this);
}
public boolean mouseDown(Event e , int x1 ,int y1)
{
x = x1; y = y1;
repaint();
return true;
}
}
In this program, we
have used drawImage instead of drawString. Whenever the mouse is clicked in the
window, x and y get initialized to the click position. repaint() calls the
paint function which in turn draws the image where the mouse is clicked. Thus
the image follows the mouse click.
Loops
The if statement is
the bedrock of programming because it gives intelligence and decision power to
a language. The second major part of any programming language is a looping
construct. In Java, the for statement allows you to repeat computer programming
statements. However, you already know that we can enclose statements within a
block, thus it also allows repetition of multiple statements.
This next program
should clarify this.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
int i;
for ( i = 1; i<= 10; i = i + 1)
{
System.out.println(“Hi “+i);
}
}
}
The for statement has
2 semicolons. The statement upto the first semicolon is executed only once. For
the first time i.e. only once is i initialized to 1. The statement enclosed
within the first and second semicolon is a condition. The condition checks
whether i <= 10 evaluates to true. Since this condition evaluates to true,
the statements within the open and the close brackets will be executed. If the
condition evaluates to false, all these statements are skipped and the loop
terminates. Here, since the for loop is required to execute only a single statement,
the ‘{}’ brackets are optional. This rule is applicable here too. The variable
i has a value 1 which is less than 10, so System.out.println will be called and
it will display hi 1. After all the statements within the block are executed,
the last part of the for is executed. i=i+1 will increase the value of i by 1,
making its new value 2. The condition is checked again, is 2 <= 10? The
answer here is true so hi 2 is displayed. Now i is incremented once more and
now becomes 3. The condition 3 <= 10 is again evaluated to true or false and
this goes on till the condition is false. When i has the value 11, the
condition checked is, 11 <= 10, which is false. The for terminates and the
remaining lines of the program after the for block are executed. This is how
the for statement enables the repetition of code. When we leave the for
statement the value of i will be 11.
The while lopp is
similar to the for loop.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
int i;
i = 1;
while ( i<= 10 )
{
System.out.println(“Hi “+i);
i = i + 1;
}
}
}
The while loop only
takes a condition, hence the variable i is initialized to 1 before entering the
loop. The condition checks if i <= 10 evaluates to true. Currently the value
of i is 1. The condition evaluates to true and the statements within the curly
braces are executed. System.out.println is called with Hi and i. The next most
important thing to do is increment the value of i or else it will have the same
value and the loop will go on indefinitely.
You may ponder over
the question, “Should I use for or while?’ After all, the for loop is similar
to the while loop. To answer your question is “On Mondays, Wednesdays, Fridays
use for and on Tuesdays, Thursdays, Saturdays use while. Take a break on
Sundays; nobody works on Sundays”. Alternatively “Toss a coin. If it’s heads
use while and if it’s tails, don’t use for” ;-)
This is the biggest
problem regarding computer programming. There are multiple ways of doing the
same thing. Both while and for do the same thing. The middle parameter of the
for statement and the condition in while loop are basically the same. It is
entirely up to you to choose one.
The next program
creates an infinite loop using the while statement.
The while condition
simply says true. The condition will never evaluate to false and hence the loop
will go on indefinitely.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
int i;
i = 1;
while ( true )
{
System.out.println(“Hi “+i);
i = i + 1;
}
}
}
Arrays
All programming
languages implement arrays. An array is just another entity. For e.g., all the
people born in India can be said to belong to a single array named India. They
are all parts of a single whole. The concept of an array is very flexible and
like beauty, lies in the eyes of the beholder.
Here is the simplest
example on arrays.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
int n[];
int i = 0;
public void init()
{
n = new int[4];
n[0] = 10;
n[1] = 20;
n[2] = 30;
n[3] = 40;
for (i=0; i < 4; i++)
System.out.println(n[i]);
}
}
C:\javaprg>javac zzz.java
C:\javaprg>appletviewer a.html
10
20
30
40
The init function
contains int n[ ]. The [ ] tells us that the variable is an array. Here n is an
array of ints. int i is another variable. At this point it is not known how
large the array will be. So on the next line we give n = new int[4]. This will
create 4 variables called n[0], n[1], n[2] and n[3]. These variables now need
to be initialized and we do this by giving every variable its own value. n[0]is
initialized to 10, n[1] to 20 and so on. The only change from earlier programs
is that we have created 4 int’s in one step and they have names like n[0] and
so on.
The for loop is used
to display these variables. At first i is initialized to 0. The condition
i<4 indicates that the loop will execute 4 times. System.out.println (n[i]), for the first time, will be
System.out.println(n[0]), hence it will display 10. In the next round, i will
be 1 hence System.out.println(n[1]) will display 20 and so on. In
System.out.println, it is not specifically stated which variable, instead we
have said n[i]. There is no variable called n[i], but each time the loop
executes i gets a new value ranging from 0 to 3. Arrays are thus suited for
loops as we can use a variable i to decide the name of the array variable and
thus its value. So one variable’s value decides the name of another variable.
This extra layer of abstraction allows us to create complex programs.
Doing this makes our
programs more generic. We haven’t specifically named each variable, instead
we’re using another variable to form the name.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
Image n[]; int i = 0;
public void init()
{
n = new Image[4];
n[0] = getImage(getCodeBase(),”T1.gif”);
n[1] = getImage(getCodeBase(),”T2.gif”);
n[2] = getImage(getCodeBase(),”T3.gif”);
n[3] = getImage(getCodeBase(),”T4.gif”);
}
public void paint(Graphics g)
{
g.drawImage(n[i],1,10,this);
}
}
This program creates
an array name n of type Image. n is an array of images. But how many images? n= new Image[4]
determines the number of images i.e. it creates an array 4 images. They are
initialized individually. drawImage is given the first parameter as n[i].
Remember, the value of i is 0 thus we see the image which is stored in n[0]; in
this case, T1.gif.
This goes to prove
that what we did for ints is also applicable to images. The same rules apply.
In the following
program, each time the mouse is clicked, i is incremented by 1 and then the
paint function is called.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
Image n[]; int i = 0;
public void init()
{
n = new Image[4];
n[0] = getImage(getCodeBase(),”T1.gif”);
n[1] = getImage(getCodeBase(),”T2.gif”);
n[2] = getImage(getCodeBase(),”T3.gif”);
n[3] = getImage(getCodeBase(),”T4.gif”);
}
public void paint(Graphics g)
{
g.drawImage(n[i],1,10,this);
}
public boolean mouseDown(Event e , int x1 ,int y1)
{
i++;
repaint();
return true;
}
}
The first time you see
image n[0], then n[1], then n[2] and then n[3]. But the moment i becomes 4,
drawImage takes the first parameter as n[4]. Since our array is not large
enough, thus when you go back to the dos screen you will see a screen full of
errors.
Let’s see what we can
do to prevent these errors.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
Image n[]; int i = 0;
public void init()
{
n = new Image[4];
n[0] = getImage(getCodeBase(),”T1.gif”);
n[1] = getImage(getCodeBase(),”T2.gif”);
n[2] = getImage(getCodeBase(),”T3.gif”);
n[3] = getImage(getCodeBase(),”T4.gif”);
}
public void paint(Graphics g)
{
g.drawImage(n[i],1,10,this);
}
public boolean mouseDown(Event e , int x1 ,int y1)
{
i++;
if ( i == 4)
i = 0;
repaint();
return true;
}
}
Here, we are making
sure that when the variable i becomes 4, it is re-initialized to 0. Thus as you
keep clicking in the window, i gets a new value which is within the limits of
the array size and the images keep changing.
Using this concept,
let’s animate the 10 pictures that you copied into your current directory. The
pictures range from T1 to T10. Since there are 10 pictures, if you click in the
window fast enough you will see different pictures displayed each time,
resulting in animation. The following program demonstrates this.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
Image n[]; int i = 0;int j = 1;
public void init()
{
n = new Image[10];
for ( i = 0; i <= 9 ; i++)
{
n[i] = getImage(getCodeBase(),”T”+j+”.gif”);
j++;
}
i = 0;
}
public void paint(Graphics g)
{
g.drawImage(n[i],1,10,this);
}
public boolean mouseDown(Event e , int x1 ,int y1)
{
i++;
if ( i == 10)
i = 0;
repaint();
return true;
}
}
At first, an array of
10 images is created and n now stands for the array of 10 images. Initializing
the variables individually is tedious, so we use a for statement. i is
initialized to 0 at the start of the loop. The condition in the for statement
evaluates to false when i becomes 10. Thus the value of i increases by 1 each
time control enters the loop. There is no variable called n[i], thus when i is
0 the variable becomes n[0] and when i is 9 the variable becomes n[9].
Another variable
called j is used to change the filenames. When the variable name is n[0] the
gif file will be T1.gif. Therefore, we initialize j to 1 and each time j++ is
encountered, its value is increased by 1. To give the filename, we simply use
the + sign to add the different parts of the name. So when j is 1, the filename
given as “T”+j+”.gif” will become T1.gif. We could have avoided the use of j
and simply used i by initializing it to 1 instead of 0, but that leads to
unnecessarily complicated code. Also remember that array variable names begin
with 0 and the images names start at 1.
The rest of the code remains the same.
In a nutshell, within
the for we have initialized 10 variables to 10 different images and whenever we
click with the mouse, paint is called with a new value in i. When i becomes 10,
it is reinitialized to 0. Thus any code that is repeated can be replaced by a
for statement.
Interface
Let’s get back to the
basics of Java. The first program had public class zzz extends Applet. Extends
brings the existing code from Applet into zzz. zzz is called the derived class and Applet the base class.
In the code given
below we are saying zzz implements runnable. The minute we say implements
runnable and run javac, it comes back with an error saying ‘class zzz must be
declared abstract’.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet implements Runnable
{
public void init()
{
}
}
C:\javaprg>javac zzz.java
zzz.java:3: class zzz must be declared abstract. It does not define void run() from interface java.lang.Runnable.
public class zzz extends Applet implements Runnable
^
1 error
Let’s keep this aside
for the moment and create a new file yyy.java in the same sub directory.
yyy.java
public class yyy implements xxx
{
}
Here we have a class
called yyy and we say implements xxx. Run the program by saying javac yyy.java.
It returns with an error saying that while it doesn’t know what xxx is, it
suspects that xxx must be an interface.
C:\javaprg>javac yyy.java
yyy.java:1: Interface xxx of class yyy not found.
public class yyy implements xxx
^
1 error
So create xxx.java and
write the following code. Don’t put anything between the curly braces.
xxx.java
public interface xxx
{
}
Compile xxx.java. You
won’t see any errors. Now compile yyy.java. Surprisingly this time too you get
no errors. But this does not seem to make things any clearer, so lets go back
to xxx.java.
If you don’t see the
same output while trying out code, you will just have to set the classpath as
follows.
c:\javaprg>set classpath=.;%CLASSPATH%
The compiler looks
into the directories specified in the classpath variable. The classpath tells
the compiler where to look for xxx. If it doesn’t find xxx, it gives an error.
Here, by saying ‘.’ we tell javac to look in the current directory. Classpath
is an environmental variable which informs the java compiler about either the
sub directories within which it should search for .class files or specifies the
full names of the actual .class files.
In xxx.java, add
public void abc(); within curly braces, just as we have done below.
xxx.java
public interface xxx
{
public void abc();
}
Note that function abc
has public void in front of it and followed by a semicolon. This indicates that
we are neither creating a function nor calling a function. Then what is it?
This is a function prototype and we place them in interfaces, and elsewhere as
well. When we compile xxx.java, it won’t show any errors. A function prototype contains
no code whatsoever. Compile xxx.java again.
Now go back to
yyy.java and say javac yyy.java. This results in an error as shown before.
C:\javaprg>javac yyy.java
yyy.java:1: class yyy must be declared abstract. It does not define void abc() from interface xxx.
public class yyy implements xxx
^
1 error
With implements
runnable, the error message was
zzz.java:3: class zzz must be declared abstract. It does not define void run() from interface java.lang.Runnable.
An interface only contains
function prototypes. When we use extends, we are merging the code of the
extended class with the current class. With implements this does not happen. An
implemented class may have one or a hundred function prototypes. All these
functions must be included in the current class because it implements another
class and if you don’t do so, you will get an error.
xxx has the prototype
of the function abc, so you have to write this function within zzz. You may or
may not put any code in it. When you do so, the error vanishes.
yyy.java
public class yyy implements xxx
{
public void abc()
{
}
}
In the next program,
xxx.java comprises of two function prototypes. The newly introduced function
pqr takes one parameter which is int i. If you don’t give the variable a name
it will give an error. Compile the program and you will not get any errors.
yyy implements xxx
hence pqr is included in yyy. But here the name of the variable can be
different, it doesn’t have to be called i.
xxx.java
public interface xxx
{
public void abc();
public void pqr(int i);
}
yyy.java
public class yyy implements xxx
{
public void pqr(int j)
{
}
public void abc()
{
}
}
An interface must
always be implemented and is thus different from a class. A class has function
code whereas interfaces contain only function prototypes. Any class
implementing an interface must have the code for the function whose prototype
is specified in the interface. This is to guarantee that code is present for
the interfaced functions within a class. When you extend a class you get stuff
for free but when you use implements you have to write code yourself. If a
person is an engineer, we know exactly what his capabilities are and he knows exactly what to do.
Similarly, when you implement from a class it knows exactly what it has to do.
An interface is like a
contract. Hence if Runnable as an interface has a 100 functions then we would
have to write the code for all the 100 functions. If we do not, then the java
compiler will give us errors.
Constructors
Make sure that your
program matches the following where the class zzz calls new xxx(). Also create
a public class called xxx in xxx.java
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
new xxx();
}
}
xxx.java
public class xxx
{
}
Compile both, first
obviously xxx and then zzz. You won’t see any errors. At times, you don’t need
to compile both the Java files. If you have the Java file then the compiler
automatically compiles xxx.java if it is present in the current directory; but
it is advisable to compile both.
Now add a function
name xxx to the class xxx as we have done below. Run the applet and nothing
spectacular will happen. However, when you close the window, “In const” is
displayed in the DOS box.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
new xxx();
}
}
xxx.java
public class xxx
{
xxx()
{
System.out.println(“In const”);
}
}
The appletviewer calls
init in zzz and executes new xxx( ). To execute this statement, it first loads
xxx.class and checks for a function with the same name as the name of the
class, in this case xxx. Since there is a function by that name, Java executes
this function. So we see ‘In const’ on the screen.
A constructor is a
function whose name is the same as the name of the class. You can’t call a
constructor; it is called when an instance of the class is created with the new
command. If you try to call the constructor directly, you will get an error.
Now rewrite the
constructor as int xxx().
xxx.java
public class xxx
{
int xxx()
{
System.out.println(“In const”);
return 1;
}
}
C:\javaprg>javac xxx.java
xxx.java:6: ‘return’ with value from constructor: xxx()
return 1;
^
1 error
The program will now
give an error because constructors can’t return values. Ask yourself, when is
the constructor called? The constructor is called at the time the object is
being created. In our case it is called when we say new xxx. If the constructor
is to return a value then to whom should it return the value? The object after
all has not yet been created. As such constructors cannot return values.
Now within zzz.java,
say new xxx(100), as we have done below. Don’t make any changes to xxx.java as
yet.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
new xxx(100);
}
}
xxx.java
public class xxx
{
xxx()
{
System.out.println(“In const “+h);
}
}
C:\javaprg>javac zzz.java
zzz.java:7: Wrong number of arguments in constructor.
new xxx(100);
^
1 error
The constructor in
class xxx takes no parameters. Hence we get an error. The only way to eliminate
the error is by saying xxx(int h) i.e. we are creating a constructor with one
parameter. We display the value of h by concatenating it with “In const “.
xxx.java
public class xxx
{
xxx(int h)
{
System.out.println(“In const “+h);
}
}
C:\javaprg>appletviewer a.html
In const 100
Now go back to your
program and say new xxx(); you will get an error.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
new xxx();
}
}
xxx.java
public class xxx
{
xxx(int h)
{
System.out.println(“In const “+h);
}
}
C:\javaprg>javac zzz.java
zzz.java:7: No constructor matching xxx() found in class xxx.
new xxx();
^
1 error
Bet you didn’t expect
this error! Earlier when you had new xxx() without the constructor, there was
no error triggered. In the second example, you added the constructor and the
constructor was called. Now however, when you say new xxx(), and within the
class xxx you have a constructor with one parameter, you get an error. The rule
is that if you have no constructors then you will receive one for free, the
compiler within the xxx class will actually write xxx() { } for you. But if you
have even one constructor then the free one is taken away. In order to remove
the error you will now need two constructors. This is shown in the following
program.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
new xxx();
}
}
xxx.java
public class xxx
{
xxx()
{
}
xxx(int h)
{
}
}
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
xxx x;
System.out.println(“No”);
x=new xxx();
}
}
xxx.java
public class xxx
{
xxx()
{
System.out.println(“In constructor”);
}
}
Output
No
In constructor
In this program, we
have an object x that looks like xxx. At this point, the constructor is not
being called. System.out.println displays ‘No’. Now we have x=new xxx(); This
is the point where the constructor is called. It is only when we say new that
the object is created. And only when the object is created is the constructor
called.
Constructors cannot be
called directly. In the following program we try to call the constructor by
saying x.xxx(); This will give us an
error.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
xxx x;
System.out.println(“No”);
x=new xxx();
x.xxx();
}
}
xxx.java
public class xxx
{
xxx()
{
System.out.println(“In constructor”);
}
}
It says that Method
xxx() is not found in class xxx. Thus you cannot explicitly call a constructor.
The next program
introduces threads. Here we have included Thread(this).
zzz.java
import java.applet.*;
public class zzz extends Applet
{
Thread t;
public void init()
{
t = new Thread(this);
}
}
t is a variable that
looks like Thread. new Thread (this) will create an object that looks like
Thread and saves it in t. To create the object, the constructor with one
parameter in the Thread class is called. This constructor is being passed one
parameter called ‘this’. ‘this’ in this case stands for zzz or Applet.
This program is
similar to the earlier ones. On compiling, we get an error.
C:\javaprg>javac zzz.java
zzz.java:7: Incompatible type for constructor. Explicit cast needed to convert zzz to java.lang.Runnable.
t = new Thread(this);
^
1 error
The thread constructor
requires Runnable as a parameter. ‘this’ in our program represented zzz or
Applet, hence the error. The only option left is to extend the class from
Applet and to implement Runnable.
zzz.java
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Thread t;
public void init()
{
t = new Thread(this);
}
}
C:\javaprg>javac zzz.java
zzz.java:2: class zzz must be declared abstract. It does not define void run() from interface java.lang.Runnable.
public class zzz extends Applet implements Runnable
^
1 error
If you stop here you
will get another error. Runnable is an interface and it has one function called
run, which hasn’t been implemented in the class. In the next program, we have added
run and within it we are calling the System.out.println function.
zzz.java
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Thread t;
public void init()
{
t = new Thread(this);
}
public void run()
{
System.out.println(“hi”);
}
}
This program doesn’t
give us any errors but when you run the program nothing happens either!
To call run, we have
to say t.start() where start is a function in Thread. Add this function to your
program. Now when you run the program you will see hi displayed in the dos box.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Thread t;
public void init()
{
t = new Thread(this);
t.start();
}
public void run()
{
System.out.println(“hi”);
}
}
C:\javaprg>appletviewer a.html
hi
Here, the function run
is called only once. If you use a while loop and give the condition as true,
the loop will go on infinitely. This is demonstrated in the following program.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Thread t;
public void init()
{
t = new Thread(this);
t.start();
}
public void run()
{
while ( true )
{
System.out.println(“hi”);
}
}
}
This also confirms
that ‘start’ in the Thread class calls run().
You have used a class
called Thread in your program but what is a Thread? The following program will
make this concept much clearer.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Thread t; int i = 0;Button b;
public void init()
{
t = new Thread(this);
t.start();
b = new Button(“No”);
add(b);
}
public void paint(Graphics g)
{
g.drawString(“hi “ + i,1,20);
}
public void run()
{
while ( true )
{
i++;
repaint();
}
}
public boolean mouseDown(Event e , int x , int y)
{
b.reshape(x,y,80,50);
return true;
}
}
Let’s walk through
this code and examine how it works.
A thread called t is
created; t.start will call run. run contains an infinite while loop which
increments the value of i. The loop contains the repaint function and therefore
the paint function will be called. In paint, drawString will display the value
of i. Now that we have understood one part of the program, let’s move onto the
other.
Then we have b that
looks like Button. We create this object by saying new Button (“no”); nothing
happens here because we have simply created an object that looks like a button
and given it a parameter ‘no’. The add function is a part of Applet and it
takes one parameter. So when you say add(b), you will see a button with the
label ‘no’.
Each time you click in
the window, mouseDown will be called. This function calls reshape, which is
part of the button class and hence we
can say b.reshape. reshape takes 4 parameters; x,y is the location where the button
will be drawn and the next two parameters, 80 and 50, specify the width and
height of the button. Thus the button obediently follows every click in the
window. Simultaneously, drawString also does its job of displaying the new
value for i.
The crux of the
program is that you can do two things at the same time and this is made
possible by using threads.
Today, any computer in
the world is by far faster than a human being in terms of thinking as well as
work. It is a lot faster than a hard disk or a floppy disk.
Windows is said to be
a multi-tasking operating system. In other words, it can handle multiple jobs
at the same time, allowing you to run more than one program at a time.
Let us assume you are
using Microsoft Word and have given the save command to save a file. If this
file is a 50 megabytes large, Word will take a long time to save it. Assuming
it takes half an hour, what should you do in the meantime? While the file is
being saved, you should be able to run any other program.
To tackle these issues,
every time you run a program under any operating system like Windows or Linux,
the operating system will run it in its own thread. A thread is an abstract
entity; it is code being executed. Let us assume that in one minute i.e. 60
seconds of time, and you have 3 programs or 3 threads running simultaneously
and each is allocated 20 seconds. This is all hypothetical because in real
life, no thread would be given 20 seconds at a stretch. The OS switches between
threads so fast that you won’t notice it at all, nor would you believe that the
same computer is handling 3 different programs at the same time.
Thus when you save a
file in Microsoft Word under MS Windows by clicking on File - Save, Word starts
a new thread. If you have 3 programs running concurrently with the save
command, there will now be 4 threads. Now the time slice will be 15 secs per
minute to every program/thread. So while the thread saves the file, the main
thread in which Word operates too can continue with its work. That is, you can
use word as before.
Our Java program
already operates in a thread. The mouseDown event is captured in this thread.
By creating an object that looks like Thread, a new thread is created which
calls run. run calls paint which displays the values. This is how two jobs can
be done at the same time. The run function is only called once, while the while
loop will run on forever.
In the previous
chapter, we had a program where the image followed the mouseclick. What we did
earlier in mouseDown, we can do in the run function too.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Image n[]; int i = 0;int j = 1;Thread t;
public void init()
{
n = new Image[10];
for ( i = 0; i <= 9 ; i++)
{
n[i] = getImage(getCodeBase(),”T”+j+”.gif”);
j++;
}
i = 0;
t = new Thread(this);
t.start();
}
public void paint(Graphics g)
{
g.drawImage(n[i],1,10,this);
}
public void run()
{
while ( true)
{
i++;
if ( i == 10)
i = 0;
repaint();
}
}
}
The code remains the
same, the only difference being that this time we have put it in the run
function. When you run this program using the appletviewer, the code starts
animating by itself and at great speed. Amazing isn’t it!!!
What we need to do is
slow this down. Let’s see how this can be done.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
abc();
}
public void abc() throws InterruptedException
{
}
}
C:\javaprg>javac zzz.java
zzz.java:6: Exception java.lang.InterruptedException must be caught, or it must be declared in the throws clause of this method.
abc();
^
1 error
Here, init calls the
abc function. The function code has throws Interruped Exception added to it.
Let us assume you
opened a file and the operation returned an error. You then have to check for
the error and write code for error handling. Suppose you are opening files from
20 different places in your program, you’ll have to repeat the same error
handling code 20 times. If you have 6 different types of errors, you will have
to check for all of them. That’s a lot of code!
The second preoblem is
with the constructor. If a constructor has an error, what should the
constructor do? The constructor cannot return an error because, as discussed
earlier, constructors do not return values.
The developers
followed a new approach to error handling. This approach states that if a
function has a problem, it should throw an exception and a handler should catch
it.
The abc function
throws an exception called InterruptedException. This is a exception that comes
with java but you can create your own
exceptions too. An exception is a class derived from Exception. The abc
function throws an exception, hence when you are calling abc you have to catch
it or else you will get an error.
The next program shows
how you how to catch the error.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
try
{
abc();
}
catch (InterruptedException i) {}
catch (Exception i) {}
}
public void abc() throws InterruptedException
{
}
}
At first, we say ‘try’
and within this block we place the function that throws exceptions. At the end
of the block, we use catch along with the type of exception to handle the
exception. So within the {}’s we can put whatever code we want and it will be
executed if that error occurs.
zzz.java
iimport java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
try
{
abc();
System.out.println(“After abc”);
}
catch (InterruptedException i) {System.out.println(“I am Interrupted Exception”);}
catch (Exception i) {System.out.println(“I am Exception”);}
System.out.println(“After Exception”);
}
public void abc() throws InterruptedException
{
throw new InterruptedException();
}
}
Output
I am Interrupted Exception
After Exception
In this program, we
have throw new InterruptedException. throw is a reserved word in Java. It is
only when we use throw new InterruptedException that the exception is called.
Within the try-catch, we call abc. abc throws InterruptedException and thus the
code in catch which deals with InterruptedException is called. So println will
display ‘I am Interrupted Exception’. Once an exception occurs all the
remaining code in the try block is skipped. Thus you will not see ‘After abc’
displayed. After the catch is called, any code after catch will be executed.
Since we have a println statement after catch, it will display ‘After
Exception’.
In try, we can put as
many functions as we want. We can also put as many catches as we like. Here, we
are catching two exceptions, InterruptedException and Exception. So depending
upon the exception that occurs, the relevant code is called.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
try
{
abc();
}
catch (Exception i)
{}
}
public void abc() throws InterruptedException{}
}
All code in the init
function can be placed between the try and catch. We can be generic by having
only one catch with Exception. Exception is the mother of all exceptions. All
other exceptions are extended or derived from it, even InterruptedException.
You decide the level of sophistication you like in your program. A function can
throw as many exceptions as it wants using commas.
Similar to ‘try-catch’
is a throw. This entire exercise was conducted because our pictures were being
displayed too fast. To slow it down, we will now call a function called sleep,
which is part of thread. So we say t.sleep and then give 500, which is the time
in milliseconds.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Image n[]; int i = 0;int j = 1;Thread t;
public void init()
{
n = new Image[10];
for ( i = 0; i <= 9 ; i++)
{
n[i] = getImage(getCodeBase(),”T”+j+”.gif”);
j++;
}
i = 0;
t = new Thread(this);
t.start();
}
public void paint(Graphics g)
{
g.drawImage(n[i],1,10,this);
}
public void run()
{
while ( true)
{
t.sleep(500);
i++;
if ( i == 10)
i = 0;
repaint();
}
}
}
‘sleep’ gives an
error. This is because it throws an exception and we are not catching it.
C:\javaprg>javac zzz.java
zzz.java:26: Exception java.lang.InterruptedException must be caught, or it must
be declared in the throws clause of this method.
t.sleep(500);
^
1 error
Our next program is
the last in this chapter; it is a working example showing animation. Here the
sleep function is put in ‘try-catch’. We have no code for error handling so
we’ll leave it blank.
zzz.java
import java.awt.*;
import java.applet.*;
public class zzz extends Applet implements Runnable
{
Image n[]; int i = 0;int j = 1;Thread t;
public void init()
{
n = new Image[10];
for ( i = 0; i <= 9 ; i++)
{
n[i] = getImage(getCodeBase(),”T”+j+”.gif”);
j++;
}
i = 0;
t = new Thread(this);
t.start();
}
public void paint(Graphics g)
{
g.drawImage(n[i],1,10,this);
}
public void run()
{
while ( true)
{
try
{
t.sleep(500);
}
catch ( Exception e) {}
i++;
if ( i == 10)
i = 0;
repaint();
}
}
}
Conclusion
Thus, from this
chapter it can be concluded that any program that displays animation
necessarily requires the use of threads. We saw how the applet begins the
animation cycle when it is activated and the animation is terminated when the
applet is no longer active. But when you want the applet to provide
functionality beyond animation, then you’ll have to use threads. Often
Animators are built within applets. Therefore, you need an interface. To
accomplish this we implemented the Runnable interface. In the process, we also
learnt how exceptions are handled with the help of the ‘try-catch’ statement.
By now you are also well versed with the concepts of loops, arrays and
constructors.