You are on page 1of 171

.

Basic Java

Basic Java 1
.

Table of Contents

1. Introduction to Java ……………..…………………………………………….3

2. The language package ……………………………………................29

3. The Utilities package ……………………………………….................36

4. The I/O Package ……………………………………………………………….48

5. Applet Programming …………………………………………...............68

6. Multithreading ………………………………………………………………….109

7. Networking in Java …………………………………………………………..120

8. Java Database Connectivity ……………………………………………131

Basic Java 2
.

CHAPTER-1: INTRODUCTION TO JAVA


Java, a Web programming technology, had altered the course of software
development, especially in regard to the Internet. Java sports all features necessary
for extending the Web in ways previously impossible. Java was designed with issues
such as portability and reliability in mind. Because of Java, the entire concept of the
Web and what it can do is being redefined.

Java is a simple, distributed, interpreted, secure, architecturally neutral, portable,


high-performance, multithreaded and dynamic language. But what exactly makes
Java unique is that it is the first programming language that can be used for writing
general-purpose applications, as well as programs designed for the Internet.

Java Buzzwords:

SIMPLICITY

Java was designed to be a powerful language but simple. To support the


development of large software, the concept of package is used. The major difference
was the removal of the direct use of pointers. Java automatically handles
referencing and dereferencing of language objects. Other difference includes the
removal of support for data structures like struct, union. Its in-built classes
provide this. Also, the concepts of operator overloading and multiple-inheritance
in the form of classes have been removed.

OBJECT-ORIENTED NATURE

The notion of object in Java is implemented by its class construct. In fact, it is not
possible to write a Java program that does something meaningful without using the
class construct. Java language comes with very powerful set of pre-defined classes
with a hierarchy level.

DISTRIBUTED NATURE

Java provides the network capabilities by a pre-defined package java.net. This


package has many classes that simplify the network communication. Accessing to
any remote object is also possible in Java via the java.rmi package.

ARCHITECTURALLY NEUTRAL

The Java Compiler does not produce the machine language instructions that make
up the executable Java Program. The Java Compiler DOES NOT generate a .exe
file. Instead the compiler produces an intermediate code called as 'byte code'. Java
byte code is an architecturally neutral representation of the program, that is, it is
independent of any processor type or machine architecture. These byte codes are
read by the Java interpreter and the same is executed using an internal model of an
abstract machine. The Java Interpreter and the implementation of this abstract
machine are called the JAVA VIRTUAL MACHINE.

SECURE LANGUAGE

Before any Java program is interpreted, the Java runtime system performs a byte-
code verification to ensure that the program is not violating the system integrity. Also,

Basic Java 3
.
programs loaded from the net are loaded in a separate name space than the local
classes. This prevents any other program to affect the system classes.

MULTITHREADED LANGUAGE

Java supports multitasking in the form of multithreading within itself.

First Java Application

HelloWorld Application

public class HelloWorld


{
public static void main(String args[])
{
System.out.println("Hello World!!");
}
}

Create the file

Save this into a file called HelloWorld.java using any text editor. It is very important to
call the file HelloWorld.java, because the compiler expects the file name to match the
class identifier.

Compile the code

Type

Prompt> javac HelloWorld.java

at a command prompt.

The javac program creates a file called HelloWorld.class from the HelloWorld.java
file. Inside this file (HelloWorld.class) is text known as bytecodes which can be run by
the Java interpreter.

Run the program


Now that you have compiled the program, you can run it by typing at the command
prompt:

Promtpt> java HelloWorld

The input to the interpreter is nothing but the name of the class that has the main
method.

After you do this, the computer should print to the screen

Hello World!!

Understanding HelloWorld

Declaring a class

The first task when creating any Java program is to create a class. Look at the first
line of the HelloWorld application:

Basic Java 4
.

public class HelloWorld {

This declares a class called HelloWorld.

To create any class, simply write a line that looks like:

public class ClassName

Here, ClassName is the name of the program you are writing. In addition,
ClassName must correspond to the file name. Next, notice the little curly brace ({)
that is located after the class declaration. If you look at the end of the class, there is
also a closing brace (}). The braces tell the compiler where your class will begin and
end. Any code between those two braces is considered to be in the HelloWorld class.

public static void main(String args[]){

This line declares what is known as the main method. Methods are essentially mini-
programs. Each method performs some of the tasks of a complete program. The
main method is the most important one with respect to applications, because it is the
place that all Java applications start. For instance, when you run java HelloWorld, the
Java interpreter starts at the first line of the main method.

Writing to the Screen

The text Hello World!! appears on the screen through

System.out.println("Hello World!!");

You can replace any of the text within the quotation marks ("") with any text that you
would like.
The System.out line is run because, when the application starts up, the interpreter
looks at the first line of code (namely the printout) and executes it. If you place any
other code there, it runs that code instead.

The System.out.println serves approximately the same purpose as the writeln in


Pascal. In C, the function is printf, and in C++, cout.

println Versus print

There is one minor variation on println which is also readily used: print("Hello
World!!"). The difference between println and print is that print does not add a
carriage return at the end of the line, so any subsequent printouts are on the same
line.

Access Specifiers :

The first option for a method is the access specifier. Access specifiers are used to
restrict access to the method. Regardless of what the access specifier is, though, the
method is accessible from any other method in the same class.

public
The public modifier is the most relaxed modifier possible for a method. By specifying
a method as public it becomes accessible to all classes regardless of their lineage or
their package. In other words, a public method is not restricted in any way.

Basic Java 5
.

protected
The second possible access modifier is protected. Protected methods can be
accessed by any class within the current package, but are inaccessible to any class
outside the package.

default
The next access modifier that can be applied to a class is that of default. Default
methods are accessible only to the current class and any classes that extend from it.
If you fail to specify an access modifier, the method is considered default.

private
private is the highest degree of protection that can be applied to a method. A private
method is only accessible by those methods in the same class. Even classes that
extend from the current class do not have access to a private class.

Method Modifiers

Method modifiers enable you to set properties for the method, such as where it will
be visible and how subclasses of the current class will interact with it.

static
Placing the static modifier in front of a method or variable declaration makes it
common to all object references of that class. While non-static methods can also
operate with static variables, static methods can only deal with static variables and
static methods.

abstract
Abstract methods are simply methods that are declared, but are not implemented in
the current class. The responsibility of defining the body of the method is left to
subclasses of the current class.

final
By placing the keyword final in front of the method declaration, you prevent any
subclasses of the current class from overriding the given method. This ability
enhances the degree of insulation of your classes, you can ensure that the
functionality defined in this method will never be altered in any way.

Note:
Neither static methods nor class constructors can be declared to be abstract.
Furthermore, you should not make abstract methods final, because doing so
prevents you from overriding the method.

native
Native methods are methods that you want to use, but do not want to write in Java.
Native methods are most commonly written in C++, and can provide several benefits
such as faster execution time. Like abstract methods, they are declared simply by
placing the modifier native in front of the method declaration and by substituting a
semicolon for the method body.

synchronized
By placing the keyword synchronized in front of a method declaration, you can
prevent data corruption that may result when two methods attempt to access the
same piece of data at the same time. While this may not be a concern for simple

Basic Java 6
.
programs, once you begin to use threads in your programs, this may become a
serious problem.

Modified HelloWorld

In the above HelloWorld program, the print method was called inside the same class.
The following example creates a separate PrintWorld object that has a print method
and any other class can invoke this method to print the necessary result.

class PrintWorld
{
String data_member;
public PrintWorld(String line)
{
data_member = new String(line);
}
public void printMe()
{
System.out.println(data_member);
}
}

public class ObjectWorld


{
public static void main(String args[])
{
PrintWorld p_world = new PrintWorld("Hello World");
p_world.printMe();
}
}

In the above program,

PrintWorld p_world = new PrintWorld("Hello World");

is used to construct the class PrintWorld. Quite simply, the line tells the compiler to
allocate memory for an instance of the class and points variable to the new section of
memory. In the process of doing this, the compiler also calls the class's constructor
method and passes the appropriate parameters to it

p_world is the object to the class PrintWorld. This class has a data member,
data_member and a method printMe().

In the construction phase of the class, the argument of the constructor is assigned to
the data member. And later when the printMe() method is called, this data member
value is retrieved and printed.

Getting information from the user with System.in

System.out has a convenient partner called System.in. While System.out is used to


print information to the screen, System.in is used to get information into the program.

Requesting input from the user

Let's use System.in.read() to get a character from the user.

Basic Java 7
.
ReadHello.java

public class ReadHello


{
public static void main (String args[]
{
int inChar =’0’;
System.out.println("Enter a Character:");
try
{
inChar = System.in.read();
System.out.println("You entered " + inChar);
}
catch (IOException e)
{
System.out.println("Error reading from user");
}
}
}

You've probably already noticed that there is a lot more to this code than there was
to the last one. Let’s first compile the program.

Enter a Character:
A
You entered 65

The code we are most interested in is the line, which reads:

inChar = System.in.read();

System.in.read() is a method that takes a look at the character that the user enters. It
then performs what is known as a return on the value. A value that is returned by a
method is then able to be used in an expression. In the case of ReadHello, a variable
called inChar is set to the value which is returned by the System.in.read() method.

In the next line, the value of the inChar variable is added to the System.out string. By
adding the variable into the string, you can see the results of your work. It's not
actually necessary to use a variable. If you prefer, you can print it out directly in the
second System.out line, by changing it to

System.out.println("You entered "+ System.in.read());

Now, notice that the program displays a number instead of a character for what you
entered. This is because the read() method of System.in returns an integer, not an
actual character. The number corresponds to what is known as the ASCII character
set.

Converting integer to character

To convert the number that is returned from System.in into a character, you need to
do what is known as a cast. Casting effectively converts a given data type to another
one.

Basic Java 8
.
---
inChar =(char) System.in.read();
---
Notice the characters before System.in.read().The (char) causes the integer to be
changed into a character.

The Rest of the Extra Code—try, catch

In this code, there is a sequence there called a try-catch block.


In some programming languages, when a problem occurs during execution, there is
no way for you as a programmer to catch it and deal with the problem. In some
languages, it's a bit complicated. In Java, most problems cause what are known as
Exceptions.

When a method states that it will throw an exception, it is your responsibility to only
try to perform that method, and if it throws the exception, you need to catch it. See
the line of code right after the catch phase. If there is an error while reading, an
exception called an IOException is thrown. When that happens, the code in the catch
block is called.

JAVA LANGUAGE FUNDAMENTALS

KEYWORDS

The following is a list of the 56 keywords you can use in Java.

abstract boolean Break Byte


case cast Catch Char
class const Continue Default
do double Else Extends
final finally Float for
future generic Goto if
implements import Inner instanceof
int interface Long native
new null Operator outer
package private Protected public
rest return Short static
super switch Synchronized this
throw throws Transient try
var void Volatile while

EXTENDING OBJECTS THROUGH INHERITANCE

Inheritance is a feature of OOP programming that enables us inherit all the common
features of a parent class onto a child class, it's not necessary to reinvent the object
every time. When new classes inherit the properties of another class, they are
referred to as child classes or subclasses. The class from which they are derived is
then called a parent or super class.

A Simple Inheritance Program

class BaseClass
{
public BaseClass()

Basic Java 9
.
{
System.out.println("Base Class Constructor Called");
}
}

/*
DerivedClass extends or inherits the property
of the BaseClass
*/
class DerivedClass extends BaseClass
{
public DerivedClass()
{
System.out.println("Derived Class Constructed");
}
}

public class Inheritance


{
public static void main(String args[])
{
BaseClass base = new BaseClass();
System.out.println("------------");
DerivedClass derived = new DerivedClass();
}
}

The output is:

Base Class Constructor Called


------------
Base Class Constructor Called
Derived class Constructed

By looking at the output, you can find that, when the child class is constructed, the
parent class constructor is invoked first.

INTERFACES

Interfaces are Java's substitute for C++'s feature of multiple inheritance, the practice
of allowing a class to have several super classes. While it is often desirable to have a
class inherit several sets of properties, for several reasons the creators of Java
decided not to allow multiple inheritance. Java classes, however, can implement
several interfaces, thereby enabling you to create classes that build upon other
objects without the problems created by multiple inheritance.

The syntax for creating an interface is extremely similar to that for creating a class.
However, there are a few exceptions. The most significant difference is that none of
the methods in your interface may have a body.

An Interface Example

public interface Product


{
public int getPrice(int id);

Basic Java 10
.
}

public class Shoe implements Product


{
public int getPrice(int id)
{
if (id == 1)
return(5);
else
return(10);
}

public class Store


{
public static void main(String argv[])
{
Shoe some = new Shoe();
int x = Some.getPrice(3);
System.out.println(“the price : “+x);
}
}

The Declaration

Interface declarations have the syntax

public interface NameofInterface

Public Interfaces
By default, interfaces may be implemented by all classes in the same package. But if
you make your interface public, you allow classes and objects outside of the given
package to implement it as well.

The rules for an interface name are identical to those for classes.

Extending Other Interfaces

In keeping with the OOP practice of inheritance, Java interfaces may also extend
other interfaces as a means of building larger interfaces upon previously developed
code.

e.g public interface NameOfInterface extends AnotherInterface

Interfaces cannot extend classes. There are a number of reasons for this, but
probably the easiest to understand is that any class, which the interface would be
extending would have its method bodies defined. This violates the "prime directive" of
interfaces.

The Interface Body

Basic Java 11
.
The main purposes of interfaces are to declare abstract methods that will be defined
in other classes. As a result, if you are dealing with a class that implements an
interface, you can be assured that these methods will be defined in the class. While
this process is not overly complicated, there is one important difference that should
be noticed. An interface method consists of only a declaration.

Methods in Interface

Method declarations in interfaces have the following syntax:

public return_value nameofmethod (parameters);

Note that unlike normal method declarations in classes, declarations in interfaces are
immediately followed by a semicolon.

All methods in interfaces are public by default, regardless of the presence or absence
of the public modifier. This is in contrast to class methods which default to friendly.

It's actually illegal to use any of the other standard method modifiers (including
native, static, synchronized, final, private, protected, or private protected) when
declaring a method in an interface.

Variables in Interfaces

Although interfaces are generally employed to provide abstract implementation of


methods, you may also define variables within them. Because you cannot place any
code within the bodies of the methods, all variables declared in an interface must be
global to the class. Furthermore, regardless of the modifiers used when declaring the
field, all fields declared in an interface are always public, final, and static.

While all fields will be created as public, final, and static, you do not need to explicitly
state this in the field declaration. All fields default to public, static and final regardless
of the presence of these modifiers.

It is, however, a good practice to explicitly define all fields in interfaces as public,
final, and static to remind yourself (and other programmers) of this fact.

Implementing an interface.

In order to fulfill the requirements of implementing the Product interface, the class
must override the getPrice(int) method.

Overriding Methods

Declaring a method in an interface is a good practice. However, the method cannot


be used until a class implements the interface and overrides the given method.

ENCAPSULATION

Another benefit of enclosing data and methods in classes is the OOP characteristic
of encapsulation—the ability to isolate and insulate information effectively from the
rest of your program.

POLYMORPHISM

Basic Java 12
.
Finally, the allure of the OOP approach to creating self-sustaining modules is further
enhanced by the fact that children of a given class are still considered to be of the
same "type" as the parent. This feature, called polymorphism, enables you to perform
the same operation on different types of classes as long as they share a common
trait. While the behavior of each class might be different, you know that the class will
be able to perform the same operation as its parent because it is of the same family
tree

Example of Function Overload

class Sample {
public Sample() {
System.out.println("Sample Constructor Called"); }
public void overloadMe() {
System.out.println("Overload Method Invoked"); }
public void overloadMe(String str) {
System.out.println(str);
}
}

public class Overload {


public static void main(String args[]) {
Sample samp = new Sample();
System.out.println("-------------");
samp.overloadMe();
System.out.println("-------------");
samp.overloadMe("Hi! I am not the old one");
}
}

Output:

Sample Constructor Called


-------------
Overload Method Invoked
-------------
Hi! I am not the old one

Here, though the method overloadMe is the same, it throws different ouput based on
its invocation. This is termed as method overloading.

JAVA DATA TYPES

Java has Two Types of Data Types


In Java, there are really two different categories in which data types have been
divided:

Primitive types
Reference types

Reference types enclose things such as arrays, classes, and interfaces.

Java has eight primitive types, each with its own purpose and use:

Basic Java 13
.
Type Description
• boolean - These have values of either true or false.

• byte - 8-bit 2s-compliment integer with values between -128 to 127

• short - 16-bit 2s-compliment integer with values between -2^15 and 2^15-1 (-
32,768 to 32,767)

• char 16-bit Unicode characters. For alpha-numerics, these are the same as
ASCII with the high byte set to 0. The numerical values are unsigned 16-bit
values are between 0 and 65535.

• int 32-bit 2s-compliment integer with values between -231 and 231-1 (-
2,147,483,648 to 2,147,483,647)

• long 64-bit 2s-compliment integer with values between -263 and 263-1 (-
9223372036854775808 to 9223372036854775807)

• float 32-bit single precision floating point numbers using the IEEE 754-1985
standard (+/- about 1039)

• double 64-bit double precision floating point numbers using the IEEE 754-1985
standard. (+/- about 10317)

VARIABLES

You can create any variable in Java in the same way as was just shown:

• State the data type that you will be using

• State the name the variable will be called

• Assign the variable a value

• As with every other line of code in Java, terminate the line with a semicolon

example:
int number = 0;
boolean value = false;

Identifiers—The Naming of a Variable

There are several rules that must be obeyed when creating an identifier:

The first character of an identifier must be a letter. After that, all subsequent
characters can be letters or numerals. The underscore (_) and the dollar sign ($) may
be used as any character in an identifier, including the first one. Identifiers are case-
sensitive and language-sensitive.

Examples of Legal Identifiers

HelloWorld

Basic Java 14
.
counter
HotJava$
ioc_Queue3

Examples of Illegal Identifiers

9HelloWorld
count&add
Hot Java
65536

OPERATORS

Operators are used to change the value of a particular object. They are described
here in several related categories.

UNARY LOGICAL OPERATORS

Description Operator
Increment ++
Decrement --
Negation -
Bitwise complement ~

Example for Increment and Decrement Operators


class IncDec {
public static void main (String args[]) {
int x = 8, y = 13;
System.out.println(“x = “ + x);
System.out.println(“y = “ + y);
System.out.println(“++x = “ + ++x);
System.out.println(“y++ = “ + y++);
System.out.println(“x = “ + x);
System.out.println(“y = “ + y);
}
}
Output
x=8
y = 13
++x = 9
y++ = 13
x=9
y = 14

Example for negation operator

class Negation {
public static void main (String args[]) {
int x = 8;
System.out.println(“x = “ + x);
int y = -x;
System.out.println(“y = “ + y);

Basic Java 15
.
}

Basic Java 16
.
Example for Bitwise complement operator
class BitwiseComplement {
public static void main (String args[]) {
int x = 8;
System.out.println(“x = “ + x);
int y = ~x;
System.out.println(“y = “ + y);
}
}

ARITHMETIC OPERATORS
Arithmetic operators act on pairs of integers.

Description Operator
Addition +
Subtraction -
Multiplication *
Division /
Modulus %
Bitwise AND &
Bitwise OR |
Bitwise XOR ^
Left Shift <<
Right Shift >>
Zero-Fill Right Shift >>>

Shift Operators

The left-shift, right-shift, and zero-fill-right-shift operators (<<, >>, and >>>) shift the
individual bits of an integer by a specified integer amount. The following are some
examples of how these operators are used:

x << 3;
y >> 7;
z >>> 2;

Example for Shift Operators

class Shift {
public static void main (String args[]) {
int x = 7;
System.out.println(“x = “ + x);
System.out.println(“x >> 2 = “ + (x >> 2));
System.out.println(“x << 1 = “ + (x << 1));
System.out.println(“x >>> 1 = “ + (x >>> 1));
}
}

The output of Shift follows:


x=7
x >> 2 = 1
x << 1 = 14

Basic Java 17
.
x >>> 1 = 3

Relational Operators
The last group of integer operators is the relational operators, which all operate on
integers but return a type boolean.

Description Operator
Less Than <
Greater Than >
Less Than Or Equal To <=
Greater Than Or Equal To >=
Equal To ==
Not Equal To !=

ASSIGNMENT OPERATORS

The simplest assignment operator is the standard assignment operator. This operator
is often known as the gets operator, because the value on the left gets the value on
the right.

= assignment operator

The arithmetic assignment operators provide a shortcut for assigning a value. When
the previous value of a variable is a factor in determining the value that you want to
assign, the arithmetic assignment operators are often more efficient:

Description Operator
Simple =
Addition +=
Subtraction -=
Multiplication *=
Division /=
Modulus %=
AND &=
OR |=
XOR ^=

BOOLEAN OPERATORS
Boolean operators act on Boolean types and return a Boolean result. The Boolean
operators are listed

Description Operator
Evaluation AND &
Evaluation OR |
Evaluation XOR ^
Logical AND &&
Logical OR D="I228" NAME="I228"> ||

Basic Java 18
.
Negation !
Equal To ==
Not Equal To !=
Conditional ?:

CONDITIONAL OPERATOR

It takes the following form:

expression1 ? expression2 : expression3

In this syntax, expression1 must produce a Boolean value. If this value is true, then
expression2 is evaluated, and its result is the value of the conditional. If expression1
is false, then expression3 is evaluated, and its result is the value of the conditional.

Example for Conditional Operator


class Conditional {
public static void main (String args[]) {
int x = 0;
boolean isEven = false;
System.out.println(“x = “ + x);
x = isEven ? 4 : 7;
System.out.println(“x = “ + x);
}
}

The results of the Conditional program follow:


x=0

x=7

CONTROL FLOW

Control flow is the heart of any program. Control flow is the ability to adjust (control)
the way that a program progresses (flows). By adjusting the direction that a computer
takes, the programs that you build become dynamic. Without control flow, programs
would not be able to do anything more than several sequential operations.

IF STATEMENTS

if (expression)
if_statement;
else
else_statement;

ITERATION STATEMENTS

Programmers use iteration statements to control sequences of statements that are


repeated according to runtime conditions.

Basic Java 19
.

Java supports five types of iteration statements:

while
do
for
continue
break

WHILE STATEMENTS

while (expression)
statement;

DO WHILE LOOP

do
statement;
while (expression)

FOR LOOP

for (initialization, expression , step )


statement;

SWITCH STATEMENTS

switch (expression){

case V1: statement1;


break;

case V2: statement2;


break;
default: statementD;
}

BREAK STATEMENTS

The sub-statement blocks of loops and switch statements can be broken out of by
using the break statement.

RETURN STATEMENTS

A return statement passes control to the caller of the method, constructor, or static
initializer containing the return statement. If the return statement is in a method that is
not declared void, it may have a parameter of the same type as the method.

ARRAYS

An array is simply a way to have several items in a row. If you have data that can be
easily indexed, arrays are the perfect means to represent them.

Basic Java 20
.
int IQ[] = {123,109,156,142,131};
The next line shows an example of accessing the IQ of the third individual:

int ThirdPerson = IQ[3];


Arrays in Java are somewhat tricky. This is mostly because, unlike most other
languages, there are really three steps to filling out an array, rather than one:

There are two ways to do this: place a pair of brackets after the variable type, or
place brackets after the identifier name.

int MyIntArray[];
int[] MyIntArray;

Examples of declaring arrays.

long Primes[] = new long[1000000]; // declare an array and assign


// some memory to hold it.

long[] EvenPrimes = new long[1]; // Either way, it's an array.


EvenPrimes[0] = 2; // populate the array.

There are several additional points about arrays you need to know:

Indexing of arrays starts with 0. In other words, the first element of an array is
MyArray[0], not MyArray[1].

COMMENTS

Java supports three styles of comments:

Traditional
C++ style
javadoc

Traditional Comments

A traditional comment is a C-style comment that begins with a slash-star (/*) and
ends with a star-slash (*/).

C++ Style Comments

The second style of comment begins with a slash-slash (//) and ends when the
current source code line ends. These comments are especially useful for describing
the intended meaning of the current line of code.

javadoc Comments

The final style of comment in Java is a special case of the first. It has the properties
mentioned previously, but the contents of the comment may be used in automatically
generated documentation by the javadoc tool. javadoc comments are opened with
/**, and they are closed with */. By using these comments in an appropriate manner,
you will be able to use JavaDoc to automatically create documentation pages

Basic Java 21
.
LITERALS

There are several different types of literal. In fact, there are five major types of literal,
in the Java language:

Boolean
Character
Floating-point
Integer
String
Integer Literal

Example

int j=0;
long GrainOfSandOnTheBeachNum=1L;
short Mask1=0x007f;
String FirstName = "Ernest";
char TibetanNine = '\u1049'
boolean UniverseWillExpandForever = true;

ESCAPE CHARACTERS

Escape Literal Meaning


'\b' \u0008 backspace
'\t' \u0009 horizontal tab
'\n' \u000a linefeed
'\f' \u000c form feed
'\r' \u000d carriage return
'\"' \u0022 double quote
'\'' \u0027 single quote
'\\' \u005c backslash

Don't use the \u format to express an end-of-line character. Use the \n or \r


characters instead.

ERROR-HANDLING CLASSES

Runtime error handling is a very important facility in any programming environment.


Java provides the following classes for dealing with runtime errors:
• Throwable
• Exception
• Error
The Throwable class provides low-level error-handling capabilities such as an
execution stack list. The Exception class is derived from Throwable and provides the
base level of functionality for all the exception classes defined in the Java system.
The Exception class is used for handling normal errors. The Error class is also
derived from Throwable, but it is used for handling abnormal errors that aren’t
expected to occur. Very few Java programs worry with the Error class; most use the
Exception class to handle runtime errors.

Basic Java 22
.
Example for Exception Handling

public class ExceptionHandling {


public static void main(String args[]) {
int values[] = {5,6,3,5,2};
int index = 6;
try {
int get = values[index];
System.out.println("The value in the requested index
is " +get);
} catch(Exception err) {
System.out.println("Requested Index Not found");
}
finally {
System.out.println("--------End---------");
}
}
}

In the above example, the array size is 5, but we are trying to access the 6th element.
As this is a runtime error, an exception is caught and the catch block is executed.

Use of finally clause

Suppose there is some action that you absolutely must do, no matter what happens.
Usually, this is to free some external resource after acquiring it, to close a file after
opening it, or something similar. In exception handling, the finally block is executed
no matter whether an exception is thrown or not.

Output:
Requested Index Not found
--------End---------

THE THROWABLE CLASS

The Throwable class is the superclass of all errors and exceptions in the Java
language. Only objects that are instances of this class (or of one of its subclasses)
are thrown by the Java Virtual Machine or can be thrown by the Java throw
statement. Similarly, only this class or one of its subclasses can be the argument
type in a catch clause. A Throwable class contains a snapshot of the execution stack
of its thread at the time it was created. It can also contain a message string that gives
more information about the error.

THE EXCEPTION CLASS

The class Exception and its subclasses are a form of Throwable that indicates
conditions that a reasonable application might want to catch.

EXAMPLE FOR MULTIPLE EXCEPTION HANDLING

public class MultipleExceptions {


public static void main(String args[]) {

Basic Java 23
.

int values[] = {5,6,2,3,5};


int index;
char input = (char)-1;
String data = "";

System.out.println("Enter an index value");

try {
do {
input = (char)System.in.read();
data = data + input;
}while(input!='\n');
}
catch(Exception err) {
System.out.println("Unable to obtain system input");
}

try {
index = Integer.parseInt(data.trim());

System.out.println("The value in the requested index :


"+values[index]);
}
catch(NumberFormatException err) {
System.out.println("Invalid Index");
}
catch(ArrayIndexOutOfBoundsException err) {
System.out.println("Requested Index Not Found");
}
finally {
System.out.println("--------End---------");
}
}
}
In the above program, there is a pre-defined array of length 5. The user input is got
as a String. It is then parsed into an int data type. The value in the array for this index
is given as ouput.
Here, the exceptions may be thrown

• While getting an input


• While trying to convert the input to an int data type
• While trying to access that index in the array

The exception classes for the last two exceptions are NumberFormatException and
ArrayIndexOutOfBoundsException respectively. So the try block encapsulating the
parsing of the input and searching of the index has two catch blocks to handle these
exceptions in their own different way.

If input is not an integer, then output is

Invalid Index
--------End---------

Basic Java 24
.
If input is an integer, but index is out of range in the array, then output is

Requested Index Not Found


--------End---------

Note that in both the cases, the finally block is executed.

Packages:

Java provides a mechanism for partitioning the classname into more manageable
chunks. This mechanism is the package. The package is both a naming and a
visibility comttrol mechanism. Classes can be defined inside a package that are not
accessible by code outside the package. Class members can also be defined that
are only exposed to other members of the same package. This is achieved with the
help of package and access protection.
Access Protection:

Java provides many levels of protection to allow fine-grained control over the
visibility of the variables and methods within classes, subclasses and packages.
Packages add another dimension to access control.

Classes and packages are both means of encapsulating and containing the
namespace and scope of variables and methods. Packages act as containers for
classes and other subordinate packages. Classes act as containers for data and
code. The class is Java’s smallest unit of abstraction.

Java addresses four categories of visibility for class members.

1. Sub classes in the same package


2. Non Subclasses in the same package
3. Subclasses in different packages
4. Classes are neither in the same package nor subclasses

The three access specifiers, private, public and protected provide a variety of ways
to produce tha many levels of access required by these categories.
public - Anything declared public can be accessed from anywhere
private – Anything declared private cannot be seen outsideof its class.

default – When a member doesnot have an access specification, it is visible to


subclasses as well as other classes in the same package.

protected – If an element has to be seen outside the current package but only to
classes that subclass your class directly.

Defining Package:

Creating a package in Java is quite easy. This is achieved by simply including a


package command as the first statement in a Java Source file. Any classes that are
declared with in that file belong to the specified package. The package statement
defines a namepsace in which classes are stored. If you omit the package statement,
the classes are put into the default package that has no name.

Basic Java 25
.
Syntax for package statement:

package mypackage;

Use package keyword as the first line in the file.

E.g. package com.first

The classes under this package are in com/first namespace.


The classes under this package must be stored inside the com/first folder
Use import keyword for using the classes in different package.

Example for Package mechanism:

package com.first.one;

public class BaseClass


{
int x=6; // default access
private int x_pri=2; // private access
protected int x_pro=3; //protected access
public int x_pub=4; //public access

public BaseClass()
{
System.out.println("Inside Constructor of Base Class"); }
public void display()
{
System.out.println("Value of x(default) is "+x);
System.out.println("Value of x(private) is
"+x_pri);
System.out.println("Value of x(protected) is
"+x_pro);
System.out.println("Value of x(public) is "+x_pub);

}
}

package com.first.one;

class Derived extends BaseClass


{
Derived()
{
System.out.println("Inside Derived Class
Constrcutor\n");
System.out.println("Value of x(default) is "+x);
// Not available to derived class also because it is
private (Class only)
// System.out.println("Value of x(private) is
"+x_pri);
System.out.println("Value of x(protected) is
"+x_pro);

Basic Java 26
.
System.out.println("Value of x(public) is "+x_pub);
}
public static void main(String arg[])
{
Derived deri=new Derived();
}
}

package com.first.one;

public class TestBaseClass


{
public TestBaseClass()
{
System.out.println("Inside TestBaseClass
constructor");
BaseClass bc1=new BaseClass();
System.out.println("Value of x(default) is
"+bc1.x);
// Not accessible because private - access is for Class
only
// System.out.println("Value of x(private) is
"+bc1.x_pri);
System.out.println("Value of x(protected) is
"+bc1.x_pro);
System.out.println("Value of x(public) is
"+bc1.x_pub);
}
public static void main(String arg[])
{
BaseClass bc=new BaseClass();
bc.display();
System.out.println("\n****************TestBaseClass*
**************\n");
TestBaseClass test=new TestBaseClass();
}
}

package com.first.two;

import com.first.one.BaseClass;

class BaseClassNew extends BaseClass


{
BaseClassNew()
{
System.out.println("Constrcutor of Base class in
another package");
//Not accessible because it is default - for package
only
//System.out.println("Value of x(default) is"+x);
// Not accessible becuase it is private - for Class
only
//System.out.println("Value of x(private) is
"+x_pri);

Basic Java 27
.
System.out.println("Value of x(protected) is
"+x_pro);
System.out.println("Value of x(public) is "+x_pub);

public static void main(String arg[])


{
BaseClassNew bcn=new BaseClassNew();
}
}

package com.first.two;

import com.first.one.*;

public class SomeClass


{
SomeClass()
{
System.out.println("Inside Constructor of
SomeClass");
BaseClass bc=new BaseClass();
// Only for package
//System.out.println("Value of x(default) is
"+bc.x);
// Only for Class
//System.out.println("Value of x(private) is
"+bc.x_pri);
// Only for Class, subClass & package
//System.out.println("Value of x(protected) is
"+bc.x_pro);
System.out.println("Value of x(public) is
"+bc.x_pub);
}

public static void main(String arg[])


{
SomeClass sc=new SomeClass();
}
}

Basic Java 28
.

Basic Java 29
.
CHAPTER-2: THE LANGUAGE PACKAGE – java.lang

The Java language package, which is also known as java.lang, provides classes that
make up the core of the Java language. The language package contains classes at
the lowest level of the Java class libraries. For example, the Object class, which all
classes are derived from, is located in the language package.
It’s impossible to write a Java program without dealing with at least a few of the
elements of the language package. The most important classes contained in the
language package follow:

• The Object Class


• Data Type Wrapper Classes
• The Math Class
• String Classes
• System and Runtime Classes
• Thread Classes
• Class Classes
• Exception Handling Classes
• Process Classes

THE OBJECT CLASS

The Object class is the super class for all classes in Java. Because all classes are
derived from Object, the methods defined in Object are shared by all classes. These
results in a core set of methods that all Java classes are guaranteed to support.
Object includes methods for making copies of an object, testing objects for equality,
and converting the value of an object to a string.

DATA TYPE WRAPPER CLASSES


The fundamental data types (int, char, float, and so on) in Java are not implemented
as classes. Many times it is useful, however, to know more information about a
fundamental types than just its value. By implementing class wrappers for the
fundamental types, additional information can be maintained, as well as methods
defined that act on the types. The data type wrapper classes serve as class versions
of the fundamental data types, and are named similarly to the types they wrap. For
example, the type wrapper for int is the Integer class. Following are the Java data
type wrapper classes:

• Boolean
• Character
• Double
• Float
• Integer
• Long
• Number

Type wrappers are also useful because many of Java’s utility classes require classes
as parameters, not simple types. Type wrappers and simple types are not
interchangeable.

Basic Java 30
.
THE MATH CLASS

The Math class serves as a grouping of mathematical functions and constants. It is


interesting to note that all the variables and methods in Math are static, and the Math
class itself is final. This means you can’t derive new classes from Math. Additionally,
you can’t instantiate the Math class. It’s best to think of the Math class as just a
conglomeration of methods and constants for performing mathematical
computations.
The Math class includes the E and PI constants, methods for determining the
absolute value of a number, methods for calculating trigonometric functions, and
minimum and maximum methods, among others.

EXAMPLE FOR MATH CLASS

public class MathExample


{
public static void main(String args[]) {
char temp = (char)-1;
String input = "";
Double data = null;

System.out.println("Enter any number");

/** Gets the user input**/

try {
do {
temp = (char)System.in.read();
input = input + temp;
}while(temp != '\n');
data = new Double(input);
}
catch(Exception err)
{
System.out.println("Exception ...");
System.exit(0);
}

double d_data = data.doubleValue();

System.out.println("Printing Math values......");


System.out.println("Sin : " + (Math.sin(d_data)));
System.out.println("Cos : " + (Math.cos(d_data)));
System.out.println("Tan : " + (Math.tan(d_data)));
System.out.println("asin : " + (Math.asin(d_data)));
System.out.println("acos : " + (Math.acos(d_data)));
System.out.println("atan : " + (Math.atan(d_data)));
System.out.println("Abs : " + (Math.abs(d_data)));
System.out.println("Exp : " + (Math.exp(d_data)));
System.out.println("Log : " + (Math.log(d_data)));
System.out.println("Sqrt : " + (Math.sqrt(d_data)));
System.out.println("Ceil : " + (Math.ceil(d_data)));
System.out.println("Floor : " + (Math.floor(d_data)));
System.out.println("rint : " + (Math.rint(d_data)));

Basic Java 31
.
System.out.println("round : " + (Math.round(d_data)));
System.out.println("Random Number : " + (Math.random()));
}
}

STRING CLASSES
For various reasons (mostly security related), Java implements text strings as
classes, rather than forcing the programmer to use character arrays. The two Java
classes that represent strings are String and StringBuffer. The String class is useful
for working with constant strings that can’t change in value or length. The
StringBuffer class is used to work with strings of varying value and length.

THE STRING CLASS

The String class represents character strings. All string literal in Java programs, such
as "abc", are implemented as instances of this class. Strings are constant; their
values cannot be changed after they are created. String buffers support mutable
strings. Because String objects are immutable they can be shared. For example:

String str = "abc";

is equivalent to:

char data[] = {'a', 'b', 'c'};


String str = new String(data);

Here are some more examples of how strings can be used:

System.out.println("abc");
String cde = "cde";
System.out.println("abc" + cde);
String c = "abc".substring(2,3);
The class String includes methods for examining individual characters of the
sequence, for comparing strings, for searching strings, for extracting substrings, and
for creating a copy of a string with all characters translated to uppercase or to
lowercase. The Java language provides special support for the string concatenation
operator ( + ), and for conversion of other objects to strings. String concatenation is
implemented through the StringBuffer class and its append method. String
conversions are implemented through the method toString(), defined by Object and
inherited by all classes in Java.

EXAMPLE FOR STRING CLASS

public class StringExample {


public static void main(String args[]) {

String str = new String("Java World");


int length = str.length();
System.out.println("Length of data : "+length);
System.out.println("Extracting character...");
for(int index=0;index<length;index++)
{
char temp = str.charAt(index);
System.out.println(temp);

Basic Java 32
.
}

System.out.println("Substring from 3rd position : "


+(str.substring(3)));
System.out.println("Substring from 3rd to 5th position :
" +(str.substring(3,6)));
System.out.println("Index of Wor : " +
(str.indexOf("Wor")));
System.out.println("Converting to Upper Case : " +
(str.toUpperCase()));
System.out.println("Replacing 'a' with '*' : " +
(str.replace('a','*')));
System.out.println("--------End-------");
}
}

THE STRINGBUFFER CLASS

A string buffer implements a mutable sequence of characters. String buffers are safe
for use by multiple threads. The methods are synchronized where necessary so that
all the operations on any particular instance behave as if they occur in some serial
order.
String buffers are used by the compiler to implement the binary string concatenation
operator +. For example, the code:

x = "a" + 4 + "c"

is compiled to the equivalent of:

x = new StringBuffer().append("a").append(4).append("c").toString()

The principal operations on a StringBuffer are the append and insert methods, which
are overloaded so as to accept data of any type. Each effectively converts a given
datum to a string and then appends or inserts the characters of that string to the
string buffer. The append method always adds these characters at the end of the
buffer; the insert method adds the characters at a specified point.
For example, if z refers to a string buffer object whose current contents are "start",
then the method call z.append("le") would cause the string buffer to contain "startle",
whereas z.insert(4, "le") would alter the string buffer to contain "starlet".
Every string buffer has a capacity. As long as the length of the character sequence
contained in the string buffer does not exceed the capacity, it is not necessary to
allocate a new internal buffer array. If the internal buffer overflows, it is automatically
made larger.

EXAMPLE FOR STRINGBUFFER

public class SBExample


{
public static void main(String args[])
{

String s = new String("Hello");


/** Constructors

Basic Java 33
.
1. Empty Constructor will create with initial capacity of
16 characters.
2. Constructor with specified characters as the initial
capacity
3. Constructor with specified string as the initial value
*/
StringBuffer sb1 = new StringBuffer();
StringBuffer sb2 = new StringBuffer(40);
StringBuffer sb3 = new StringBuffer(s);

//Appending a boolean value

sb1.append(true);
System.out.println("Value of StringBuffer = " + sb1);

//Appending a character
sb1.append('c');
System.out.println("Value of StringBuffer = " + sb1);

//Appending a character array


char c[] = {'H','e','l','l','o'};
sb1.append(c);

System.out.println("Value of StringBuffer = " + sb1);


sb1.append(c,2,3);

System.out.println("Value of StringBuffer = " + sb1);


double d = 12.141354;
sb1.append(d);

System.out.println("Value of StringBuffer = " + sb1);


float f = (float)15.1;
sb1.append(f);

System.out.println("Value of StringBuffer = " + sb1);


int i = 1;
sb1.append(i);
System.out.println("Value of StringBuffer = " + sb1);
long l = 1000000;
sb1.append(l);
System.out.println("Value of StringBuffer = " + sb1);
sb1.append(s);
System.out.println("Value of StringBuffer = " + sb1);
System.out.println("Capacity = " + sb2.capacity());
System.out.println("Character at 5th position = " +
sb1.charAt(5));
sb1.getChars(0,4,c,0);
System.out.println("Chars extracted from Sb1 = " + c);

//Insert the boolean value at the 5th position


sb1.insert(5,true);

//Insert the character value at the 9th position


sb1.insert(9,'M');

Basic Java 34
.
System.out.println("Length of the string buffer = " +
sb1.length());
sb1.reverse();
System.out.println("Reverse of the String Buffer = " +
sb1);
sb1.setCharAt(5, 'Y');
System.out.println("Value of String Buffer = " + sb1);
}
}

THE SYSTEM AND RUNTIME CLASSES


The System and Runtime classes provide a means for your programs to access
system and runtime environment resources. Like the Math class, the System class is
final and is entirely composed of static variables and methods. The System class
basically provides a system-independent programming interface to system
resources. Examples of system resources include the standard input and output
streams, System.in and System.out, which typically model the keyboard and monitor.

The Runtime class provides direct access to the runtime environment. An example of
a run-time routine is the freeMemory method, which returns the amount of free
system memory available.

EXAMPLE FOR RUNTIME

public class RuntimeExample


{
public static void main(String args[])
{
try
{
Runtime run = Runtime.getRuntime();
run.exec("notepad.exe");
}
catch(Exception err)
{
System.out.println("Exception " +err.getMessage());
}
}
}

THREAD CLASSES

Java is a multithreaded environment and provides various classes for managing and
working with threads. Following are the classes and interfaces used in conjunction
with multithreaded programs:
• Thread
• ThreadDeath
• ThreadGroup
• Runnable
The Thread class is used to create a thread of execution in a program. The
ThreadDeath class is used to clean up after a thread has finished execution. As its
name implies, the ThreadGroup class is useful for organizing a group of threads.

Basic Java 35
.
Finally, the Runnable interface provides an alternate means of creating a thread
without subclassing the Thread class.

CLASS CLASSES

Java provides two classes for working with classes: Class and ClassLoader. The
Class class provides runtime information for a class, such as the name, type, and
parent superclass. Class is useful for querying a class for runtime information, such
as the class name. The ClassLoader class provides a means to load classes into the
runtime environment. ClassLoader is useful for loading classes from a file or for
loading distributed classes across a network connection.

Example to print the class name of an object:

void printClassName(Object obj) {


System.out.println("The class of " + obj + " is " + obj.getClass().getName());
}

Basic Java 36
.
CHAPTER- 3: THE UTILITIES PACKAGE – java.util

The Java utilities, package, which is also known as java.util, provides various
classes that perform different utility functions. The utilities package includes a
class for working with dates, a set of data structure classes, a class for
generating random numbers, and a string tokenizer class, among others. The
most important classes contained in the utilities package follow:

• The Date Class


• Data Structure Classes
• The Random Class
• The StringTokenizer Class
• The Properties Class
• The Observer Interface
• The Enumeration Interface

THE DATE CLASS

The Date class represents a calendar date and time in a system-independent


fashion. The Date class provides methods for retrieving the current date and
time as well as computing days of the week and month.

EXAMPLE FOR DATE CLASS


import java.util.Date;
public class DateExample { public static void main(String
args[]) {
String days[] =
{"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
Date sys_date = new Date();
Date date = new Date(101,8,3);

System.out.println("System Date : " +


(sys_date.toString()));
System.out.println("Specified Date : " +
(date.toString()));

int day = date.getDay();System.out.println("The day for


the specified date : " +
days[day]);System.out.println("Does the specified date
precede the system date ?
");System.out.println(date.before(sys_date));
}}

THE CALENDAR CLASS

Calendar is an abstract base class for converting between a Date object and a set of
integer fields such as YEAR, MONTH, DAY, HOUR, and so on. (A Date object
represents a specific instant in time with millisecond precision. See java.util.Date for
information about the Date class.)

Basic Java 37
.
Subclasses of Calendar interpret a Date according to the rules of a specific calendar
system. The JDK provides one concrete subclass of Calendar: GregorianCalendar.
Future subclasses could represent the various types of lunar calendars in use in
many parts of the world.
Like other locale-sensitive classes, Calendar provides a class method, getInstance,
for getting a generally useful object of this type. Calendar's getInstance method
returns a GregorianCalendar object whose time fields have been initialized with the
current date and time:

EXAMPLE FOR CALENDAR CLASS

import java.util.Calendar;

public class CalendarExample


{
public static void main(String args[])
{

Calendar calendar = Calendar.getInstance();


int date = calendar.get(Calendar.DATE);
int month = calendar.get(Calendar.MONTH);
int year = calendar.get(Calendar.YEAR);

System.out.println("Date : " + date + "/" + (month+1) +


"/" +year);

calendar.add(Calendar.DATE,50);

date = calendar.get(Calendar.DATE);
month = calendar.get(Calendar.MONTH);
year = calendar.get(Calendar.YEAR);

System.out.println("Latest date : " + date + "/" +


(month+1) + "/" +year);
}
}

Data Structure Classes


The Java data structure classes and interfaces implement popular data structures for
storing data. The data structure classes and interfaces are as follows:
• Dictionary
• Hashtable
• Vector
• Stack
• Enumeration
• Random

THE RANDOM CLASS


Many programs, especially programs that model the real world, require some
degree of randomness. Java provides randomness by way of the Random
class. The Random class implements a random-number generator by

Basic Java 38
.
providing a stream of pseudo-random numbers. A slot machine program is a
good example of one that would make use of the Random class.

EXAMPLE FOR RANDOM CLASS

import java.util.*;
public class RandomExample {
public static void main(String args[]) {
Random random = new Random();

System.out.println("Random number(int):" +
(random.nextInt()));

System.out.println("Random number(float): " +


(random.nextFloat()));

System.out.println("Random number(double): "


+(random.nextDouble()));

System.out.println("Random number(gaussian): "


+(random.nextGaussian()));

Date date = new Date();

Random seed_random = new Random(date.getTime());

System.out.println("Random number with seed(int): "


+(seed_random.nextInt()));

System.out.println("Random number with seed(float): "


+(seed_random.nextFloat()));

System.out.println("Random number with seed(double): " +


(seed_random.nextDouble()));

System.out.println("Random number with seed(gaussian) : "


+(seed_random.nextGaussian()));

}
}

THE STRINGTOKENIZER CLASS


The StringTokenizer class provides a means of converting text strings into individual
tokens. By specifying a set of delimiters, you can parse text strings into tokens using
the StringTokenizer class. String tokenization is useful in a wide variety of programs,
from compilers to text-based adventure games.

public class StringTokenizer extends Object implements Enumeration

The string tokenizer class allows an application to break a string into tokens. The
tokenization method is much simpler than the one used by the StreamTokenizer
class. The StringTokenizer methods do not distinguish among identifiers, numbers,
and quoted strings, nor do they recognize and skip comments. The set of delimiters

Basic Java 39
.
(the characters that separate tokens) may be specified either at creation time or on a
per-token basis. An instance of StringTokenizer behaves in one of two ways,
depending on whether it was created with the returnTokens flag having the value true
or false:

• If the flag is false, delimiter characters serve to separate tokens. A token is a


maximal sequence of consecutive characters that are not delimiters.
• If the flag is true, delimiter characters are considered to be tokens. A token is
either one delimiter character, or a maximal sequence of consecutive
characters that are not delimiters.

The following is one example of the use of the tokenizer. The code:

StringTokenizer st = new StringTokenizer("this is a test");


while (st.hasMoreTokens()) {
println(st.nextToken());
}

prints the following output:

this
is
a
test

EXAMPLE FOR STRINGTOKENIZER

import java.util.StringTokenizer;

public class TokenizerExample {


public static void main(String args[]) {
char temp = (char)-1;

String input = "";

System.out.println("Enter a string ");

try
{

do
{
temp = (char)System.in.read();
input = input + temp;
}while(temp != '\n');

}
catch(Exception err){}

input = input.trim();
System.out.println("Printing tokens...");
StringTokenizer tokenizer = new StringTokenizer(input);
System.out.println("Number of tokens :
"+(tokenizer.countTokens()));

Basic Java 40
.

while(tokenizer.hasMoreTokens())
{
System.out.println(tokenizer.nextToken());
}
}
}

THE HASHTABLE CLASS

This class implements a hashtable, which maps keys to values. Any non-null object
can be used as a key or as a value. To successfully store and retrieve objects from a
hashtable, the objects used as keys must implement the hashCode method and the
equals method. An instance of Hashtable has two parameters that affect its
efficiency: its capacity and its load factor. The load factor should be between 0.0 and
1.0. When the number of entries in the hashtable exceeds the product of the load
factor and the current capacity, the capacity is increased by calling the rehash
method. Larger load factors use memory more efficiently, at the expense of larger
expected time per lookup. If many entries are to be made into a Hashtable, creating it
with a sufficiently large capacity may allow the entries to be inserted more efficiently
than letting it perform automatic rehashing as needed to grow the table. This
example creates a hashtable of numbers. It uses the names of the numbers as keys:

Hashtable numbers = new Hashtable();


numbers.put("one", new Integer(1));
numbers.put("two", new Integer(2));
numbers.put("three", new Integer(3));

To retrieve a number, use the following code:

Integer n = (Integer)numbers.get("two");
if (n != null) {
System.out.println("two = " + n);
}

EXAMPLE FOR HASHTABLE CLASS

import java.util.*;

public class HashtableExample {


public static void main(String args[]) {
Hashtable hash = new Hashtable();
String days[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};

for(int index=0;index<days.length;index++)
{
Integer pos = new Integer(index);
hash.put(pos,days[index]);
}

Date date = new Date();


int day = date.getDay();

Basic Java 41
.
Integer pos = new Integer(day);
System.out.println("Day : " + (hash.get(pos).toString()));
}
}

THE STACK CLASS

The Stack class represents a last-in-first-out (LIFO) stack of objects.

EXAMPLE FOR STACK CLASS

import java.util.*;

public class StackExample {


public static void main(String args[]) {
Stack stack = new Stack();

Date date = new Date();


StringTokenizer tokenizer = new
StringTokenizer(date.toString());
System.out.println("tokens : "+tokenizer.countTokens());
while (tokenizer.hasMoreTokens())
{
stack.push(tokenizer.nextToken());
}

Object obj = stack.peek();

System.out.println("First element in stack - by peek : " +


(obj.toString()));

System.out.println("Pop out the elements in stack ");

while(!stack.empty())
{
obj = stack.pop();
System.out.println(obj.toString());
}
}
}

THE VECTOR CLASS

The Vector class implements a growable array of objects. Like an array, it contains
components that can be accessed using an integer index. However, the size of a
Vector can grow or shrink as needed to accommodate adding and removing items
after the Vector has been created.

Each vector tries to optimize storage management by maintaining a capacity and a


capacityIncrement. The capacity is always at least as large as the vector size; it is
usually larger because as components are added to the vector, the vector's storage
increases in chunks the size of capacityIncrement. An application can increase the
capacity of a vector before inserting a large number of components; this reduces the
amount of incremental reallocation.

Basic Java 42
.
EXAMPLE FOR VECTOR CLASS

import java.util.*;

public class VectorExample {

public static void main(String args[]) {


Vector store = new Vector();
String input = "";
char temp = (char)-1;
System.out.println("Enter a string ");
try {
do {
temp = (char)System.in.read();
input = input+temp;
}while(temp != '\n');
input = input.trim();
}catch(Exception err){}
StringTokenizer tokenizer = new StringTokenizer(input);
while(tokenizer.hasMoreTokens()) {
store.addElement(tokenizer.nextToken());
}
System.out.println("Size of the Vector : "+store.size());

System.out.println("Capacity of the Vector :


"+store.capacity());

System.out.println("First Element : "+store.firstElement());

System.out.println("Last Element : "+store.lastElement());

Enumeration enum = store.elements();

while(enum.hasMoreElements())
{

System.out.println(enum.nextElement().toString());
}

store.trimToSize();

System.out.println("Capacity of the vector after trimming : "


+ (store.capacity()));

}
}

Basic Java 43
.
The Collections Framework
The collections framework is a unified architecture for representing and manipulating
collections, allowing them to be manipulated independently of the details of their
representation. It reduces programming effort while increasing performance. It allows
for interoperability among unrelated APIs, reduces effort in designing and learning
new APIs, and fosters software reuse. The framework is based on six collection
interfaces. It includes implementations of these interfaces, and algorithms to
manipulate them.
Introduction
The 1.2 release of the Java platform includes a new collections framework. A
collection is an object that represents a group of objects. A collections framework is a
unified architecture for representing and manipulating collections, allowing them to be
manipulated independently of the details of their representation.
The primary advantages of a collections framework are that it:

• Reduces programming effort by providing useful data structures and


algorithms so you don't have to write them yourself.

• Increases performance by providing high-performance implementations of


useful data structures and algorithms. Because the various implementations
of each interface are interchangeable, programs can be easily tuned by
switching implementations.

• Provides interoperability between unrelated APIs by establishing a


common language to pass collections back and forth.

• Reduces the effort required to learn APIs by eliminating the need to learn
multiple ad hoc collection APIs.

• Reduces the effort required to design and implement APIs by eliminating


the need to produce ad hoc collections APIs.

• Fosters software reuse by providing a standard interface for collections and


algorithms to manipulate them.

The collections framework consists of:

• Collection Interfaces - Represent different types of collections, such as sets,


lists and maps. These interfaces form the basis of the framework.

• General-purpose Implementations - Primary implementations of the


collection interfaces.

• Legacy Implementations - The collection classes from earlier releases,


Vector and Hashtable, have been retrofitted to implement the collection
interfaces.

• Wrapper Implementations - Add functionality, such as synchronization, to


other implementations.

• Convenience Implementations - High-performance "mini-implementations"


of the collection interfaces.

• Abstract Implementations - Partial implementations of the collection


interfaces to facilitate custom implementations.

Basic Java 44
.
• Algorithms - Static methods that perform useful functions on collections,
such as sorting a list.

• Infrastructure - Interfaces that provide essential support for the collection


interfaces.

• Array Utilities - Utility functions for arrays of primitives and reference objects.
Not, strictly speaking, a part of the Collections Framework, this functionality is
being added to the Java platform at the same time and relies on some of the
same infrastructure.

Collection Interfaces

There are six collection interfaces. The most basic interface is Collection. Three
interfaces extend Collection: Set, List, and SortedSet. The other two collection
interfaces, Map and SortedMap, do not extend Collection, as they represent
mappings rather than true collections. However, these interfaces contain collection-
view operations, which allow them to be manipulated as collections.

Collection
The Collection interface is the root of the collection hierarchy. A
Collection represents a group of objects, known as its elements. Some
Collection implementations allow duplicate elements and others do
not. Some are ordered and others unordered. The JDK doesn't
provide any direct implementations of this interface: It provides
implementations of more specific subinterfaces like Set and List. This
interface is the least common denominator that all collections
implement. Collection is used to pass collections around and
manipulate them when maximum generality is desired.
Set
A Set is a collection that cannot contain duplicate elements. As you
might expect, this interface models the mathematical set abstraction. It
is used to represent sets like the cards comprising a poker hand, the

Basic Java 45
.
courses making up a student's schedule, or the processes running on
a machine.
List
A List is an ordered collection (sometimes called a sequence). Lists
can contain duplicate elements. The user of a List generally has
precise control over where in the List each element is inserted. The
user can access elements by their integer index (position). If you've
used Vector, you're already familiar with the general flavor of List.
Map
A Map is an object that maps keys to values. Maps cannot contain
duplicate keys: Each key can map to at most one value. If you've used
Hashtable, you're already familiar with the general flavor of Map.

The last two core collection interfaces (SortedSet and SortedMap) are merely sorted
versions of Set and Map
Object Ordering
There are two ways to order objects: The Comparable interface
provides automatic natural order on classes that implement it, while
the Comparator interface gives the programmer complete control over
object ordering. Note that these are not core collection interfaces, but
underlying infrastructure.

The last two core collection interfaces:


SortedSet
A SortedSet is a Set that maintains its elements in ascending order.
Several additional operations are provided to take advantage of the
ordering. The SortedSet interface is used for things like word lists and
membership rolls.
SortedMap
A SortedMap is a Map that maintains its mappings in ascending key
order. It is the Map analogue of SortedSet. The SortedMap interface is
used for apps like dictionaries and telephone directories.

All of the modification methods in the collection interfaces are labeled optional. Some
implementations may not perform one or more of these operations, throwing a
runtime exception (UnsupportedOperationException) if they are attempted.
Implementations must specify in their documentation which optional operations they
support. Several terms are introduced to aid in this specification:

• Collections that do not support any modification operations (such as add,


remove and clear) are referred to as unmodifiable. Collections that are not
unmodifiable are referred to modifiable.

• Collections that additionally guarantee that no change in the Collection object


will ever be visible are referred to as immutable. Collections that are not
immutable are referred to as mutable.

• Lists that guarantee that their size remains constant even though the
elements may change are referred to as fixed-size. Lists that are not fixed-
size are referred to as variable-size.

Basic Java 46
.
Some implementations may restrict what elements (or in the case of Maps, keys and
values) may be stored. Possible restrictions include requiring elements to:

• Be of a particular type.

• Be non-null.

• Obey some arbitrary predicate.

Attempting to add an element that violates an implementation's restrictions results in


a runtime exception, typically a ClassCastException, an IllegalArgumentException or
a NullPointerException. Attempting to remove or test for the presence of an element
that violates an implementation's restrictions may result in an exception, though
some "restricted collections" may permit this usage.

Collection Implementations

Class that implement the collection interfaces typically have names of the form
<Implementation-style><Interface>. The general-purpose implementations are
summarized in the table below:

Implementations
Hash Table Resizable Array Balanced Tree Linked List
Set HashSet TreeSet
Interfaces List ArrayList LinkedList
Map HashMap TreeMap
The general-purpose implementations support all of the optional operations in the
collection interfaces, and have no restrictions on the elements they may contain.

The AbstractCollection, AbstractSet, AbstractList, AbstractSequentialList and


AbstractMap classes provide skeletal implementations of the core collection
interfaces, to minimize the effort required to implement them. The API documentation
for these classes describes precisely how each method is implemented so the
implementer knows which methods should be overridden, given the performance of
the "basic operations" of a specific implementation.

Design Goals
The main design goal was to produce an API that was reasonably small, both in size,
and, more importantly, in "conceptual weight." It was critical that the new functionality
not seem alien to current Java programmers; it had to augment current facilities,
rather than replacing them. At the same time, the new API had to be powerful
enough to provide all the advantages described above.

To keep the number of core interfaces small, the interfaces do not attempt to capture
such subtle distinctions as mutability, modifiability, resizability. Instead, certain calls
in the core interfaces are optional, allowing implementations to throw an
UnsupportedOperationException to indicate that they do not support a specified
optional operation. Of course, collection implementers must clearly document which
optional operations are supported by an implementation.

To keep the number of methods in each core interface small, an interface contains a
method only if either:

Basic Java 47
.
1. It is a truly fundamental operation: a basic operations in terms of which others
could be reasonably defined,

2. There is a compelling performance reason why an important implementation


would want to override it.

It was critical that all reasonable representations of collections interoperate well. This
included arrays, which cannot be made to implement the Collection interface directly
without changing the language. Thus, the framework includes methods to allow
collections to be dumped into arrays, arrays to be viewed as collections, and maps to
be viewed as collections.

Basic Java 48
.
CHAPTER – 4 :THE I/O PACKAGE - java.io

The Java I/O package, also known as java.io, provides classes with support for
reading and writing data to and from different input and output devices, including
files. The I/O package includes classes for inputting streams of data, outputting
streams of data, working with files, and tokenizing streams of data. The most
important classes contained in the I/O package follows:

• Input Stream Classes


• Output Stream Classes
• File Classes
• The StreamTokenizer Class

FILE CLASSES

Files are the most widely used method of data storage in computer systems. Java
supports files with two different classes: File and RandomAccessFile. The File class
provides an abstraction for files that takes into account system-dependent features.
The File class keeps up with information about a file including the location where it is
stored and how it can be accessed. The File class has no methods for reading and
writing data to and from a file; it is only useful for querying and modifying the
attributes of a file. In actuality, you can think of the File class data as representing a
filename, and the class methods as representing operating system commands that
act on filenames.

The RandomAccessFile class provides a variety of methods for reading and writing
data to and from a file. RandomAccessFile contains many different methods for
reading and writing different types of information, namely the data type wrappers.

THE FILE CLASS

Instances of this class represent the name of a file or directory on the host file
system. A file is specified by a pathname, which can either be an absolute pathname
or a pathname relative to the current working directory. The pathname must follow
the naming conventions of the host platform.

The File class is intended to provide an abstraction that deals with most of the
machine dependent complexities of files and pathnames in a machine-independent
fashion.
Note that whenever a filename or path is used it is assumed that the host's file
naming conventions are used.

Example for File

import java.io.*;
import java.util.Date;

public class FileExample


{
public static void main(String args[])
{

Basic Java 49
.
if(args.length == 0)
{
System.out.println("Usage : java FileExample
<filename>");
System.exit(0);
}
String filename = args[0];
try
{
File file = new File(filename);
System.out.println("File Exists : "+file.exists());

Date date = new Date(file.lastModified());


System.out.println("Last Modified : "+date.toString());
System.out.println("Absolute Path :
"+file.getAbsolutePath());
System.out.println("Length of file : "+file.length());
System.out.println("Parent : "+file.getParent());
}
catch(Exception err)
{
System.out.println("Exception in accessing file");
}
}
}

THE RANDOMACCESSFILE CLASS

Instances of this class support both reading and writing to a random access file. An
application can modify the position in the file at which the next read or write occurs.
This class provides a sense of security by offering methods that allow specified mode
accesses of read-only or read-write to files.

Example for RandomAccessFile

import java.io.*;
public class RandomAccessExample {
public static void main(String args[]) {
if(args.length != 2) {
System.out.println("Usage : ");
System.out.println("java RandomAccessExample <sourcefile>
<destfile>");
System.exit(0);
}
String sourcefile = args[0];
String destinfile = args[1];
String data = "";

try
{
File srcfile = new File(sourcefile);
File destfile = new File(destinfile);
RandomAccessFile srcrdm = new RandomAccessFile(srcfile,"r");
RandomAccessFile dstrdm =new RandomAccessFile(destfile,"rw");

Basic Java 50
.

System.out.println("The size of the file "+srcrdm.length());


System.out.println("The file pointer is at
"+srcrdm.getFilePointer());
data = srcrdm.readLine();
while(!data.equals(""))
{
dstrdm.writeBytes(data);
data = srcrdm.readLine();
}
System.out.println("File successfully copied");
System.out.println("Open the destination file to view the
result");
} catch(Exception err) {
}
}}

INPUT STREAM CLASSES

Java uses input streams to handle reading data from an input source. An input
source can be a file, a string, memory, or anything else that contains data. The input
stream classes follow:

• InputStream
• BufferedInputStream
• ByteArrayInputStream
• DataInputStream
• FileInputStream
• FilterInputStream
• LineNumberInputStream
• PipedInputStream
• PushbackInputStream
• SequenceInputStream
• StringBufferInputStream

The InputStream class is an abstract class that serves as the base class for all input
streams. The InputStream class defines an interface for reading streamed bytes of
data, finding out the number of bytes available for reading, and moving the stream
position pointer, among other things. All the other input streams provide support for
reading data from different types of input devices.

OUTPUT STREAM CLASSES


Output streams are the counterpart to input streams and handle writing data to an
output source. Similar to input sources, output sources include files, strings, memory,
and anything else that can contain data. The output stream classes defined in java.io
follow:

• OutputStream
• BufferedOutputStream
• ByteArrayOutputStream
• DataOutputStream

Basic Java 51
.
• FileOutputStream
• FilterOutputStream
• PipedOutputStream
• PrintStream

The OutputStream class is an abstract class that serves as the base class for all
output streams. OutputStream defines an interface for writing streamed bytes of data
to an output source. All the other output streams provide support for writing data to
different output devices. Data written by an output stream is formatted to be read by
an input stream.

THE BUFFEREDINPUTSTREAM CLASS

The class implements a buffered input stream. By setting up such an input stream,
an application can read bytes from a stream without necessarily causing a call to the
underlying system for each byte read. The data is read by blocks into a buffer;
subsequent reads can access the data directly from the buffer.

Example for BufferedInputStream

import java.io.*;
class BufferedExample {
public static void main (String args[]) {
BufferedInputStream in = new
BufferedInputStream(System.in);
byte buf[] = new byte[10];
try {
in.read(buf, 0, 10);
}
catch (Exception e) {
System.out.println(“Error: “ + e.toString()); }
String s = new String(buf, 0); System.out.println(s);
} }

THE BUFFEREDOUTPUTSTREAM CLASS

The class implements a buffered output stream. By setting up such an output stream,
an application can write bytes to the underlying output stream without necessarily
causing a call to the underlying system for each byte written. The data is written into
a buffer, and then written to the underlying stream if the buffer reaches its capacity,
the buffer output stream is closed, or the buffer output stream is explicity flushed.

Example for BufferedOutputStream Class

import java.io.*;
class WriteStuff
{
public static void main (String args[])
{
// Copy the string into a byte array
String s = new String(“Dance, spider!\n”);

byte[] buf = new byte[64];

Basic Java 52
.
s.getBytes(0, s.length(), buf, 0);

// Output the byte array (buffered)


BufferedOutputStream out = new
BufferedOutputStream(System.out); try
{
out.write(buf, 0, 64);
out.flush();
}
catch (Exception e)
{
System.out.println(“Error: “ + e.toString());
}
}
}

THE DATAINPUTSTREAM CLASS

A data input stream lets an application read primitive Java data types from an
underlying input stream in a machine-independent way. An application uses a data
output stream to write data that can later be read by a data input stream.

Data input streams and data output streams represent Unicode strings in a format
that is a slight modification of UTF-8.

All characters in the range '\u0001' to '\u007F' are represented by a single byte:
0bits 0-7

The null character '\u0000' and characters in the range '\u0080' to '\u07FF' are
represented by a pair of bytes:

110bits 6-1010bits 0-5


Characters in the range '\u0800' to '\uFFFF' are represented by three bytes:
1110bits 12-1510bits 6-1110bits 0-5

The two differences between this format and the "standard" UTF-8 format are the
following:

• The null byte '\u0000' is encoded in 2-byte format rather than 1-byte, so that the
encoded strings never have embedded nulls.
• Only the 1-byte, 2-byte, and 3-byte formats are used.

Example for DataInputStream and DataOutputStream

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;

public class DataIOApp


{

Basic Java 53
.
public static void main(String args[]) throws IOException
{
File file = new File("test.txt");
FileOutputStream outFile = new FileOutputStream(file);
DataOutputStream outStream = new DataOutputStream(outFile);
outStream.writeBoolean(true);
outStream.writeInt(123456);
outStream.writeChar('j');
outStream.writeDouble(1234.56);
System.out.println(outStream.size()+" bytes were written");
outStream.close();
outFile.close();
FileInputStream inFile = new FileInputStream(file);
DataInputStream inStream = new DataInputStream(inFile);
System.out.println(inStream.readBoolean());
System.out.println(inStream.readInt());
System.out.println(inStream.readChar());
System.out.println(inStream.readDouble());
inStream.close();
inFile.close();
file.delete();
}
}

THE FILEINPUTSTREAM CLASS

A file input stream is an input stream for reading data from a File or from a
FileDescriptor.

Example for FileInputStream

import java.io.*;
class ReadFile
{
public static void main (String args[])
{
byte buf[] = new byte[64];
try
{
FileInputStream in = new FileInputStream(“Grocery.txt”);
in.read(buf, 0, 64);
}
catch (Exception e)
{
System.out.println(“Error: “ + e.toString());
}
String s = new String(buf, 0);
System.out.println(s);
}}

Basic Java 54
.
THE FILEOUTPUTSTREAM CLASS

A file output stream is an output stream for writing data to a File or to a


FileDescriptor.

Example for FileOutputStream


import java.io.*;
class WriteFile
{
public static void main (String args[])
{
// Read the user input byte buf[] = new byte[64];
try
{
System.in.read(buf, 0, 64);
}
catch (Exception e)
{
System.out.println(“Error: “ + e.toString());
}
// Output the data to a file
try
{
FileOutputStream out = new FileOutputStream(“Output.txt”);
out.write(buf);
}
catch (Exception e)
{
System.out.println(“Error: “ + e.toString());
}
}
}

THE BYTEARRAYINPUTSTREAM CLASS

This class allows an application to create an input stream in which the bytes read are
supplied by the contents of a byte array. Applications can also read bytes from a
string by using a StringBufferInputStream.

Example for Byte Array input/output stream

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ByteArrayIOApp


{
public static void main(String args[]) throws IOException
{
ByteArrayOutputStream outStream = new
ByteArrayOutputStream();
String s = "This is a test.";
for(int i=0;i<s.length();++i)
outStream.write(s.charAt(i));
System.out.println("outstream: "+outStream);

Basic Java 55
.
System.out.println("size: "+outStream.size());
ByteArrayInputStream inStream;
inStream = new
ByteArrayInputStream(outStream.toByteArray());
int inBytes = inStream.available();
System.out.println("inStream has "+inBytes+" available
bytes");
byte inBuf[] = new byte[inBytes];
int bytesRead = inStream.read(inBuf,0,inBytes);
System.out.println(bytesRead+" bytes were read");
System.out.println("They are: "+new String(inBuf));
}
}

THE BYTEARRAYOUTPUTSTREAM CLASS

This class implements an output stream in which the data is written into a byte array.
The buffer automatically grows as data is written to it. The data can be retrieved
using toByteArray() and toString().

THE CHARARRAYREADER CLASS

This class implements a character buffer that can be used as a character-input


stream.

Example for CharArrayReader and Writer

import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.IOException;

public class CharArrayIOApp


{
public static void main(String args[]) throws IOException
{
CharArrayWriter outStream = new CharArrayWriter();
String s = "This is a test.";
for(int i=0;i<s.length();++i)
outStream.write(s.charAt(i));
System.out.println("outstream: "+outStream);
System.out.println("size: "+outStream.size());
CharArrayReader inStream;
inStream = new CharArrayReader(outStream.toCharArray());
int ch=0;
StringBuffer sb = new StringBuffer("");
while((ch = inStream.read()) != -1)
sb.append((char) ch);
s = sb.toString();
System.out.println(s.length()+" characters were read");
System.out.println("They are: "+s);
}
}

Basic Java 56
.
THE LINENUMBERREADER CLASS

A buffered character-input stream that keeps track of line numbers. A line is


considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or
a carriage return followed immediately by a linefeed.

Example for LineNumberReader

import java.io.LineNumberReader;
import java.io.FileReader;
import java.io.BufferedWriter;
import java.io.IOException;

public class LineNumberIOApp


{
public static void main(String args[]) throws IOException
{
FileReader inFile = new FileReader("LineNumberIOApp.java");
LineNumberReader inLines = new LineNumberReader(inFile);
String inputLine;
while ((inputLine=inLines.readLine()) != null) {
System.out.println(inLines.getLineNumber()+". "+inputLine);
}
}
}

THE PUSHBACKINPUTSTREAM CLASS

This class is an input stream filter that provides a buffer into which data can be
"unread." An application may unread data at any time by pushing it back into the
buffer, as long as the buffer has sufficient room. Subsequent reads will read all of the
pushed-back data in the buffer before reading from the underlying input stream.

This functionality is useful when a fragment of code should read an indefinite number
of data bytes that are delimited by particular byte values. After reading the
terminating byte the code fragment can push it back, so that the next read operation
on the input stream will re-read that byte.

Example PushbackInputStream and OutputStream Classes

import java.io.PushbackInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class PushbackIOApp


{
public static void main(String args[]) throws IOException
{
ByteArrayOutputStream outStream = new
ByteArrayOutputStream();
String s = "This is a test.";

for(int i=0;i<s.length();++i)
outStream.write(s.charAt(i));

Basic Java 57
.

System.out.println("outstream: "+outStream);
System.out.println("size: "+outStream.size());

ByteArrayInputStream inByteArray;
inByteArray = new
ByteArrayInputStream(outStream.toByteArray());

PushbackInputStream inStream;
inStream = new PushbackInputStream(inByteArray);

char ch = (char) inStream.read();


System.out.println("First character of inStream is "+ch);
inStream.unread((int) 't');
int inBytes = inStream.available();

System.out.println("inStream has "+inBytes+" available


bytes");
byte inBuf[] = new byte[inBytes];

for(int i=0;i<inBytes;++i) inBuf[i]=(byte) inStream.read();


System.out.println("They are: "+new String(inBuf));
}
}

THE SEQUENCEINPUTSTREAM CLASS

The sequence input stream class allows an application to combine several input
streams serially and make them appear as if they were a single input stream. Each
input stream is read from, in turn, until it reaches the end of the stream. The
sequence input stream class then closes that stream and automatically switches to
the next input stream.

Example for SequenceInputStream

import java.io.FileInputStream;
import java.io.SequenceInputStream;
import java.io.IOException;

public class SequenceIOApp


{
public static void main(String args[]) throws IOException
{
SequenceInputStream inStream;
FileInputStream f1 = new
FileInputStream("ByteArrayIOApp.java");
FileInputStream f2 = new FileInputStream("FileIOApp.java");
inStream = new SequenceInputStream(f1,f2);
boolean eof = false;
int byteCount = 0;

while (!eof)
{
int c = inStream.read();
if(c == -1) eof = true;

Basic Java 58
.
else
{
System.out.print((char) c);
++byteCount;
}
}
System.out.println(byteCount+" bytes were read");
inStream.close();
f1.close();
f2.close();
}
}

THE STREAMTOKENIZER CLASS

The StreamTokenizer class takes an input stream and parses it into "tokens",
allowing the tokens to be read one at a time. The parsing process is controlled by a
table and a number of flags that can be set to various states. The stream tokenizer
can recognize identifiers, numbers, quoted strings, and various comment styles.

Each byte read from the input stream is regarded as a character in the range '\u0000'
through '\u00FF'. The character value is used to look up five possible attributes of the
character: white space, alphabetic, numeric, string quote, and comment character.
Each character can have zero or more of these attributes.

In addition, an instance has four flags. These flags indicate:

• Whether line terminators are to be returned as tokens or treated as white space


that merely separates tokens.
• Whether C-style comments are to be recognized and skipped.
• Whether C++-style comments are to be recognized and skipped. Whether the
characters of identifiers are converted to lowercase.

A typical application first constructs an instance of this class, sets up the syntax
tables, and then repeatedly loops calling the nextToken method in each iteration of
the loop until it returns the value TT_EOF.

Example for StreamTokenizer Class

import java.io.StreamTokenizer;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;

public class StreamTokenApp


{
public static void main(String args[]) throws IOException
{
BufferedReader inData =
new BufferedReader(new InputStreamReader(System.in));

StreamTokenizer inStream = new StreamTokenizer(inData);


inStream.commentChar('#');

Basic Java 59
.
boolean eof = false;
do
{
int token=inStream.nextToken();
switch(token)
{
case inStream.TT_EOF:
System.out.println("EOF encountered.");
eof = true;
break;
case inStream.TT_EOL:
System.out.println("EOL encountered.");
break;
case inStream.TT_WORD:
System.out.println("Word: "+inStream.sval);
break;
case inStream.TT_NUMBER:
System.out.println("Number: "+inStream.nval);
break;
default:
System.out.println((char) token+" encountered.");
if(token=='!') eof=true;
}
} while(!eof);
}
}

THE PIPEDINPUTSTREAM CLASS

A piped input stream is the receiving end of a communications pipe. Two threads can
communicate by having one thread send data through a piped output stream and
having the other thread read the data through a piped input stream.

Example for Piped Input/Output Operations

import java.io.*;

public class PipedExample


{
public static void main(String args[])
{
if(args.length == 0)
{
System.out.println("Usage : java PipedExample <filename>");
System.exit(0);
}
String filename = args[0];
try
{
File file = new File(filename);
FileInputStream fis = new FileInputStream(file);

byte store[] = new byte[fis.available()];


byte p_store[] = new byte[fis.available()];
fis.read(store,0,store.length);

Basic Java 60
.

PipedOutputStream piped_out = new PipedOutputStream();


PipedInputStream piped_in = new PipedInputStream(piped_out);

piped_out.write(store,0,store.length);
piped_in.read(p_store,0,p_store.length);

System.out.println("Result stored in file 'output.txt'");


FileOutputStream fos = new FileOutputStream("ouput.txt");
fos.write(p_store,0,p_store.length);

System.out.println("----------End----------");

}
catch(Exception err)
{
System.out.println("Exception in accessing file");
}
}
}

THE PRINTSTREAM CLASS

Print values and objects to an output stream, using the platform's default character
encoding to convert characters into bytes.

If automatic flushing is enabled at creation time, then the stream will be flushed each
time a line is terminated or a newline character is written.

Methods in this class never throw I/O exceptions. Client code may inquire as to
whether any errors have occurred by invoking the checkError method.

Note: This class is provided primarily for use in debugging, and for compatibility with
existing code; new code should use the PrintWriter class.

THE SERIALIZABLE INTERFACE

Serializability of a class is enabled by the class implementing the java.io.Serializable


interface. Classes that do not implement this interface will not have any of their state
serialized or deserialized. All subtypes of a serializable class are themselves
serializable. The serialization interface has no methods or fields and serves only to
identify the semantics of being serializable.

To allow subtypes of non-serializable classes to be serialized, the subtype may


assume responsibility for saving and restoring the state of the supertype'spublic,
protected, and (if accessible) package fields. The subtype may assume this
responsibility only if the class it extends has an accessible no-arg constructor to
initialize the class's state. It is an error to declare a class Serializable in this case.
The error will be detected at runtime.

During deserialization, the fields of non-serializable classes will be initialized using


thepublic or protected no-arg constructor of the class. A no-arg constructor must be
accessible to the subclass that is serializable. The fields of serializable subclasses
will be restored from the stream.

Basic Java 61
.

When traversing a graph, an object may be encountered that does not support the
Serializable interface. In this case the NotSerializableException will be thrown and
will identify the class of the non-serializable object.

Classes that require special handling during the serialization and deserialization
process must implement special methods with these exact signatures:

private void writeObject(java.io.ObjectOutputStream out)


throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;

The writeObject method is responsible for writing the state of the object for its
particular class so that the corresponding readObject method can restore it. The
default mechanism for saving the Object's fields can be invoked by calling
out.defaultWriteObject. The method does not need to concern itself with the state
belonging to its superclasses or subclasses. State is saved by writing the individual
fields to the ObjectOutputStream using the writeObject method or by using the
methods for primitive data types supported by DataOutput.

The readObject method is responsible for reading from the stream and restoring the
classes fields. It may call in.defaultReadObject to invoke the default mechanism for
restoring the object's non-static and non-transient fields. The defaultReadObject
method uses information in the stream to assign the fields of the object saved in the
stream with the correspondingly named fields in the current object. This handles the
case when the class has evolved to add new fields. The method does not need to
concern itself with the state belonging to its superclasses or subclasses. State is
saved by writing the individual fields to the ObjectOutputStream using the writeObject
method or by using the methods for primitive data types supported by DataOutput.

THE EXTENALIZABLE INTERFACE

Externalization allows a class to specify the methods to be used to write the object's
contents to a stream and to read them back. The Externalizable interface's
writeExternal and readExternal methods are implemented by a class to give the class
complete control over the format and contents of the stream for an object and its
supertypes. These methods must explicitly coordinate with the supertype to save its
state.
Object Serialization uses the Serializable and Externalizable interfaces. Object
persistence mechanisms may use them also. Each object to be stored is tested for
the Externalizable interface. If the object supports it, the writeExternal method is
called. If the object does not support Externalizable and does implement Serializable
the object should be saved using ObjectOutputStream.
When an Externalizable object is to be reconstructed, an instance is created using
thepublic no-arg constructor and the readExternal method called. Serializable objects
are restored by reading them from an ObjectInputStream.

THE OBJECTINPUTSTREAM CLASS

An ObjectInputStream deserializes primitive data and objects previously written using


an ObjectOutputStream. ObjectOutputStream and ObjectInputStream can provide an
application with persistent storage for graphs of objects when used with a

Basic Java 62
.
FileOutputStream and FileInputStream respectively. ObjectInputStream is used to
recover those objects previously serialized. Other uses include passing objects
between hosts using a socket stream or for marshaling and unmarshaling arguments
and parameters in a remote communication system.

ObjectInputStream ensures that the types of all objects in the graph created from the
stream match the classes present in the Java Virtual Machine. Classes are loaded as
required using the standard mechanisms.

Only objects that support the java.io.Serializable or java.io.Externalizable interface


can be read from streams. The method readObject is used to read an object from the
stream. Java's safe casting should be used to get the desired type. In Java, strings
and arrays are objects and are treated as objects during serialization. When read
they need to be cast to the expected type.

Primitive data types can be read from the stream using the appropriate method on
DataInput.

The default deserialization mechanism for objects restores the contents of each field
to the value and type it had when it was written. Fields declared as transient or static
are ignored by the deserialization process. References to other objects cause those
objects to be read from the stream as necessary. Graphs of objects are restored
correctly using a reference sharing mechanism. New objects are always allocated
when deserializing, which prevents existing objects from being overwritten.

Reading an object is analogous to running the constructors of a new object. Memory


is allocated for the object and initialized to zero (NULL). No-arg constructors are
invoked for the non-serializable classes and then the fields of the serializable classes
are restored from the stream starting with the serializable class closest to
java.lang.object and finishing with the object's most specifiec class.

For example to read from a stream as written by the example in ObjectOutputStream:

FileInputStream istream = new FileInputStream("t.tmp");


ObjectInputStream p = new ObjectInputStream(istream);
int i = p.readInt();
String today = (String)p.readObject();
Date date = (Date)p.readObject();
istream.close();

Classes control how they are serialized by implementing either the


java.io.Serializable or java.io.Externalizable interfaces.

Implementing the Serializable interface allows object serialization to save and restore
the entire state of the object and it allows classes to evolve between the time the
stream is written and the time it is read. It automatically traverses references
between objects, saving and restoring entire graphs. Serializable classes that require
special handling during the serialization and deserialization process should
implement both of these methods:

private void writeObject(java.io.ObjectOutputStream stream)


throws IOException;
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;

Basic Java 63
.

The readObject method is responsible for reading and restoring the state of the
object for its particular class using data written to the stream by the corresponding
writeObject method. The method does not need to concern itself with the state
belonging to its superclasses or subclasses. State is restored by reading data from
the ObjectInputStream for the individual fields and making assignments to the
appropriate fields of the object. Reading primitive data types is supported by
DataInput.

Serialization does not read or assign values to the fields of any object that does not
implement the java.io.Serializable interface. Subclasses of Objects that are not
serializable can be serializable. In this case the non-serializable class must have a
no-arg constructor to allow its fields to be initialized. In this case it is the responsibility
of the subclass to save and restore the state of the non-serializable class. It is
frequently the case that the fields of that class are accessible (public, package, or
protected) or that there are get and set methods that can be used to restore the
state.

Any exception that occurs while deserializing an object will be caught by the
ObjectInputStream and abort the reading process.

Implementing the Externalizable interface allows the object to assume complete


control over the contents and format of the object's serialized form. The methods of
the Externalizable interface, writeExternal and readExternal, are called to save and
restore the objects state. When implemented by a class they can write and read their
own state using all of the methods of ObjectOutput and ObjectInput. It is the
responsibility of the objects to handle any versioning that occurs.

Example for ObjectInput and Output Streams

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Date;

public class ObjectIOApp


{
public static void main(String args[]) throws IOException,
ClassNotFoundException
{
File file = new File("test.txt");
FileOutputStream outFile = new FileOutputStream(file);
ObjectOutputStream outStream = new
ObjectOutputStream(outFile);

TestClass1 t1 = new TestClass1(true,9,'A',0.0001,"java");


TestClass2 t2 = new TestClass2();

String t3 = "This is a test.";


Date t4 = new Date();

Basic Java 64
.

outStream.writeObject(t1);
outStream.writeObject(t2);
outStream.writeObject(t3);
outStream.writeObject(t4);
outStream.close();
outFile.close();

FileInputStream inFile = new FileInputStream(file);


ObjectInputStream inStream = new ObjectInputStream(inFile);

System.out.println(inStream.readObject());
System.out.println(inStream.readObject());
System.out.println(inStream.readObject());
System.out.println(inStream.readObject());
inStream.close();
inFile.close();
file.delete();
}
}

class TestClass1 implements Serializable


{
boolean b;
int i;
char c;
double d;
String s;
TestClass1(boolean b,int i,char c,double d,String s)
{
this.b = b;
this.i = i;
this.c = c;
this.d = d;
this.s = s;
}

public String toString()


{
String r = String.valueOf(b)+" ";
r += String.valueOf(i)+" ";
r += String.valueOf(c)+" ";
r += String.valueOf(d)+" ";
r += String.valueOf(s);
return r;
}
}

class TestClass2 implements Serializable


{
int i;
TestClass1 tc1;
TestClass1 tc2;

Basic Java 65
.
TestClass2()
{
i=0;
tc1 = new TestClass1(true,2,'j',1.234,"Java");
tc2 = new TestClass1(false,7,'J',2.468,"JAVA");
}
public String toString()
{
String r = String.valueOf(i)+" ";
r += tc1.toString()+" ";
r += tc2.toString();
return r;
}
}

THE OBJECTOUTPUTSTREAM CLASS

An ObjectOutputStream writes primitive data types and graphs of Java objects to an


OutputStream. The objects can be read (reconstituted) using an ObjectInputStream.
Persistent storage of objects can be accomplished by using a file for the stream. If
the stream is a network socket stream, the objects can be reconsituted on another
host or in another process.

Only objects that support the java.io.Serializable interface can be written to streams.
The class of each serializable object is encoded including the class name and
signature of the class, the values of the object's fields and arrays, and the closure of
any other objects referenced from the initial objects.

The method writeObject is used to write an object to the stream. Any object, including
Strings and arrays, is written with writeObject. Multiple objects or primitives can be
written to the stream. The objects must be read back from the corresponding
ObjectInputstream with the same types and in the same order as they were written.

Primitive data types can also be written to the stream using the appropriate methods
from DataOutput. Strings can also be written using the writeUTF method.

The default serialization mechanism for an object writes the class of the object, the
class signature, and the values of all non-transient and non-static fields. References
to other objects (except in transient or static fields) cause those objects to be written
also. Multiple references to a single object are encoded using a reference sharing
mechanism so that graph of objects can be restored to the same shape as when the
original was written.

For example to write an object that can be read by the example in


ObjectInputStream:

FileOutputStream ostream = new FileOutputStream("t.tmp");


ObjectOutputStream p = new ObjectOutputStream(ostream);
p.writeInt(12345);
p.writeObject("Today");
p.writeObject(new Date());
p.flush();
ostream.close();

Basic Java 66
.

Classes that require special handling during the serialization and deserialization
process must implement special methods with these exact signatures:

private void readObject(java.io.ObjectInputStream stream)


throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException

The writeObject method is responsible for writing the state of the object for its
particular class so that the corresponding readObject method can restore it. The
method does not need to concern itself with the state belonging to the object's
superclasses or subclasses. State is saved by writing the individual fields to the
ObjectOutputStream using the writeObject method or by using the methods for
primitive data types supported by DataOutput.

Serialization does not write out the fields of any object that does not implement the
java.io.Serializable interface. Subclasses of Objects that are not serializable can be
serializable. In this case the non-serializable class must have a no-arg constructor to
allow its fields to be initialized. In this case it is the responsibility of the subclass to
save and restore the state of the non-serializable class. It is frequently the case that
the fields of that class are accessible (public, package, or protected) or that there are
get and set methods that can be used to restore the state.

Serialization of an object can be prevented by implementing writeObject and


readObject methods that throw the NotSerializableException. The exception will be
caught by the ObjectOutputStream and abort the serialization process. Implementing
the Externalizable interface allows the object to assume complete control over the
contents and format of the object's serialized form. The methods of the Externalizable
interface, writeExternal and readExternal, are called to save and restore the objects
state. When implemented by a class they can write and read their own state using all
of the methods of ObjectOutput and ObjectInput. It is the responsibility of the objects
to handle any versioning that occurs.

THE INPUTSTREAMREADER CLASS

An InputStreamReader is a bridge from byte streams to character streams: It reads


bytes and translates them into characters according to a specified character
encoding. The encoding that it uses may be specified by name, or the platform's
default encoding may be accepted.

Each invocation of one of an InputStreamReader's read() methods may cause one or


more bytes to be read from the underlying byte-input stream. For top efficiency,
consider wrapping an InputStreamReader within a BufferedReader; for example,

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

Example for InputStreamReader

import java.io.InputStreamReader;
import java.io.BufferedReader;

Basic Java 67
.
import java.io.IOException;

public class InputConversionApp


{
public static void main(String args[]) throws IOException
{
InputStreamReader in = new InputStreamReader(System.in);
BufferedReader inStream = new BufferedReader(in);
System.out.println("Encoding: "+in.getEncoding());
String inputLine;
do
{
System.out.print(">");
System.out.flush();
inputLine=inStream.readLine();
System.out.println(inputLine);
} while (inputLine.length() != 0);
}
}

THE OUTPUTSTREAMWRITER CLASS

Write characters to an output stream, translating characters into bytes according to a


specified character encoding. Each OutputStreamWriter incorporates its own
CharToByteConverter, and is thus a bridge from character streams to byte streams.

The encoding used by an OutputStreamWriter may be specified by name, by


providing a CharToByteConverter, or by accepting the default encoding, which is
defined by the system property file.encoding.

Each invocation of a write() method causes the encoding converter to be invoked on


the given character(s). The resulting bytes are accumulated in a buffer before being
written to the underlying output stream. The size of this buffer may be specified, but
by default it is large enough for most purposes. Note that the characters passed to
the write() methods are not buffered. For top efficiency, consider wrapping an
OutputStreamWriter within a BufferedWriter so as to avoid frequent converter
invocations. For example,

Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

Basic Java 68
.
CHAPTER – 5: APPLET PROGRAMMING

An applet is a small program that is intended not to be run on its own, but rather to be
embedded inside another application. The Applet class must be the superclass of
any applet that is to be embedded in a Web page or viewed by the Java Applet
Viewer. The Applet class provides a standard interface between applets and their
environment.

HelloWorld Applet

Applets can be run in a browser such as Netscape Navigator, Internet Explorer.


Several differences exist between applets and applications. The most important of
these is that Java applet classes extend an existing class. This class is called
java.applet.Applet. You have to extend Applet in order for a class to be usable as
such.

One of the simplest applets is the HelloWorld applet, the source code for which is
shown below. Right away you should see that the applet HelloWorld is quite different
from the HelloWorld application.

HelloApplet.java

import java.applet.Applet;
import java.awt.Graphics;
public class HelloApplet extends Applet
{
public void paint (Graphics g)
{
g.drawString ("Hello World!",0,50);
}
}

Creating HTML file

When you created the HelloWorld application , you ran them using the Java
interpreter. Applets, however, don't run from the command line; they are executed
within a browser. To get the applet into the browser, you need to embed what are
known as HTML tags into an HTML file. The HTML file can then be read into a
browser.
The simplest HTML file for the HelloApplet class is shown.

<HTML>
<BODY>
<APPLET CODE="HelloApplet.class" WIDTH ="200" HEIGHT="200">
</APPLET>
</BODY>
</HTML>

With Java files, it is necessary that the file name be the same as the class file. This is
not necessary with the HTML file. In fact, a single HTML file can contain several
<APPLET> tags.

Basic Java 69
.
Using AppletViewer

Now, to run the applet, the JDK includes a very simplified version of a browser called
Appletviewer. Appletviewer looks for <APPLET> tags in any given HTML file and
opens a new window for each of them.

To run the HelloApplet program using Appletviewer, on the command line type:

appletviewer HelloApplet.html

Appletviewer opens a new window and runs HelloApplet in it.

UNDERSTANDING THE SOURCE CODE

Importing Other Classes

The first thing to notice are the top two lines of the code:

import java.applet.Applet;
import java.awt.Graphics;

The import statement is a new one. Often it is necessary or easier to use the
contents of a class file, which have already been created, rather than try to reproduce
that work yourself. The import statement enables you to use these other classes. If
you are familiar with the C/C++ #include declaration, the import statement works in
somewhat the same way.

In the case of the HelloApplet program, there are two classes that are used other
than HelloApplet. The first is the java.applet.Applet class. The Applet class contains
all the information that is specific to applets. In fact, in order for any class to be run in
a browser as an applet, it must extend java.applet.Applet.

The second class that is imported into HelloApplet is the java.awt.Graphics class.
java.awt.Graphics contains all kinds of tools for drawing things to the screen. In fact,
the screen is treated as a Graphics object.

Declaring an Applet Class

You may have noticed that there is a slight difference between this class declaration
for the HelloApplet class. HelloApplet extends Applet. extends is the keyword for
saying that a class should be entered into that class hierarchy. In fact, a class that
extends another class is placed at the bottom of the existing chain.

public class HelloApplet extends Applet {

You may think this is harping the issue, but it's important: all applets must extend
java.applet.Applet. However, because you imported the Applet class, you can simply
call it Applet. If you had not imported java.applet.Applet, you could still have
extended it using the full name:

public class HelloApplet extends java.applet.Applet {

Basic Java 70
.

Applet Methods—paint

The next item to notice about the HelloApplet class versus HelloWorld is that
HelloApplet doesn't have a main method. Instead, this applet only has a paint
method. How is this possible?

The answer lies in the fact that the applets don't start up themselves. They are being
added to an already running program (the browser). The browser has a predefined
means for getting each applet to do what it wants. It does this by calling methods that
it knows the Applet has. One of these is paint.

public void paint (Graphics g) {

The paint method is called any time the browser needs to display the applet on the
screen, so you can use the paint method to display anything. The browser helps out
by passing a Graphics object to the paint method. This object gives the paint method
a way to display items directly to the screen.

The next line shows an example of using the Graphics object to draw text to the
screen:

g.drawString ("Hello World!",0,50);


}

BRIEF LIFE OF AN APPLET

The paint method is not the only method that the browser calls of the applet. You can
override any of these other methods just like you did for the paint method in the
HelloWorld example.

When the applet is loaded, the browser calls the init() method. This method is only
called once no matter how many times you return to the same Web page.

After the init() method, the browser first calls the paint() method. This means that if
you need to initialize some data before you get into the paint() method, you should do
so in the init() method.

Next, the start() method is called. The start() method is called every time an applet
page is accessed. This means that if you leave a Web page and then click the Back
button, the start() method is called again. However, the init() method is not.

When you leave a Web page (say, by clicking a link), the stop() method is called.

Finally, when the browser exits all together the destroy() method is called.

Notice that unlike the paint(Graphics g) method, the init(), start(), stop(), and
destroy() methods do not take any parameters between the parentheses.

The java.applet.AppletContext Interface

This interface corresponds to an applet's environment: the document containing the


applet and the other applets in the same document. The methods in this interface
can be used by an applet to obtain information about its environment.

Basic Java 71
.

The java.applet.AppletStub Interface

When an applet is first created, an applet stub is attached to it using the applet's
setStub method. This stub serves as the interface between the applet and the
browser environment or applet viewer environment in which the application is
running.

The java.applet.AudioClip Interface

The AudioClip interface is a simple abstraction for playing a sound clip. Multiple
AudioClip items can be playing at the same time, and the resulting sound is mixed
together to produce a composite.

Basic Java 72
.

THE ABSTRACT WINDOW TOOLKIT

The Abstract Window Toolkit (normally referred to as the AWT) is a well-thought-out


and very portable windowing library. It is a standard part of the Java environment and
provides all of the basic functionality one would expect to use in a modern windowing
system.
The AWT delivers on the promise made by many cross-platform windowing libraries,
allowing your application to run on completely different windowing systems.
Moreover, it manages to preserve the look and feel of the user’s system, so AWT-
based applications won’t get a reputation for having a Java look.
The bulk of the basic AWT is sub classed from one basic class: Component

HIERARCHY CHART OF THE AWT COMPONENTS

Object

Compone Container
Panel
Button
Window

TextCompone TextField
Frame Dialog
Choice TextArea

List

MenuCompone

MenuItem Menu

MenuBar

Basic Java 73
.
A Simple AWT Applet
import java.awt.*;
import java.applet.Applet;

public class Example1 extends Applet


{
Button hiButton;
public void init()
{
hiButton = new Button(“Click Me!”);
add(hiButton);
}
}

<applet code=Example1.class width=250 height=100></applet>

It is not important at this point to understand exactly what every line means. Instead,
try to get a general feel for what is going on. The example is doing the following:
1. A Button component is created with the label, Click Me!
2. The Button is added to the container (in this case an applet).
For a program with a user interface that produces output, there is surprisingly little
code here. Almost all the real work of handling the user interface is hidden behind the
scenes. If you are using basic components, it’s relatively easy to keep things simple.
However, if you want to extend the functionality of the basic components, the
complexity of your code increases.
When a component is created, it usually is added to a container. A container is
simply an area of the screen in which components (and even other containers) can
be placed. This can go on endlessly: A component is added to a container, which is
added to another container, and so on. We will, in fact, be doing just this in the
calculator example at the end of the chapter.
This flexibility is one of the biggest advantages of programming the AWT. In an
object-oriented programming environment, it makes sense to think of the user
interface as actual objects and concentrate on relationships between objects. This is
exactly what the AWT lets you do.

Components
Components are the building blocks from which all programs using the AWT are built.
There are many other classes to handle the components and the interactions
between them, but if it’s on the screen, it’s a component.
This enables us to say a number of things about all components:
• All components have a screen position and a size
• All components have a foreground and background color
• Components are either enabled or disabled
• There is a standard interface for components to handle events
AWT components can be conceptually broken down into three major categories:

Interface components

Interface components encompass all of the standard widgets or controls normally


associated with a windowing system. Examples of these include buttons, text labels,
scrollbars, pick lists, and text-entry fields.

Basic Java 74
.
Containers
Containers encompass areas in which components can be placed. This allows
groups of components to be grouped together to form a more cohesive object to be
manipulated. A Panel is an example of this type of component.

Windows
Windows are a very special case of the Component class. All other components are
added onto a container that already exists, whereas a Window is an actual, separate
window with a completely new area to create an interface upon. Normally with applet
programming, windows are not used. Dialogs and Frames are examples of this type
of component.

The java.awt.Graphics classThe Graphics class is the abstract base class for all
graphics contexts that allow an application to draw onto components that are realized
on various devices, as well as onto off-screen images.

A Graphics object encapsulates state information needed for the basic rendering
operations that Java supports. This state information includes the following
properties:

• The Component object on which to draw.


• A translation origin for rendering and clipping coordinates.
• The current clip.
• The current color.
• The current font.
• The current logical pixel operation function (XOR or Paint).
• The current XOR alternation color .

Coordinates are infinitely thin and lie between the pixels of the output device.
Operations, which draw the outline of a figure, operate by traversing an infinitely thin
path between pixels with a pixel-sized pen that hangs down and to the right of the
anchor point on the path. Operations, which fill a figure operate by filling the interior
of that infinitely thin path. Operations, which render horizontal text render the
ascending portion of character glyphs entirely above the baseline coordinate.

The graphics pen hangs down and to the right from the path it traverses. This has the
following implications:

• If you draw a figure that covers a given rectangle, that figure occupies one extra
row of pixels on the right and bottom edges as compared to filling a figure that is
bounded by that same rectangle.
• If you draw a horizontal line along the same y coordinate as the baseline of a line
of text, that line is drawn entirely below the text, except for any descends.
All coordinates, which appear as arguments to the methods of this Graphics object
are considered relative to the translation origin of this Graphics object prior to the
invocation of the method. All rendering operations modify only pixels, which lie within
the area bounded by both the current clip of the graphics context and the extents of
the component used to create the Graphics object. All drawing or writing is done in
the current color, using the current paint mode, and in the current font.

Basic Java 75
.

Example for using Graphics class

import java.awt.Graphics;
import java.applet.Applet;

public class GraphicsExample extends Applet


{
public void paint(Graphics g)
{
g.drawString("Example for Graphics class",50,50);

g.drawRect(60,60,10,10);
g.drawOval(90,60,10,10);
g.drawRoundRect(120,60,10,10,6,6);
g.fillRect(60,90,10,10);
g.fillOval(90,90,10,10);
g.fillRoundRect(120,90,10,10,6,6);
}
}

The java.awt.Color class

This class encapsulates colors using the RGB format. In RGB format, the red, blue,
and green components of a color are each represented by an integer in the range 0-
255. The value 0 indicates no contribution from this primary color. The value 255
indicates the maximum intensity of this color component.

Although the Color class is based on the three-component RGB model, the class
provides a set of convenience methods for converting between RGB and HSB colors.

Example for Using Color class

import java.awt.*;
import java.applet.Applet;

public class ColorExample extends Applet


{
Color c_green;

public void init()


{
c_green = new Color(0,255,0);
}

public void paint(Graphics g)


{
g.drawString("Example for Color class",50,50);

g.drawRect(60,60,10,10);

g.setColor(Color.red);
g.drawOval(90,60,10,10);

Basic Java 76
.
g.drawRoundRect(120,60,10,10,6,6);

g.setColor(c_green);
g.fillRect(60,90,10,10);
g.fillOval(90,90,10,10);
g.fillRoundRect(120,90,10,10,6,6);
}
}

The java.awt.Font Class

A class that produces font objects.

Example for Font Class

import java.awt.*;
import java.applet.Applet;

public class FontExample extends Applet


{
Font font;

public void init()


{
font = new Font("Helvetica",Font.BOLD+Font.ITALIC,15);
}

public void paint(Graphics g)


{
g.setFont(font);
g.drawString("Text Displayed in Helvetica font",25,50);
}
}

The java.awt.FontMetrics class

public abstract class FontMetrics extends Object implements Serializable


A font metrics object, which gives information about the rendering of a particular font
on a particular screen. Note that the implementations of these methods are
inefficient, they are usually overridden with more efficient toolkit-specific
implementations.

Note to subclassers: Since many of these methods form closed mutually recursive
loops, you must take care that you implement at least one of the methods in each
such loop in order to prevent infinite recursion when your subclass is used. In
particular, the following is the minimal suggested set of methods to override in order
to ensure correctness and prevent infinite recursion (though other subsets are
equally feasible):

• getAscent()
• getDescent()
• getLeading()
• getMaxAdvance()

Basic Java 77
.
• charWidth(char ch)
• charsWidth(char data[], int off, int len)

When an application asks AWT to place a character at the position (x, y), the
character is placed so that its reference point is put at that position. The reference
point specifies a horizontal line called the baseline of the character. In normal
printing, the baselines of characters should align.

In addition, every character in a font has an ascent, a descent, and an advance


width. The ascent is the amount by which the character ascends above the baseline.
The descent is the amount by which the character descends below the baseline. The
advance width indicates the position at which AWT should place the next character.

If the current character is placed with its reference point at the position (x, y), and the
character's advance width is w, then the following character is placed with its
reference point at the position (x + w, y). The advance width is often the same as the
width of character's bounding box, but need not be so. In particular, oblique and italic
fonts often have characters whose top-right corner extends slightly beyond the
advance width.

An array of characters or a string can also have an ascent, a descent, and an


advance width. The ascent of the array is the maximum ascent of any character in
the array. The descent is the maximum descent of any character in the array. The
advance width is the sum of the advance widths of each of the characters in the
array.

The java.awt.LabelClass

A Label object is a component for placing text in a container. A label displays a single
line of readonly text. The text can be changed by the application, but a user cannot
edit it directly.

The java.awt.Button Class

This class creates a labeled button. The application can cause some action to
happen when the button is pushed.

The gesture of clicking on a button with the mouse is associated with one instance of
ActionEvent, which is sent out when the mouse is both pressed and released over
the button. If an application is interested in knowing when the button has been
pressed but not released, as a separate gesture, it can specialize
processMouseEvent, or it can register itself as a listener for mouse events by calling
addMouseListener. Both of these methods are defined by Component, the abstract
superclass of all components.

When a button is pressed and released, AWT sends an instance of ActionEvent to


the button, by calling processEvent on the button. The button's processEvent method
receives all events for the button; it passes an action event along by calling its own
processActionEvent method. The latter method passes the action event on to any
action listeners that have registered an interest in action events generated by this
button.

Basic Java 78
.
If an application wants to perform some action based on a button being pressed and
released, it should implement ActionListener and register the new listener to receive
events from this button, by calling the button's addActionListener method. The
application can make use of the button's action command as a messaging protocol.

The java.awt.TextComponent Class

public class TextComponent extends Component


The TextComponent class is the superclass of any component that allows the
editing of some text.

A text component embodies a string of text. The TextComponent class


defines a set of methods that determine whether or not this text is editable. If
the component is editable, it defines another set of methods that supports a
text insertion caret.

In addition, the class defines methods that are used to maintain a current
selection from the text. The text selection, a substring of the component's text,
is the target of editing operations. It is also referred to as the selected text.

The java.awt.Checkbox Class

public class Checkbox extends Component implements ItemSelectable

A check box is a graphical component that can be in either an "on" (true) or "off"
(false) state. Clicking on a check box changes its state from "on" to "off," or from "off"
to "on."

The following code example creates a set of check boxes:

add(new Checkbox("one", null, true));


add(new Checkbox("two"));
add(new Checkbox("three"));

The button labeled one is in the "on" state, and the other two are in the "off" state. In
this example, the states of the three check boxes are set independently.

Alternatively, several check boxes can be grouped together under the control of a
single object, using the CheckboxGroup class. In a check box group, at most one
button can be in the "on" state at any given time. Clicking on a check box to turn it on
forces any other check box in the same group that is on into the "off" state.

The java.awt.CheckboxGroup Class

public class CheckboxGroup extends Object implements Serializable


The CheckboxGroup class is used to group together a set of Checkbox buttons.

Exactly one check box button in a CheckboxGroup can be in the "on" state at any
given time. Pushing any button sets its state to "on" and forces any other button that
is in the "on" state into the "off" state.

The following code example produces a new check box group, with three check
boxes:

Basic Java 79
.
CheckboxGroup cbg = new CheckboxGroup();
add(new Checkbox("one", cbg, true));
add(new Checkbox("two", cbg, false));
add(new Checkbox("three", cbg, false));
The java.awt.Choice

public class Choice extends Component implements ItemSelectable

The Choice class presents a popup menu of choices. The current choice is displayed
as the title of the menu.

Example for adding Choice

import java.awt.*;
import java.applet.Applet;

public class ChoiceExample extends Applet


{
Choice ColorChooser;
public void init|()
{
ColorChooser = new Choice();
ColorChooser.add("Green");
ColorChooser.add("Red");
ColorChooser.add("Blue");
add(ColorChooser);
}
}

The java.awt.List Class

public class List extends Component implements ItemSelectable


The List component presents the user with a scrolling list of text items. The list can
be set up so that the user can choose either one item or multiple items.

For example, the code . . .

List lst = new List(4, false);


lst.add("Mercury");
lst.add("Venus");
lst.add("Earth");
lst.add("JavaSoft");
lst.add("Mars");
lst.add("Jupiter");
lst.add("Saturn");
lst.add("Uranus");
lst.add("Neptune");
lst.add("Pluto");
cnt.add(lst);

Clicking on an item that isn't selected selects it. Clicking on an item that is already
selected deselects it. In the preceding example, only one item from the scrolling list
can be selected at a time, since the second argument when creating the new
scrolling list is false. Selecting an item causes any other selected item to be
automatically deselected.

Basic Java 80
.

Beginning with Java 1.1, the Abstract Window Toolkit sends the List object all
MOUSE, keyboard, and focus events that occur over it. (The old AWT event model is
being maintained only for backward compatibility, and its use is discouraged.)

When an item is selected or deselected, AWT sends an instance of Item Event to the
list. When the user double-clicks on an item in a scrolling list, AWT sends an instance
of ActionEvent to the list following the item event. AWT also generates an action
event when the user presses the return key while an item in the list is selected.

If an application wants to perform some action based on an item in this list being
selected or activated, it should implement ItemListener or ActionListener as
appropriate and register the new listener to receive events from this list.

For multiple selection scrolling lists, it is considered a better user interface to use an
external gesture (such as clicking on a button) to trigger the action.

The java.awt.Canvas Class

A Canvas component represents a blank rectangular area of the screen onto which
the application can draw or from which the application can trap input events from the
user.

An application must subclass the Canvas class in order to get useful functionality
such as creating a custom component. The paint method must be overridden in order
to perform custom graphics on the canvas.

Example for Canvas Class

import java.awt.*;

public class CanvasTest extends java.applet.Applet


{
MyCanvas doodle;

public void init()


{
doodle = new MyCanvas(getSize().width,
getSize().height);
add(doodle);
}
}

class MyCanvas extends Canvas {

public MyCanvas() {
this(100,100);
}

public MyCanvas(int width, int height) {


resize(width,height);
}

public void paint(Graphics g) {

Basic Java 81
.
g.fillRect(0, 0, getSize().width-1, getSize().height-
1);
}
}

The java.awt.Scrollbar Class

public class Scrollbar extends Component implements Adjustable


The Scrollbar class embodies a scroll bar, a familiar user interface object. A scroll bar
provides a convenient means for allowing a user to select from a range of values.

The following code provides a sample model of scrollbar.

redSlider=new Scrollbar(Scrollbar.VERTICAL, 0, 1, 0, 255);


add(redSlider);

Alternatively, a scroll bar can represent a range of values. For example, if a scroll bar
is used for scrolling through text, the width of the "bubble" or "thumb" can represent
the amount of text that is visible. Here is an example of a scroll bar that represents a
range:

The value range represented by the bubble is the visible range of the scroll bar. The
horizontal scroll bar in this example could be created with code like the following:

ranger = new Scrollbar(Scrollbar.HORIZONTAL, 0, 64, 0, 255);


add(ranger);

Note that the maximum value above, 255, is the maximum value for the scroll bar's
bubble. The actual width of the scroll bar's track is 255 + 64. When the scroll bar is
set to its maximum value, the left side of the bubble is at 255, and the right side is at
255 + 64.

Normally, the user changes the value of the scroll bar by making a gesture with the
mouse. For example, the user can drag the scroll bar's bubble up and down, or click
in the scroll bar's unit increment or block increment areas. Keyboard gestures can
also be mapped to the scroll bar. By convention, the Page Up and Page Down keys
are equivalent to clicking in the scroll bar's block increment and block decrement
areas.

When the user changes the value of the scroll bar, the scroll bar receives an instance
of AdjustmentEvent. The scroll bar processes this event, passing it along to any
registered listeners.

Any object that wishes to be notified of changes to the scroll bar's value should
implement AdjustmentListener, an interface defined in the package java.awt.event.
Listeners can be added and removed dynamically by calling the methods
addAdjustmentListener and removeAdjustmentListener.

The AdjustmentEvent class defines five types of adjustment event, listed here:

AdjustmentEvent.TRACK is sent out when the user drags the scroll bar's bubble.
AdjustmentEvent.UNIT_INCREMENT is sent out when the user clicks in the left
arrow of a horizontal scroll bar, or the top arrow of a vertical scroll bar, or makes the
equivalent gesture from the keyboard.

Basic Java 82
.
AdjustmentEvent.UNIT_DECREMENT is sent out when the user clicks in the right
arrow of a horizontal scroll bar, or the bottom arrow of a vertical scroll bar, or makes
the equivalent gesture from the keyboard. AdjustmentEvent.BLOCK_INCREMENT is
sent out when the user clicks in the track, to the left of the bubble on a horizontal
scroll bar, or above the bubble on a vertical scroll bar. By convention, the Page Up
key is equivalent, if the user is using a keyboard that defines a Page Up key.
AdjustmentEvent.BLOCK_DECREMENT is sent out when the user clicks in the track,
to the right of the bubble on a horizontal scroll bar, or below the bubble on a vertical
scroll bar. By convention, the Page Down key is equivalent, if the user is using a
keyboard that defines a Page Down key.
The JDK 1.0 event system is supported for backward compatibility, but its use with
newer versions of JDK is discouraged. The fives types of adjustment event
introduced with JDK 1.1 correspond to the five event types that are associated with
scroll bars in previous JDK versions. The following list gives the adjustment event
type, and the corresponding JDK 1.0 event type it replaces.

• AdjustmentEvent.TRACK replaces Event.SCROLL_ABSOLUTE


• AdjustmentEvent.UNIT_INCREMENT replaces Event.SCROLL_LINE_UP
• AdjustmentEvent.UNIT_DECREMENT replaces Event.SCROLL_LINE_DOWN
• AdjustmentEvent.BLOCK_INCREMENT replaces Event.SCROLL_PAGE_UP
• AdjustmentEvent.BLOCK_DECREMENT replaces
Event.SCROLL_PAGE_DOWN

The java.awt.ScrollPane Class

public class ScrollPane extends Container

A container class, which implements automatic horizontal and/or vertical scrolling for
a single child component. The display policy for the scrollbars can be set to:

1.as needed : scrollbars created and shown only when needed by scrollpane
2.always : scrollbars created and always shown by the scrollpane
3.never : scrollbars never created or shown by the scrollpane

The state of the horizontal and vertical scrollbars is represented by two objects (one
for each dimension) which implement the Adjustable interface. The API provides
methods to access those objects such that the attributes on the Adjustable object
(such as unitIncrement, value, etc.) can be manipulated.

Certain adjustable properties (minimum, maximum, blockIncrement, and


visibleAmount) are set internally by the scrollpane in accordance with the geometry
of the scrollpane and its child and these should not be set by programs using the
scrollpane.

If the scrollbar display policy is defined as "never", then the scrollpane can still be
programmatically scrolled using the setScrollPosition() method and the scrollpane will
move and clip the child's contents appropriately. This policy is useful if the program
needs to create and manage its own adjustable controls.

The placement of the scrollbars is controlled by platformspecific properties set by the


user outside of the program.

The initial size of this container is set to 100x100, but can be reset using setSize().

Basic Java 83
.

Insets are used to define any space used by scrollbars and any borders created by
the scroll pane. getInsets() can be used to get the current value for the insets. If the
value of scrollbarsAlwaysVisible is false, then the value of the insets will change
dynamically depending on whether the scrollbars are currently visible or not.

Example for ScrollPane Class

import java.applet.Applet;
import java.awt.*;
public class ScrollpaneTest extends Applet
{
public void init()
{
ScrollPane pane;
XCanvas xcan;
setLayout(new BorderLayout());
pane = new ScrollPane();
add("Center", pane);
xcan = new XCanvas();
xcan.setSize(200, 200);
pane.add(xcan);
}
}

class XCanvas extends Canvas {


public void paint(Graphics g) {
g.drawLine(0, 0, 200, 200);
g.drawLine(0, 200, 200, 0);
}
}

The java.awt.Insets Class

public class Insets extends Object implements Cloneable, Serializable


An Insets object is a representation of the borders of a container. It specifies the
space that a container must leave at each of its edges. The space can be a border, a
blank space, or a title.

Example for Using Insets

import java.awt.*;
class InsetTest
{
public static void main (String[] args)
{

MyFrame win = new MyFrame();

win.setLayout( new FlowLayout() );


win.add( new Button("One") );
win.add( new Button("Two") );
win.add( new Button("Three") );

Basic Java 84
.
win.add( new Button("Four") );
win.pack();
win.show();
System.out.println( win.insets() );
}
}
class MyFrame extends Frame
{
public Insets insets() { return new Insets(100, 2, 2, 2); }
//public Insets insets() { return new Insets(25, 100, 2, 2);
}
// public Insets insets() { return new Insets(25, 2, 100, 2);
}
//public Insets insets() { return new Insets(25, 2, 2, 100); }
}

EVENT HANDLING

An event is a communication from the outside world to the program that something
has occurred. The following are a few basic event types:

• Mouse clicks
When the mouse button is clicked while positioned over a component.
• Mouse movement
The mouse is moved over a component, many events are sent to the
component informing it what coordinates in the component the mouse has
moved to.
• Action events
A component that an action can be performed upon is used, an Action event
is created by default and the owner of the component (usually the container in
which the component is placed) is notified that something happened.

One of the most important things to understand about the AWT is how events are
handled. Without events, your application will not be able to respond to user actions.

Event Handling in JDK1.0

Example for using action

import java.awt.*;
import java.applet.Applet;

public class ActionEvent extends Applet


{
Button bt_submit;
TextField tf_data;

public void init()


{
bt_submit = new Button("SUBMIT");
tf_data = new TextField(15);

add(bt_submit);

Basic Java 85
.
add(tf_data);
}
public boolean action(Event evt, Object obj)
{
if(evt.target == bt_submit)
{
tf_data.setText("Button Clicked");
}
return true;
}
}

Let’s break the action() method down line by line:

public boolean action(Event evt, Object what) {

All event handlers have a form similar to this. They accept a parameter of type Event
that provides detailed information about the event. Second, they return a Boolean
value-indicating True if the event was handled or False if it was not.
if (evt.target == bt_submit) {
Here the target of the event is being checked to see whether or not it is the button.
Because evt.target and hiButton are both objects, we can check to see if they are the
same objects.

tf_data.setText(“Button Clicked”)
Because the button was clicked, we change the textfield to reflect that.

return true;
}
else
return false;

Finally, if the event was handled, return true or else return false. This is an important
concept to keep in mind: The event handler keeps searching for a method that will
accept the Event. Accepting the Event is signaled by returning true.

Event Handling in Detail


In almost all cases, you will want to use the event-handling methods that Sun has
provided for you. These are summarized in Table below. Remember that everything
is relative to the component. For example, the mouseMove() method of a component
is called when the mouse is moved inside that component.
Java events.

Event Type Method


Action taken action(Event evt, Object what)
Mouse button pressed mouseDown(Event evt, int x, int y)
Mouse button released mouseUp(Event evt, int x, int y)
Mouse moved mouseMove(Event evt, int x, int y)
Mouse dragged mouseDrag(Event evt, int x, int y)
Mouse enters component mouseEnter(Event evt, int x, int y)
Mouse exits component mouseExit(Event evt, int x, int y)
Key pressed keyDown(Event evt, int key)

Basic Java 86
.
Key released keyUp(Event evt, int key)
When would you want to use other methods than action()? The answer is that when
you actually want to change the behavior of a component (as opposed to just using
the component as is was originally designed) action() isn’t quite enough. It only
reports events that are essential to the utility of the component, such as a mouse
click on a button.
Let’s add new behavior to the previous example.

Adding new behavior to the sample applet.

import java.awt.*;

import java.applet.Applet;

public class Example3 extends Applet {

Button hiButton;

public void init() {

hiButton = new Button(“Click Me!!!”);

add(hiButton);

public boolean mouseEnter(Event evt, int x, int y) {

hiButton.setLabel(“Go Away!”);

return true;

public boolean mouseExit(Event evt, int x, int y) {

hiButton.setLabel(“Stay Away!”);

return true;

public boolean action(Event evt, Object what) {

if (evt.target == hiButton) {

hiButton.setLabel(“Clicked!”);

return true;

else

Basic Java 87
.
return false;

<applet code=Example3.class width=250 height=100></applet>

Now, whenever the mouse moves over the applet, the user is informed that perhaps
clicking on the button isn’t such a good idea. This is a fundamentally different
behavior than the previous example. Before, we were using a button in a completely
standard manner. Here, we wished to change that functionality. This is important to
remember—otherwise, you might end up sub-classing components where you don’t
need to, making your program slower and more difficult to understand and maintain.

handleEvent() or action()
Generally, a combination of action() and the other built-in event handlers will do the
job nicely. For those times when you want to take complete control of the process
yourself, handleEvent() is available.
handleEvent() has advantages and disadvantages. On the positive side, you have
complete control. On the negative side, you have complete control. This means that
you must be very careful overriding the default handleEvent() or your application can
become buggy and confusing very quickly.
For example, let’s say you overrode handleEvent() in your class for whatever reason,
but you had used mouseEnter() earlier in the development of the program, as shown
in the following:

Example using handleEvent

class MyLabel extends Label


{
MyLabel(String label)
{
super(label);
}

public boolean mouseEnter(Event evt, int x, int y)


{
setText(“Not Again”);
}

public boolean handleEvent(Event evt)


{
if (Event.id == KEY_PRESS)
{
setText(“Keypress”);
return true;
}
else return false;
}
}
You would expect the mouseEnter() you had written to keep working. Unfortunately
that’s not the case. Because the default handleEvent() has been overridden,

Basic Java 88
.
mouseEnter() never gets called. Luckily there is an easy solution to this problem for
many cases. Add the following to your handleEvent() in place of return false;:

return super.handleEvent(evt);

This has the benefit of keeping all of the functionality of the old handleEvent() while
letting you manipulate things first. Note, however, that you can also override
handleEvent() to remove functionality, in which case you wouldn’t want to call the
parent’s handleEvent(). It’s all up to you.

Delivering Events
Occasionally the ability of the program to manufacture its own events comes in quite
handy. Although it may seem strange to fake an event, in reality it makes the design
of a program much simpler.
For example, if you were designing a calculator you might decide to write an event
handler in the main container that deciphers the action events from the button, as
follows:
public boolean action(Event evt, obj What) {

if (evt.target == oneKey)

... // Append 1 to the current number

}
...
}

However, it might make sense to add the ability to handle keyboard input, because a
user of the calculator would expect that functionality from a calculator. Although you
could just copy the code from the action() handler to a new keyDown() handler, you
would then have two copies of the same code in the same program to maintain and
keep track of. The solution is to deliver your own event. A simple event can be
created with the following form:

Event aEvent = new Event (target, id, obj);

Where target is the Object that you would like the event delivered to, id is an integer
representing the event type, and obj is an arbitrary argument to append to the event
if there is extra information that you would like the handler to receive. Then, to deliver
the event, you just need to call deliverEvent() as follows:

deliverEvent(aEvent);

So, in the previous example, you could add another handler that does the following:

public boolean keyDown(Event evt, int key)


{
if (key == 49) { // If the 1 key was pressed
deliverEvent(new Event(oneKey,Event.MOUSE_DOWN, null));
return true;
}
...
}

Basic Java 89
.

Now you can manage the rest of the program without worrying about handling
keyboard input differently—the same event is generated whether the button is clicked
or the correspond

AWT event types.

Event type Event ID’s


The Action event ACTION_EVENT
Mouse button pressed MOUSE_DOWN
Mouse dragged MOUSE_DRAG
Mouse entered MOUSE_ENTER
Mouse exited MOUSE_EXIT
Mouse button released MOUSE_UP
Mouse moved MOUSE_MOVE
Key pressed KEY_PRESS
Key released KEY_RELEASE

Dealing with Focus


When a user clicks a user interface component, that item becomes in a sense
“selected”. This is as known as the input focus. For instance, when a text field is
clicked on, the user then can type in the field because it has the input focus.
When a component receives the input focus, the gotFocus() method of that
component is called, as follows:

public boolean gotFocus(Event evt, Object what) {


...
}

When a component loses the input focus, the lostFocus() method of that component
is called, as follows:

public boolean lostFocus(Event evt, Object what) {


...
}

It is not uncommon for a program to desire to keep the focus. For example, if a text-
entry field were being used to display output rather than to accept input, you probably
would not want it to be able to receive the focus. Using a text-entry field to display
output enables you to take advantage of the field’s text-handling abilities. In that
case, the requestFocus() method exists, as shown in the following:

public void requestFocus() {


...
}
This could be placed in the container that the text field has been used in and would
bar that field from receiving the focus.

Basic Java 90
.

Event Handling in JDK1.1

Event Handling in JDK 1.1 is through listeners. Listeners are provided as interfaces
to enable multiple listeners to a class and also to enable the class to provide a
specific definition. . In Java 1.1 and later versions, the Event class is maintained only
for backwards compatibilty

Example for using ActionListener

import java.awt.Button;
import java.applet.Applet;
import java.awt.event.*;

public class ButtonDelegateTest extends Applet


{

public void init()


{

Button b = new Button("I have a listener!");


add(b);
b.addActionListener(listener);

public void actionPerformed(ActionEvent e)


{
System.out.println("Listener here: the button was
clicked.");
}

The java.awt.event.ActionListener interface

public interface ActionListener extends EventListener


The listener interface for receiving action events.

Methods

public abstract void actionPerformed(ActionEvent e)


Invoked when an action occurs.

Example for using AdjustmentListener

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class AdjustmentEventTest extends Applet


implements AdjustmentListener
{
public void init()
{

Basic Java 91
.

setLayout(new BorderLayout());
// A plain scrollbar that delegates to the applet.
Scrollbar sbar1 = new Scrollbar();
sbar1.addAdjustmentListener(this);
add(sbar1, "West");
// A subclass that handles its own adjustment events
SelfScrollbar sbar2 = new SelfScrollbar();
add(sbar2, "East");
}
public void adjustmentValueChanged(AdjustmentEvent e)
{
System.out.println("Scrollbar #1: " + e.getValue());
}
}
class SelfScrollbar extends Scrollbar
{
public SelfScrollbar()
{
enableEvents(AWTEvent.ADJUSTMENT_EVENT_MASK);
}

public void processAdjustmentEvent (AdjustmentEvent e) {


System.out.println("Scrollbar #2: " + e.getValue());
}
}

Example for using FocusEvent

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class FocusEventTest extends Applet


implements FocusListener {

public void init() {


setLayout(new BorderLayout());
// A textfield that delegates to the applet.
TextField tf = new TextField();
tf.addFocusListener(this);
add(tf, "North");
// A subclass that handles its own focus events
SelfTextArea sta = new SelfTextArea();
add(sta, "Center");
}

public void focusGained(FocusEvent e) {


System.out.println("Text Field gained focus");
}

public void focusLost(FocusEvent e) {


System.out.println("Text Field lost focus");
}

Basic Java 92
.
}

class SelfTextArea extends TextArea {

public SelfTextArea() {
enableEvents(AWTEvent.FOCUS_EVENT_MASK);
}

public void processFocusEvent(FocusEvent e) {


if (e.getId() == FocusEvent.FOCUS_GAINED)
System.out.println("Text Area gained focus");
else
System.out.println("Text Area lost focus");
}
}
The java.awt.event.FocusListener interface

The listener interface for receiving keyboard focus events on a component.

public abstract void focusGained(FocusEvent e)


public abstract void focusLost(FocusEvent e)

Example for using ItemListener

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class ItemEventTest extends Applet


implements ItemListener {
List list;
SelfChoice sc;

public void init() {


// A list that delegates to the applet.
list = new List(5, false);
list.addItem("Chocolate");
list.addItem("Vanilla");
list.addItem("Strawberry");
list.addItem("Mocha");
list.addItem("Peppermint Swirl");
list.addItem("Blackberry Ripple");
list.addItem("Butterscotch");
list.addItem("Spumoni");
list.addItemListener(this);
add(list);
// A choice subclass that handles its own item events
sc = new SelfChoice();
sc.addItem("Ice Cream");
sc.addItem("Frozen Yogurt");
sc.addItem("Sorbet");

Basic Java 93
.
add(sc);
}

public void itemStateChanged(ItemEvent e) {


System.out.println("New item from list:" +
list.getSelectedItem());
}
}

class SelfChoice extends Choice {

public SelfChoice() {
enableEvents(AWTEvent.ITEM_EVENT_MASK);
}

public void processItemEvent(ItemEvent e) {


System.out.println("New item from choice: " +
getSelectedItem());
}
}

The java.awt.event.ItemListener interface

public interface ItemListener extends EventListener


The listener interface for receiving item events.

public abstract void itemStateChanged(ItemEvent e)

Example for using KeyListener

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class KeyEventTest extends Applet


implements KeyListener {

public void init() {


setLayout(new BorderLayout());
// A text field that delegates to the applet.
TextField tf = new TextField();
tf.addKeyListener(this);
add(tf, "North");
// A text area subclass that handles its own item events
SelfKeyTextArea sta = new SelfKeyTextArea();
add(sta, "Center");
}

public void keyTyped(KeyEvent e)


{
System.out.println("Key typed in text field: " +
e.getKeyChar());
}

Basic Java 94
.
public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
}

class SelfKeyTextArea extends TextArea {


public SelfKeyTextArea() {
enableEvents(AWTEvent.KEY_EVENT_MASK);
}

public void processKeyEvent(KeyEvent e) {


if (e.getId() == KeyEvent.KEY_TYPED)
System.out.println("Key typed in text area: " +
e.getKeyChar());
}
}

The java.awt.event.KeyListener interface

public interface KeyListener extends EventListener


The listener interface for receiving keyboard events.

public abstract void keyTyped(KeyEvent e)


Invoked when a key has been typed. This event occurs when a key press is followed
by a key release.

public abstract void keyPressed(KeyEvent e)


Invoked when a key has been pressed.

public abstract void keyReleased(KeyEvent e)


Invoked when a key has been released.

Example for using Mouse & MouseMotion Listeners

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class MouseEventTest extends Applet


implements MouseListener, MouseMotionListener {

public void init() {


setLayout(new GridLayout(2, 1));
// A canvas that delegates to the applet.
Canvas can1 = new Canvas();
can1.setBackground(Color.yellow);
can1.addMouseListener(this);
can1.addMouseMotionListener(this);
add(can1);
// A canvas subclass that handles its own item events
SelfMouseCanvas can2 = new SelfMouseCanvas();
add(can2);
}

Basic Java 95
.
public void mousePressed(MouseEvent e) {
System.out.println("UPPER: mouse pressed at " +
e.getX() + "," + e.getY());
}

public void mouseReleased(MouseEvent e) {


System.out.println("UPPER: mouse released at " +
e.getX() + "," + e.getY());
}

public void mouseEntered(MouseEvent e) {


System.out.println("UPPER: mouse entered");
}

public void mouseExited(MouseEvent e) { } // Satisfy


compiler
public void mouseClicked(MouseEvent e) { } // Ditto
public void mouseMoved(MouseEvent e) { } // Ditto
public void mouseDragged(MouseEvent e) { } // Ditto
}

class SelfMouseCanvas extends Canvas {


public SelfMouseCanvas() {
setBackground(Color.green);
enableEvents(AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK);
}

public void processMouseEvent(MouseEvent e) {


if (e.getId() == MouseEvent.MOUSE_PRESSED)
System.out.println("LOWER: mouse pressed at " +
e.getX() + "," + e.getY());
else if (e.getId() == MouseEvent.MOUSE_RELEASED)
System.out.println("LOWER: mouse released at " +
e.getX() + "," + e.getY());
else if (e.getId() == MouseEvent.MOUSE_ENTERED)
System.out.println("LOWER: mouse entered");
}
}

The java.awt.event.MouseListener interface

public interface MouseListener extends EventListener


The listener interface for receiving mouse events on a component.

public abstract void mouseClicked(MouseEvent e)


Invoked when the mouse has been clicked on a component.

public abstract void mousePressed(MouseEvent e)


Invoked when a mouse button has been pressed on a component.

public abstract void mouseReleased(MouseEvent e)


Invoked when a mouse button has been released on a component.

Basic Java 96
.
public abstract void mouseEntered(MouseEvent e)
Invoked when the mouse enters a component.

public abstract void mouseExited(MouseEvent e)


Invoked when the mouse exits a component.

The java.awt.event.MouseMotionListener interface

public interface MouseMotionListener extends EventListener


The listener interface for receiving mouse motion events on a component.

public abstract void mouseDragged(MouseEvent e)


Invoked when a mouse button is pressed on a component and then dragged. Mouse
drag events will continue to be delivered to the component where the first originated
until the mouse button is released (regardless of whether the mouse position is within
the bounds of the component).

public abstract void mouseMoved(MouseEvent e)


Invoked when the mouse button has been moved on a component (with no buttons
no down).

Example for using TextListener

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class TextEventTest extends Applet


implements TextListener {

public void init() {


setLayout(new GridLayout(2, 1));
// A text area that delegates to the applet.
TextArea ta1 = new TextArea();
ta1.addTextListener(this);
add(ta1);
// A text area subclass that handles its own item events
SelfTextTA ta2 = new SelfTextTA();
add(ta2);
}

public void textValueChanged(TextEvent e) {


System.out.println("UPPER get text event: " + e);
}
}

class SelfTextTA extends TextArea {


public SelfTextTA() {
enableEvents(AWTEvent.TEXT_EVENT_MASK);
}

public void processTextEvent(TextEvent e) {


System.out.println("LOWER get text event: " + e);
}
}

Basic Java 97
.

The java.awt.event.TextListener interface

public interface TextListener extends EventListener


The listener interface for receiving adjustment events.

public abstract void textValueChanged(TextEvent e)


Invoked when the value of the text has changed.

The java.awt.event.WindowListener interface

public interface WindowListener extends EventListener


The listener interface for receiving window events.

public abstract void windowOpened(WindowEvent e)


Invoked when a window has been opened.

public abstract void windowClosing(WindowEvent e)


Invoked when a window is in the process of being closed. The close operation can be
overridden at this point.

public abstract void windowClosed(WindowEvent e)


Invoked when a window has been closed.

public abstract void windowIconified(WindowEvent e)


Invoked when a window is iconified.

public abstract void windowDeiconified(WindowEvent e)


Invoked when a window is deiconified.

public abstract void windowActivated(WindowEvent e)


Invoked when a window is activated.

public abstract void windowDeactivated(WindowEvent e)


Invoked when a window is deactivated.

AWT LAYOUTS

The java.awt.FlowLayout class

public class FlowLayout extends Object implements LayoutManager, Serializable


A flow layout arranges components in a left to right flow, much like lines of text in a
paragraph. Flow layouts are typically used to arrange buttons in a panel. It will
arrange buttons left to right until no more buttons fit on the same line. Each line is
centered.

Basic Java 98
.
Example for FlowLayout

import java.awt.*;
import java.applet.Applet;
public class myButtons extends Applet {
Button button1, button2, button3;
FlowLayout flow;

public void init()


{
flow = new FlowLayout(FlowLayout.CENTER);
setLayout(flow);
button1 = new Button("Ok");
button2 = new Button("Open");
button3 = new Button("Close");
add(button1);
add(button2);
add(button3);
}
}

A flow layout lets each component assume its natural (preferred) size.

The java.awt.BorderLayout class

public class BorderLayout extends Object implements LayoutManager2, Serializable

A border layout lays out a container, arranging and resizing its components to fit in
five regions: North, South, East, West, and Center. When adding a component to a
container with a border layout, use one of these five names, for example:

Panel p = new Panel();


p.setLayout(new BorderLayout());
p.add(new Button("Okay"), "South");

As a convenience, BorderLayout interprets the absence of a string specification the


same as "Center":
Panel p2 = new Panel();
p2.setLayout(new BorderLayout());
p2.add(new TextArea()); // Same as p.add(new TextArea(), "Center");

The components are laid out according to their preferred sizes and the constraints of
the container's size. The North and South components may be stretched horizontally;
the East and West components may be stretched vertically; the Center component
may stretch both horizontally and vertically to fill any space left over.
Here is an example of five buttons in an applet laid out using the BorderLayout layout
manager:

Example for using BorderLayout

import java.awt.*;
import java.applet.Applet;
public class buttonDir extends Applet {
public void init() {

Basic Java 99
.
setLayout(new BorderLayout());
add("North", new Button("North"));
add("South", new Button("South"));
add("East", new Button("East"));
add("West", new Button("West"));
add("Center", new Button("Center"));
}
}

The java.awt.BorderLayout class

public class BorderLayout extends Object implements LayoutManager2, Serializable

A border layout lays out a container, arranging and resizing its components to fit in
five regions: North, South, East, West, and Center. When adding a component to a
container with a border layout, use one of these five names, for example:

Panel p = new Panel();


p.setLayout(new BorderLayout());
p.add(new Button("Okay"), "South");

As a convenience, BorderLayout interprets the absence of a string specification the


same as "Center":

Panel p2 = new Panel();


p2.setLayout(new BorderLayout());
p2.add(new TextArea()); // Same as p.add(new TextArea(), "Center");

The components are laid out according to their preferred sizes and the constraints of
the container's size. The North and South components may be stretched horizontally;
the East and West components may be stretched vertically; the Center component
may stretch both horizontally and vertically to fill any space left over.

Here is an example of five buttons in an applet laid out using the BorderLayout layout
manager:

Example for using BorderLayout

import java.awt.*;
import java.applet.Applet;
public class buttonDir extends Applet {
public void init() {
setLayout(new BorderLayout());
add("North", new Button("North"));
add("South", new Button("South"));
add("East", new Button("East"));
add("West", new Button("West"));
add("Center", new Button("Center"));
}
}

The java.awt.GridLayout class

public class GridLayout extends Object implements LayoutManager,

Basic Java 100


.
Serializable
The GridLayout class is a layout manager that lays out a container's components in a
rectangular grid.

The container is divided into equalsized rectangles, and one component is placed in
each rectangle.

For example, the following is an applet that lays out six buttons into three rows and
two columns:

Example for GridLayout

import java.awt.*;
import java.applet.Applet;
public class ButtonGrid extends Applet
{
public void init()
{
setLayout(new GridLayout(3,2));
add(new Button("1"));
add(new Button("2"));
add(new Button("3"));
add(new Button("4"));
add(new Button("5"));
add(new Button("6"));
}
}

The java.awt.GridbagLayout class

public class GridBagLayout extends Object implements LayoutManager2,


Serializable
The GridBagLayout class is a flexible layout manager that aligns components
vertically and horizontally, without requiring that the components be of the same size.
Each GridBagLayout object maintains a dynamic rectangular grid of cells, with each
component occupying one or more cells, called its display area.

Each component managed by a grid bag layout is associated with an instance of


GridBagConstraints that specifies how the component is laid out within its display
area.

How a GridBagLayout object places a set of components depends on the


GridBagConstraints object associated with each component, and on the minimum
size and the preferred size of the components' containers.

To use a grid bag layout effectively, you must customize one or more of the
GridBagConstraints objects that are associated with its components. You customize
a GridBagConstraints object by setting one or more of its instance variables:

gridx, gridy

Specifies the cell at the upper left of the component's display area, where the
upperleftmost cell has address gridx = 0, gridy = 0. Use

Basic Java 101


.
GridBagConstraints.RELATIVE (the default value) to specify that the component be
just placed just to the right of (for gridx) or just below (for gridy) the component that
was added to the container just before this component was added.

gridwidth, gridheight

Specifies the number of cells in a row (for gridwidth) or column (for gridheight) in the
component's display area. The default value is 1. Use
GridBagConstraints.REMAINDER to specify that the component be the last one in its
row (for gridwidth) or column (for gridheight). Use GridBagConstraints.RELATIVE to
specify that the component be the next to last one in its row (for gridwidth) or column
(for gridheight).

fill

Used when the component's display area is larger than the component's requested
size to determine whether (and how) to resize the component. Possible values are
GridBagConstraints.NONE (the default), GridBagConstraints.HORIZONTAL (make
the component wide enough to fill its display area horizontally, but don't change its
height), GridBagConstraints.VERTICAL (make the component tall enough to fill its
display area vertically, but don't change its width), and GridBagConstraints.BOTH
(make the component fill its display area entirely).

ipadx, ipady

Specifies the component's internal padding within the layout, how much to add to the
minimum size of the component. The width of the component will be at least its
minimum width plus (ipadx * 2) pixels (since the padding applies to both sides of the
component). Similarly, the height of the component will be at least the minimum
height plus (ipady * 2) pixels.

insets

Specifies the component's external padding, the minimum amount of space between
the component and the edges of its display area.

anchor

Used when the component is smaller than its display area to determine where (within
the display area) to place the component. Valid values are
GridBagConstraints.CENTER (the default), GridBagConstraints.NORTH,
GridBagConstraints.NORTHEAST, GridBagConstraints.EAST,
GridBagConstraints.SOUTHEAST, GridBagConstraints.SOUTH,
GridBagConstraints.SOUTHWEST, GridBagConstraints.WEST, and
GridBagConstraints.NORTHWEST.

weightx, weighty

Used to determine how to distribute space, which is important for specifying resizing
behavior. Unless you specify a weight for at least one component in a row (weightx)
and column (weighty), all the components clump together in the center of their
container. This is because when the weight is zero (the default), the GridBagLayout
object puts any extra space between its grid of cells and the edges of the container.

Basic Java 102


.

Example for GridbagLayout

import java.awt.*;
public class Gridbag extends java.applet.Applet
{
public void init()
{
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
Button b;

setLayout(gb);
// gbc.fill= GridBagConstraints.HORIZONTAL;
gbc.anchor= GridBagConstraints.NORTHWEST;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.gridx = 0;
gbc.gridy = 0;
b = new Button("First");
gb.setConstraints(b, gbc);
add(b);
b = new Button("Second");
gbc.gridx = 1;
gbc.gridwidth = 2;
gb.setConstraints(b, gbc);
add(b);
b = new Button("Third");
gbc.gridx = 3;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gb.setConstraints(b, gbc);
add(b);
b = new Button("Fourth");
gbc.gridy++;
gbc.gridx = 0;
gb.setConstraints(b, gbc);
add(b);
b = new Button("Fifth");
gbc.gridwidth = 1;
gbc.gridy++;
gb.setConstraints(b, gbc);
add(b);
b = new Button("Sixth");
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridx = 2;
gb.setConstraints(b, gbc);
add(b);

}
}

Basic Java 103


.
Java Foundation Classes

To address the shortcomings of the AWT, the Java Foundation Classes (JFC) were
developed. JFC 1.2 is an extension of the AWT, not a replacement of it. The JFC
visual components extend the AWT container class. So the methods in the
Component & Container classes are still valid.

JFC 1.2 consists of five major packages:

9 Swing
9 Pluggable Look-and-feel(PL&F)
9 Drag and Drop
9 Accessibility
9 2D

Swing
Swing components allow for efficient graphical user interface development. Swing
Components are lightweight components. The major difference between lightweight
and heavyweight components is that a lightweight component can have transparent
pixels while a heavyweight component is always opaque. By taking advantage of
transparent pixels, a lightweight component can appear to be non-rectangular, while
a heavyweight component must always be rectangular. A mouse event occuring in a
lightweight component falls through to its parent component, while a mouse event in
a heavyweight component doesnot propagate through its parent component. Swing
Components are Java Bean Compliant.

Application Code

JFC Java 2D

Swing Drag and Drop

AWT
Accessibility

Basic Java 104


.
The Swing component toolkit consists of over 250 pure Java classes and 75
interfaces contained in more than 10 packages. Swing consists of UI and non-UI
classes. UI components descend from the Jcomponent class. Non-UI classes consist
of the event related classes.

The Swing packages available are :

9 javax.swing

9 javax.swing.border

9 javax.swing.text

9 javax.swing.table

9 javax.swing.event

9 javax.swing.undo

9 javax.swing.plaf etc

The First Swing Program:

import javax.swing.*;
import java.awt.*;
public class HelloSwing extends JFrame {
JLabel text;
public HelloSwing(String title) {
super(title);
text = new JLabel("Hello Swing");
getContentPane().add(BorderLayout.NORTH,text);
pack();
setVisible(true);
}
public static void main(String arg[])
{
HelloSwing swing = new HelloSwing("First
Swing");
}
}

An Insight :

The line "import javax.swing.*" denotes the package that includes all the swing APIs.
The JLabel & JFrame are swing components extending JComponent. The method
"getContentPane()" returns reference to a JContainer on which the components can
be added.

Applying Border:

The statement,

panel.setBorder (BorderFactory.createTitledBorder("Border Example"));

Basic Java 105


.

creates a border with title "Border Example"

Other Borders

9 MatteBorder

9 LineBorder

9 EtchedBorder

9 EmptyBorder

9 BevelBorder

9 SoftBevelBorder

9 CompoundBorder

Example of using Other Borders

----
JPanel panel2, panel3;
panel2 = new JPanel();
panel3 = new JPanel();
panel2.setBorder(BorderFactory.createLineBorder(Color.red,5));
Icon imgIcon = new ImageIcon("dot.gif");
MatteBorder matte = new MatteBorder(imgIcon);
panel3.setBorder(matte);
----

Creating an ImageButton

---
Icon imgIcon = new ImageIcon(“dot.gif”);
JButton imgBtn = new JButton(“Click here”,imgIcon);
---

displays a ImageButton with the image and the label

Basic Java 106


.
Example Using JProgressBar

import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
import java.awt.event.*;
public class UsingProgressBar extends JFrame implements
ActionListener,Runnable {

JButton start;
JProgressBar progress;
int count = 0;
Thread t = null;

public UsingProgressBar(String title)


{
//code for adding components
t = new Thread(this);
}

public void actionPerformed(ActionEvent event) {


t.start();
}
public void run() {
while(true)
progress.setValue(++count);
}

Example using JTree

//code for class & constructor


DefaultMutableTreeNode main = new DefaultMutableTreeNode("MDC
Futura");
DefaultMutableTreeNode first = new
DefaultMutableTreeNode("COMXpert");
DefaultMutableTreeNode second = new
DefaultMutableTreeNode("CORBAXpert");
DefaultMutableTreeNode a_first = new
DefaultMutableTreeNode("ASP");
DefaultMutableTreeNode b_first = new
DefaultMutableTreeNode("COM");
DefaultMutableTreeNode a_second = new
DefaultMutableTreeNode("JAVA");
DefaultMutableTreeNode b_second = new
DefaultMutableTreeNode("CORBA");

first.add(a_first); first.add(b_first);
second.add(a_second);
second.add(b_second);
main.add(first); main.add(second);

TreeModel model = new DefaultTreeModel(main);


JTree tree = new JTree(model);

Basic Java 107


.
//rest of code

This displays a tree structure as follows:

Using JTable

//code for class & constructor


Vector row = new Vector();
Vector data = new Vector();
Vector column = new Vector();

row.addElement("COMXpert");
row.addElement("ASP & COM");
data.addElement(row);

row = new Vector();


row.addElement("CORBAXpert");
row.addElement("JAVA & CORBA");
data.addElement(row);
row = new Vector();
row.addElement("WEBXpert");
row.addElement("COM & CORBA");
data.addElement(row);

column.addElement("Course Name");
column.addElement("Course Contents");
JTable table = new JTable(data,column);
//code to add the table

Basic Java 108


.
This displays a table as follows:

Using Toolitp

The statement,
setTooltipText(String text)
is used to set the tooltip for a JComponent

Example
JButton btn = new JButton(“Submit”);
btn.setTooltipText(“Click here “);

KeyStroke Handling :

//code to be added
tf_data.registerKeyboardAction(this,KeyStroke.getKeyStroke
(KeyEvent.VK_ESCAPE,0),JComponent.WHEN_FOCUSED);

The above statement listens to the Escape key press on the textfield tf_data and
performs the code stated in the actionPerformed block of the ActionListener

Creating Custom Cursor

The code block,

---
Image img = getToolkit().getImage("duke.gif");
Cursor cr = getToolkit().createCustomCursor
(img, new Point(16,16), "crosshair cursor");
btn.setCursor(cr);
---
creates a cursor with image of a duke. This cursor is made visible when the mouse is
moved over the button.

Basic Java 109


.
CHAPTER – 6 : MULTITHREADING

Threads are a relatively recent invention in the computer science world. Although
processes, their larger parent, have been around for decades, threads have only
recently been accepted into the mainstream. What’s odd about this is that they are
extremely valuable, and programs written with them are noticeably better, even to the
casual user. In fact, some of the best individual, Herculean efforts over the years
have involved implementing a threads-like facility by hand to give a program a more
friendly feel to its users.

Imagine that you’re using your favorite text editor on a large file. When it starts up,
does it need to examine the entire file before it lets you edit? Does it need to make a
copy of the file? If the file is huge, this can be a nightmare. Wouldn’t it be nicer for it
to show you the first page, enabling you to begin editing, and somehow (in the
background) complete the slower tasks necessary for initialization? Threads allow
exactly this kind of within-the-program parallelism.

Perhaps the best example of threading (or lack of it) is a Web browser. Can your
browser download an indefinite number of files and Web pages at once while still
enabling you to continue browsing? While these pages are downloading, can your
browser download all the pictures, sounds, and so forth in parallel, interleaving the
fast and slow download times of multiple Internet servers? HotJava can do all of
these things—and more—by using the built-in threading of the Java language.

Threads: What They Are and Why You Need Them

Depending on your experience with operating systems and with environments within
those systems, you may or may not have run into the concept of threads. Let’s start
from the beginning with some definitions.
When a program runs, it starts executing, runs its initialization code, calls methods or
procedures, and continues running and processing until it’s complete or until the
program is exited. That program uses a single thread—where the thread is a single
locus of control for the program.

Multithreading, as in Java, enables several different execution threads to run at the


same time inside the same program, in parallel, without interfering with each other.
Here’s a simple example. Suppose you have a long computation near the start of a
program’s execution. This long computation may not be needed until later on in the
program’s execution—it’s actually tangential to the main point of the program, but it
needs to get done eventually. In a single-threaded program, you have to wait for that
computation to finish before the rest of the program can continue running. In a
multithreaded system, you can put that computation into its own thread, enabling the
rest of the program to continue running independently.

Using threads in Java, you can create an applet so that it runs in its own thread, and
it will happily run all by itself without interfering with any other part of the system.
Using threads, you can have lots of applets running at once on the same page.
Depending on how many you have, you may eventually exhaust the system so that
all of them will run slower, but all of them will run independently.
Even if you don’t have lots of applets, using threads in your applets is good Java
programming practice. The general rule of thumb for well-behaved applets:
Whenever you have any bit of processing that is likely to continue for a long time

Basic Java 110


.
(such as an animation loop, or a bit of code that takes a long time to execute), put it
in a thread.

Thread Scheduling

The part of the system that decides the real-time ordering of threads is called the
scheduler.
You might wonder exactly what order your threads will be run in, and how you can
control that order. Unfortunately, the current implementations of the Java system
cannot precisely answer the former, though with a lot of work, you can always do the
latter.

Preemptive Versus Non-preemptive

Normally, any scheduler has two fundamentally different ways of looking at its job:
nonpreemptive scheduling and preemptive time-slicing.

Note:

With non-preemptive scheduling, the scheduler runs the current thread forever,
requiring that thread explicitly to tell it when it is safe to start a different thread.
With preemptive time-slicing, the scheduler runs the current thread until it has used
up a certain tiny fraction of a second, and then “preempts” it, suspend()s it, and
resume()s another thread for the next tiny fraction of a second.

Non-preemptive scheduling is very courtly, always asking for permission to schedule,


and is quite valuable in extremely time-critical, real-time applications where being
interrupted at the wrong moment, or for too long, could mean crashing an airplane.
Most modern schedulers use preemptive time slicing, because except for a few time-
critical cases, it has turned out to make writing multithreaded programs much easier.
For one thing, it does not force each thread to decide exactly when it should “yield”
control to another thread. Instead, every thread can just run blindly on, knowing that
the scheduler will be fair about giving all the other threads their chance to run.

It turns out that this approach is still not the ideal way to schedule threads. You’ve
given a little too much control to the scheduler. The final touch many modern
schedulers add is to enable you to assign each thread a priority. This creates a total
ordering of all threads, making some threads more “important” than others. Being
higher priority often means that a thread gets run more often (or gets more total
running time), but it always means that it can interrupt other, lower-priority threads,
even before their “time-slice” has expired. If you're going to depend on the priority of
your threads, make sure that you test the application on both a Windows and
Macintosh or UNIX machine.

The current Java release does not precisely specify the behavior of its scheduler.
Threads can be assigned priorities, and when a choice is made between several
threads that all want to run, the highest-priority thread wins. However, among threads
that are all the same priority, the behavior is not well-defined. In fact, the different
platforms on which Java currently runs have different behaviors—some behaving
more like a preemptive scheduler and some more like a non-preemptive scheduler.

Basic Java 111


.

Writing Applets with Threads

How do you create an applet that uses threads? There are several things you need
to do.
There are four modifications you need to make to create an applet that uses threads:
• Change the signature of your applet class to include the word implements
Runnable.
• Include an instance variable to hold this applet’s thread.
• Modify your start() method to do nothing but spawn a thread and start it
running.
• Create a run() method that contains the actual code that starts your applet
running.

Step 1:
The first change is to the first line of your class definition.
You need to change it to the following:

public class MyAppletClass extends java.applet.Applet implements Runnable {


…...
}
What does this do? It includes support for the Runnable interface in your applet.
Here, the Runnable interface includes the behavior your applet needs to run a
thread; in particular, it gives you a default definition for the run() method. Before
proceeding further, let’s get on to the details of Runnable interface

The java.lang.Runnable interface

The Runnable interface should be implemented by any class whose instances are
intended to be executed by a thread. The class must define a method of no
arguments called run. This interface is designed to provide a common protocol for
objects that wish to execute code while they are active. For example, Runnable is
implemented by class Thread. Being active simply means that a thread has been
started and has not yet been stopped. In addition, Runnable provides the means for
a class to be active while not subclassing Thread. A class that implements Runnable
can run without subclassing Thread by instantiating a Thread instance and passing
itself in as the target. In most cases, the Runnable interface should be used if you are
only planning to override the run() method and no other Thread methods. This is
important because classes should not be subclassed unless the programmer intends
on modifying or enhancing the fundamental behavior of the class.

public abstract void run()


When an object implementing interface Runnable is used to create a thread, starting
the thread causes the object's run method to be called in that separately executing
thread.

Step 2:

Basic Java 112


.
The second step is to add an instance variable to hold this applet’s thread. Call it
anything you like; it’s a variable of the type Thread (Thread is a class in java.lang, so
you don’t have to import it):
Thread runner:

Step 3:
Third, add a start() method or modify the existing one so that it does nothing but
create a new thread and start it running. Here’s a typical example of a start() method:
public void start()
{
if (runner == null);
{
runner = new Thread(this);
runner.start();
}
}

Step 4 :
If you modify start() to do nothing but spawn a thread, where does the body of your
applet go? It goes into a new method, run(), which looks like this:
public void run() {

// what your applet actually does

}
run() can contain anything you want to run in the separate thread: initialization code,
the actual loop for your applet, or anything else that needs to run in its own thread.
You also can create new objects and call methods from inside run(), and they’ll also
run inside that thread. The run method is the real heart of your applet.

Step 5:
Finally, now that you’ve got threads running and a start method to start them, you
should add a stop() method to suspend execution of that thread (and therefore
whatever the applet is doing at the time) when the reader leaves the page. stop(), like
start(), is usually something along these lines:
public void stop()
{
if (runner != null)
{
runner.stop();
runner = null;
}
}

The stop() method here does two things:

• it stops the thread from executing


• sets the thread’s variable (runner) to null.

Setting the variable to null makes the Thread object it previously contained available
for garbage collection so that the applet can be removed from memory after a certain

Basic Java 113


.
amount of time. If the reader comes back to this page and this applet, the start
method creates a new thread and starts up the applet once again.
Now you have a well-behaved applet that runs in its own thread.

The Problem with Parallelism

If threading is so wonderful, why doesn’t every system have it? Many modern
operating systems have the basic primitives needed to create and run threads, but
they are missing a key ingredient. The rest of their environment is not thread-safe.
Imagine that you are in a thread, one of many, and each of you is sharing some
important data managed by the system. If you were managing that data, you could
take steps to protect it but the system is managing it. Now visualize a piece of code
in the system that reads some crucial value, thinks about it for a while, and then adds
1 to the value:

if (crucialValue > 0)
{
... // think about what to do
crucialValue += 1;
}

Remember that any number of threads may be calling upon this part of the system at
once. The disaster occurs when two threads have both executed the if test before
either has incremented the crucialValue. In that case, the value is clobbered by them
both with the same crucialValue + 1, and one of the increments has been lost. This
may not seem so bad to you, but imagine instead that the crucial value affects the
state of the screen as it is being displayed. Now, unfortunate ordering of the threads
can cause the screen to be updated incorrectly. In the same way, mouse or keyboard
events can be lost, databases can be inaccurately updated, and so forth.

This disaster is inescapable if any significant part of the system has not been written
with threads in mind. Therein lies the barrier to a mainstream threaded
environment—the large effort required to rewrite existing libraries for thread safety.
Luckily, Java was written from scratch with this is mind, and every Java class in its
library is thread-safe. Thus, you now have to worry only about your own
synchronization and thread-ordering problems, because you can assume that the
Java system will do the right thing.

The java.lang.Thread Class

A thread is a thread of execution in a program. The Java Virtual Machine allows an


application to have multiple threads of execution running concurrently. Every thread
has a priority. Threads with higher priority are executed in preference to threads with
lower priority. Each thread may or may not also be marked as a daemon. When code
running in some thread creates a new Thread object, the new thread has its priority
initially set equal to the priority of the creating thread, and is a daemon thread if and
only if the creating thread is a daemon.

When a Java Virtual Machine starts up, there is usually a single non-daemon thread
(which typically calls the method named main of some designated class). The Java
Virtual Machine continues to execute threads until either of the following occurs:

Basic Java 114


.
• The exit method of class Runtime has been called and the security manager has
permitted the exit operation to take place.
• All threads that are not daemon threads have died, either by returning from the
call to the run method or by performing the stop method.

There are two ways to create a new thread of execution. One is to declare a class to
be a subclass of Thread. This subclass should override the run method of class
Thread. An instance of the subclass can then be allocated and started. For example,
a thread that computes primes larger than a stated value could be written as follows:

class PrimeThread extends Thread {


long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}

The following code would then create a thread and start it running:

PrimeThread p = new PrimeThread(143);


p.start();

The other way to create a thread is to declare a class that implements the Runnable
interface. That class then implements the run method. An instance of the class can
then be allocated, passed as an argument when creating Thread, and started. The
same example in this other style looks like the following:

class PrimeRun implements Runnable


{
long minPrime;
PrimeRun(long minPrime)
{
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}

The following code would then create a thread and start it running:

PrimeRun p = new PrimeRun(143);


new Thread(p).start();

Every thread has a name for identification purposes. More than one thread may have
the same name. If a name is not specified when a thread is created, a new name is
generated for it.

Basic Java 115


.

Constructors

public Thread()
Allocates a new Thread object. This constructor has the same effect as Thread(null,
null, gname), where gname is a newly generated name. Automatically generated
names are of the form "Thread-"+n, where n is an integer. Threads created this way
must have overridden their run() method to actually do anything.

An example illustrating this method being used follows:

import java.lang.*;
class plain01 implements Runnable
{
String name;
plain01() {
name = null;
}
plain01(String s) {
name = s;
}
public void run() {
if (name == null)
System.out.println("A new thread created");
else
System.out.println("A new thread with name "
+ name +
" created");
}
}
class threadtest01 {
public static void main(String args[] ) {
int failed = 0 ;
Thread t1 = new Thread();
if (t1 != null)
System.out.println("new Thread() succeed");
else {
System.out.println("new Thread() failed");
failed++;
}
}
}

public Thread(Runnable target)


Allocates a new Thread object. This constructor has the same effect as Thread(null,
target, gname), where gname is a newly generated name. Automatically generated
names are of the form "Thread-"+n, where n is an integer.

public Thread(ThreadGroup group, Runnable target)


Allocates a new Thread object. This constructor has the same effect as
Thread(group, target, gname), where gname is a newly generated name.
Automatically generated names are of the form "Thread-"+n, where n is an integer.

public Thread(String name)

Basic Java 116


.
Allocates a new Thread object. This constructor has the same effect as Thread(null,
null, name).

public Thread(ThreadGroup group, String name)


Allocates a new Thread object. This constructor has the same effect as
Thread(group, null, name)

public Thread(Runnable target,String name)


Allocates a new Thread object. This constructor has the same effect as Thread(null,
target, name).

public Thread(ThreadGroup group,Runnable target, String name)


Allocates a new Thread object so that it has target as its run object, has the specified
name as its name, and belongs to the thread group referred to by group. If group is
not null, the checkAccess method of that thread group is called with no arguments;
this may result in throwing a SecurityException; if group is null, the new process
belongs to the same group as the thread that is creating the new thread.

If the target argument is not null, the run method of the target is called when this
thread is started. If the target argument is null, this thread's run method is called
when this thread is started.

The priority of the newly created thread is set equal to the priority of the thread
creating it, that is, the currently running thread. The method setPriority may be used
to change the priority to a new value.

The newly created thread is initially marked as being a daemon thread if and only if
the thread creating it is currently marked as a daemon thread. The method
setDaemon may be used to change whether or not a thread is a daemon.

Example for using Thread Class

class FirstThread extends Thread


{
public FirstThread(String name)
{
super(name);
}
public void run()
{
for(int count = 0;count<25;count++)
{
System.out.println("count : "+count);
if(count == 10)
{
System.out.println("First Thread in sleep
state");
try
{
Thread.sleep(3000);
}
catch(Exception err){}
}
}

Basic Java 117


.
}
}

class SecondThread extends Thread


{
public SecondThread(String name)
{
super(name);
}
public void run()
{
for(int index = 0;index<25;index++)
{
System.out.println("***");
}
}
}

public class ThreadExample{public static void main(String


args[])
{
FirstThread first = new FirstThread("first");
SecondThread second = new SecondThread("second");
System.out.println("Number of active threads : " +
(Thread.activeCount()));
System.out.println("Name of
current thread : "
+((Thread.currentThread()).getName(
)));
first.start();
second.start();
}
}

Synchronization

When dealing with multiple threads, consider this: What happens when two or more
threads want to access the same variable at the same time, and at least one of the
Threads wants to change the variable? If they were allowed to do this at will, chaos
would reign. For example, while one thread reads Joe Smith's record, another thread
tries to change his salary (Joe has earned a 50-cent raise). The problem is that this
little change causes the Thread reading the file in the middle of the others update to
see something somewhat random, and it thinks Joe has gotten a $500 raise. That's a
great thing for Joe, but not such a great thing for the company, and probably a worse
thing for the programmer who will lose his job because of it. How do you resolve this?
The first thing to do is declare the method that will change the data and the method
that will read to be synchronized. Java's key word, synchronized, tells the system to
put a lock around a particular method. At most, one thread may be in any
synchronized method at a time.

Basic Java 118


.

Two synchronized methods.

public synchronized void setVar(int){


myVar=x;
}
public synchronized int getVar (){
return myVar;
}

Now, while in setVar() the Java VM sets a condition lock, and no other thread will be
allowed to enter a synchronized method, including getVar(), until setVar() has
finished. Because the other threads are prevented from entering getVar(), no thread
will obtain information which is not correct because setVar() is in mid-write.

The java.lang.ThreadGroup Class

A thread group represents a set of threads. In addition, a thread group can also
include other thread groups. The thread groups form a tree in which every thread
group except the initial thread group has a parent.
A thread is allowed to access information about its own thread group, but not to
access information about its thread group's parent thread group or any other thread
groups.

Constructors

public ThreadGroup(String name)


Constructs a new thread group. The parent of this new group is the thread group of
the currently running thread.

public ThreadGroup(ThreadGroup parent,String name)


Creates a new thread group. The parent of this new group is the specified thread
group. The checkAccess method of the parent thread group is called with no
arguments; this may result in a security exception.

The Daemon Property


Threads can be one of two types: either a thread is a user thread or a Daemon
thread.
Daemon thread is not a natural thread, either. You can set off Daemon threads on a
path without ever worrying whether they come back. Once you start a Daemon
thread, you don't need to worry about stopping it. When the thread reaches the end
of the tasks it was assigned, it stops and changes its state to inactive, much like user
threads.
A very important difference between Daemon threads and user threads is that
Daemon Threads can run all the time. If the Java interpreter determines that only
Daemon threads are running, it will exit, without worrying if the Daemon threads have
finished. This is very useful because it enables you to start threads that do things
such as monitoring; they die on their own when there is nothing else running.

Two methods in java.lang.Thread deal with the Daemonic state assigned to a thread:

Basic Java 119


.
• isDaemon()
• setDaemon(boolean)
The first method, isDaemon(), is used to test the state of a particular thread.
Occasionally, this is useful to an object running as a thread so it can determine if it is
running as a Daemon or a regular thread. isDaemon() returns true if the thread is a
Daemon, and false otherwise.
The second method, setDaemon(boolean), is used to change the daemonic state of
the thread. To make a thread a Daemon, you indicate this by setting the input value
to true. To change it back to a user thread, you set the Boolean value to false.

The java.lang.ThreadDeath Class

An instance of ThreadDeath is thrown in the victim thread when the stop method with
zero arguments in class Thread is called. An application should catch instances of
this class only if it must clean up after being terminated asynchronously. If
ThreadDeath is caught by a method, it is important that it be rethrown so that the
thread actually dies.
The top-level error handler does not print out a message if ThreadDeath is never
caught. The class ThreadDeath is specifically a subclass of Error rather than
Exception, even though it is a "normal occurrence", because many applications catch
all occurrences of Exception and then discard the exception.

Basic Java 120


.
CHAPTER – 7: Networking in Java

The Java execution environment is designed so that applications can be easily


written to efficiently communicate and share processing with remote systems. Much
of this functionality is provided with the standard Java API within the java.net
package.

TCP/IP Protocols

Three protocols are most commonly used within the TCP/IP scheme and a closer
investigation of their properties is warranted. Understanding how these three
protocols (IP, TCP, and UDP) interact is critical to developing network applications.

Internet Protocol (IP)

IP is the keystone of the TCP/IP suite. All data on the Internet flows through IP
packets, the basic unit of IP transmissions. IP is termed a connectionless, unreliable
protocol. As a connectionless protocol, IP does not exchange control information
before transmitting data to a remote system—packets are merely sent to the
destination with the expectation that they will be treated properly. IP is unreliable
because it does not retransmit lost packets or detect corrupted data. These tasks
must be implemented by higher level protocols, such as TCP.

IP defines a universal-addressing scheme called IP addresses. An IP address is a


32-bit number and each standard address is unique on the Internet. Given an IP
packet, the information can be routed to the destination based upon the IP address
defined in the packet header. IP addresses are generally written as four numbers,
between 0 and 255, separated by period. (for example, 124.148.157.6)

While a 32-bit number is an appropriate way to address systems for computers,


humans understandably have difficulty remembering them. Thus, a system called the
Domain Name System (DNS) was developed to map IP addresses to more intuitive
identifiers and vice-versa. You can use www.netspace.org instead of 128.148.157.6.

It is important to realize that these domain names are not used nor understood by IP.
When an application wants to transmit data to another machine on the Internet, it
must first translate the domain name to an IP address using the DNS. A receiving
application can perform a reverse translation, using the DNS to return a domain
name given an IP address. There is not a one-to-one correspondence between IP
addresses and domain names: A domain name can map to multiple IP addresses,
and multiple IP addresses can map to the same domain name.

Java provides a class to work with IP Addresses, InetAddress.

Basic Java 121


.
THE INETADDRESS CLASS

This class represents an Internet Protocol (IP) address. Applications should use the
methods getLocalHost, getByName, or getAllByName to create a new InetAddress
instance. Transmission Control Protocol (TCP)

Most Internet applications use TCP to implement the transport layer. TCP provides a
reliable, connection-oriented, continuous-stream protocol. The implications of these
characteristics are:

• Reliable. When TCP segments, the smallest unit of TCP transmissions, are
lost or corrupted, the TCP implementation will detect this and retransmit
necessary segments.

• Connection-oriented. TCP sets up a connection with a remote system by


transmitting control information, often known as a handshake, before
beginning a communication. At the end of the connect, a similar closing
handshake ends the transmission.

• Continuous-stream. TCP provides a communications medium that allows for


an arbitrary number of bytes to be sent and received smoothly; once a
connection has been established, TCP segments provide the application layer
the appearance of a continuous flow of data.

Because of these characteristics, it is easy to see why TCP would be used by most
Internet applications. TCP makes it very easy to create a network application, freeing
you from worrying how the data is broken up or about coding error correction
routines. However, TCP requires a significant amount of overhead and perhaps you
might wish to code routines that more efficiently provide reliable transmissions given
the parameters of your application. Furthermore, retransmission of lost data may be
inappropriate for your application, because such information's usefulness may have
expired.

An important addressing scheme which TCP defines is the port. Ports separate
various TCP communications streams which are running concurrently on the same
system. For server applications, which wait for TCP clients to initiate contact, a
specific port can be established from where communications will originate. These
concepts come together in a programming abstraction known as sockets.

User Datagram Protocol (UDP)

UDP is a low-overhead alternative to TCP for host-to-host communications. In


contrast to TCP, UDP has the following features:
• Unreliable. UDP has no mechanism for detecting errors nor retransmitting lost
or corrupted information.
• Connectionless. UDP does not negotiate a connection before transmitting
data. Information is sent with the assumption that the recipient will be
listening.
• Message-oriented. UDP allows applications to send self-contained messages
within UDP datagrams, the unit of UDP transmission. The application must
package all information within individual datagrams.
For some applications, UDP is more appropriate than TCP. For instance, with the
Network Time Protocol (NTP), lost data indicating the current time would be invalid

Basic Java 122


.
by the time it was retransmitted. In a LAN environment, Network File System (NFS)
can more efficiently provide reliability at the application layer and thus uses UDP.

As with TCP, UDP provides the addressing scheme of ports, allowing for many
applications to simultaneously send and receive datagrams. UDP ports are distinct
from TCP ports. For example, one application can respond to UDP port 512 while
another unrelated service handles TCP port 512.

Uniform Resource Locator (URL)


While IP addresses uniquely identify systems on the Internet, and ports identify TCP
or UDP services on a system, URLs provide a universal identification scheme at the
application level. Anyone who has used a Web browser is familiar with seeing URLs,
though their complete syntax may not be self-evident. URLs were developed to
create a common format of identifying resources on the Web, but they were designed
to be general enough so as to encompass applications that predated the Web by
decades. Similarly, the URL syntax is flexible enough so as to accommodate future
protocols.
URL Syntax
The primary classification of URLs is the scheme, which usually corresponds to an
application protocol. Schemes include http, ftp, telnet, and gopher. The rest of the
URL syntax is in a format that depends upon the scheme. These two portions of
information are separated by a colon to give us:
scheme-name:scheme-info

Thus, while mailto:dwb@netspace.org indicates "send mail to user dwb at the


machine netspace.org," ftp://dwb@netspace.org/ means "open an FTP connection to
netspace.org and log in as user dwb."

General URL Format

Most URLs used conform to a general format that follows the following pattern:
scheme-name://host:port/file-info#internal-reference

Scheme-name is a URL scheme such as HTTP, FTP, or Gopher. Host is the domain
name or IP address of the remote system. Port is the port number on which the
service is listening; since most application protocols define a standard port, unless a
non-standard port is being used, the port and the colon which delimits it from the host
is omitted. File-info is the resource requested on the remote system, which often
times is a file. However, the file portion may actually execute a server program and it
usually includes a path to a specific file on the system. The internal-reference is
usually the identifier of a named anchor within an HTML page. A named anchor
allows a link to target a particular location within an HTML page. Usually this is not
used, and this token with the # character that delimits it is omitted.

Java and URLs


Java provides a very powerful and elegant mechanism for creating network client
applications allowing you to use relatively few statements to obtain resources from
the Internet. The java.net package contains the sources of this power, the URL and
URLConnection classes.

Basic Java 123


.

THE URL CLASS

Class URL represents a Uniform Resource Locator, a pointer to a "resource" on the


World Wide Web. A resource can be something as simple as a file or a directory, or it
can be a reference to a more complicated object, such as a query to a database or to
a search engine. More information on the types of URLs and their formats can be
found at:
http://www.ncsa.uiuc.edu/demoweb/url-primer.html

In general, a URL can be broken into several parts. The previous example of a URL
indicates that the protocol to use is http (HyperText Transport Protocol) and that the
information resides on a host machine named www.ncsa.uiuc.edu. The information
on that host machine is named demoweb/url-primer.html. The exact meaning of this
name on the host machine is both protocol dependent and host dependent. The
information normally resides in a file, but it could be generated on the fly. This
component of the URL is called the file component, even though the information is
not necessarily in a file.

A URL can optionally specify a "port", which is the port number to which the TCP
connection is made on the remote host machine. If the port is not specified, the
default port for the protocol is used instead. For example, the default port for http is
80. An alternative port could be specified as:
http://www.ncsa.uiuc.edu:8080/demoweb/url-primer.html

A URL may have appended to it an "anchor", also known as a "ref" or a "reference".


The anchor is indicated by the sharp sign character "#" followed by more characters.
For example,

http://java.sun.com/index.html#chapter1

This anchor is not technically part of the URL. Rather, it indicates that after the
specified resource is retrieved, the application is specifically interested in that part of
the document that has the tag chapter1 attached to it. The meaning of a tag is
resource specific.

An application can also specify a "relative URL", which contains only enough
information to reach the resource relative to another URL. Relative URLs are
frequently used within HTML pages.

For example, if the contents of the URL:


http://java.sun.com/index.html

contained within it the relative URL:


FAQ.html

it would be a shorthand for:


http://java.sun.com/FAQ.html

The relative URL need not specify all the components of a URL. If the protocol, host
name, or port number is missing, the value is inherited from the fully specified URL.
The file component must be specified. The optional anchor is not inherited.

Basic Java 124


.
Example for URL

GetURLApp.java

import java.net.URL;
import java.net.MalformedURLException;
import java.io.*;

public class GetURLApp


{
public static void main(String args[])
{
try
{
if(args.length!=1) error("Usage: java GetURLApp URL");
System.out.println("Fetching URL: "+args[0]);
URL url = new URL(args[0]);
BufferedReader inStream = new BufferedReader(
new InputStreamReader(url.openStream()));
String line;
while ((line = inStream.readLine())!= null)
{
System.out.println(line);
}
inStream.close();
}
catch (MalformedURLException ex)
{
error("Bad URL");
}
catch (IOException ex)
{
error("IOException occurred.");
}
}

public static void error(String s){


System.out.println(s);
System.exit(1);
}
}

THE URLCONNECTION CLASS

The abstract class URLConnection is the superclass of all classes that represent a
communications link between the application and a URL. Instances of this class can
be used both to read from and to write to the resource referenced by the URL. In
general, creating a connection to a URL is a multistep process:
openConnection()
connect()

Manipulate parameters that affect the connection to the remote resource.


Interact with the resource; query header fields and contents.

Basic Java 125


.
1. The connection object is created by invoking the openConnection method on a
URL.
2. The setup parameters and general request properties are manipulated.
3. The actual connection to the remote object is made, using the connect method.
4. The remote object becomes available. The header fields and the contents of the
remote object can be accessed.
The setup parameters are modified using the following methods:
• setAllowUserInteraction
• setDoInput
• setDoOutput
• setIfModifiedSince
• setUseCaches
and the general request properties are modified using the method:
* setRequestProperty

Default values for the AllowUserInteraction and UseCaches parameters can be set
using the methods setDefaultAllowUserInteraction and setDefaultUseCaches. Default
values for general request properties can be set using the
setDefaultRequestProperty method.

Each of the above set methods has a corresponding get method to retrieve the value
of the parameter or general request property. The specific parameters and general
request properties that are applicable are protocol specific.
The following methods are used to access the header fields and the contents after
the connection is made to the remote object:

* getContent
* getHeaderField
* getInputStream
* getOutputStream
Certain header fields are accessed frequently. The methods:
* getContentEncoding
* getContentLength
* getContentType
* getDate
* getExpiration
* getLastModified

provide convenient access to these fields. The getContentType method is used by


the getContent method to determine the type of the remote object; subclasses may
find it convenient to override the getContentType method.
In the common case, all of the pre-connection parameters and general request
properties can be ignored: the pre-connection parameters and request properties
default to sensible values. For most clients of this interface, there are only two
interesting methods: getInputStream and getObject, which are mirrored in the URL
class by convenience methods.

More information on the request properties and header fields of an http connection
can be found at:
http://www.w3.org/hypertext/WWW/Protocols/HTTP1.0/draft-ietf-http-spec.html

Basic Java 126


.

TCP Socket Basics

Sockets were originally developed at the University of California at Berkeley as a tool


to easily accomplish network programming. Originally part of UNIX operating
systems, the concept of sockets has been incorporated into a wide variety of
operating environments, including Java.

What is a Socket?
A socket is a handle to a communications link over the network with another
application. A TCP socket is one that utilizes the TCP protocol, inheriting the
behavior of that transport protocol. Four pieces of information are needed to create a
TCP socket:

• The local system's IP address


• The TCP port number which the local application is using
• The remote system's IP address
• The TCP port number to which the remote application is responding

Sockets are often used in client-server applications: A centralized service waits for
various remote machines to request specific resources, handling each request as it
arrives. In order for clients to know how to communicate with the server, standard
application protocols are assigned well-known ports. On UNIX operating systems,
ports below 1024 can only be bound by applications with super-user (for example,
root) privileges, and thus for control, these well-known ports lie within this range, by
convention. Some well known ports are shown in the following table.

Well-known TCP ports and services

Port Service
21 FTP
23 Telnet
25 SMTP (Internet Mail Transfer)
79 Finger
80 HTTP
For many application protocols, you can merely use the Telnet application to connect
to the service port and then manually emulate a client. This may help you understand
how client-server communications work.
Client applications must also obtain, or bind, a port to establish a socket connection.
Because the client initiates the communication with the server, such a port number
could conveniently be assigned at runtime. Client applications are usually run by
normal, unprivileged users on UNIX systems, and thus these ports are allocated from
the range above 1024. This convention has held when migrated to other operating
systems, and client applications are generally given a dynamically-allocated port
above 1024.

Because no two applications can bind the same port on the same machine
simultaneously, a socket uniquely identifies a communications link. Realize that a
server may respond to two clients on the same port, since the clients will be on

Basic Java 127


.
different systems and/or different ports; the uniqueness of the link's characteristics
are preserved.

JAVA TCP SOCKET CLASSES

Java has a number of classes, which allow you to create socket-based network
applications. The two classes you use include java.net.Socket and
java.net.ServerSocket.

THE SERVERSOCKET CLASS

public class ServerSocket extends Object

This class implements server sockets. A server socket waits for requests to come in
over the network. It performs some operation based on that request, and then
possibly returns a result to the requester.
The actual work of the server socket is performed by an instance of the SocketImpl
class. An application can change the socket factory that creates the socket
implementation to configure itself to create sockets appropriate to the local firewall.

Example for ServerSocket

ServerExample.java

import java.io.*;
import java.net.*;
import java.util.Date;

public class ServerExample


{
public static void main(String args[])
{
ServerSocket server = null;
Socket socket = null;
BufferedOutputStream send = null;
try
{
server = new ServerSocket(3000);
System.out.println("server started");
while(true)
{
socket = server.accept();
send = new
BufferedOutputStream(socket.getOutputStream());
String date = (new Date()).toString();
byte data[] = new byte[date.length()];
data = date.getBytes();
send.write(data,0,data.length);
send.flush();
System.out.println("data flushed");
send.close();
socket.close();
}
}

Basic Java 128


.
catch(Exception err) {
System.out.println("Exception in transferring data to
client");
}
}
}

THE SOCKET CLASS

This class implements client sockets (also called just "sockets"). A socket is an
endpoint for communication between two machines. The actual work of the socket is
performed by an instance of the SocketImpl class. An application, by changing the
socket factory that creates the socket implementation, can configure itself to create
sockets appropriate to the local firewall.

Example for Socket

import java.io.*;
import java.net.*;

public class ClientExample {


public static void main(String args[]) {
Socket socket = null;
BufferedInputStream receive = null;
if(args.length == 0){
System.out.println("Usage : java ClientExample <server IP
address>");
System.exit(0);
}
String ser_address = args[0];
try {
socket = new Socket(InetAddress.getByName(ser_address),3000);
receive = new BufferedInputStream(socket.getInputStream());
System.out.println("socket created");
byte data[] = new byte[100];
receive.read(data,0,data.length);
String date = new String(data);
System.out.println("Date from server : "+date);
receive.close();
socket.close();
} catch(Exception err){
System.out.println("Exception in accessing file");
}
}
}

Overview of UDP Messaging


Programming with UDP has significant ramifications. Understanding these factors will
inform your network programming. UDP is a good choice for applications in which
communications can be separated into discrete messages, where a single query
from a client invokes a single response from a server. Time-dependent data is
particularly suited to UDP. UDP requires much less overhead, but the burden of

Basic Java 129


.
engineering any necessary reliability into the system is your responsibility. For
instance, if clients never receive responses to their queries—perfectly possible and
legitimate with UDP—you might want to program the clients to retransmit the request
or perhaps display an informative message indicating communication difficulties.

UDP Socket Characteristics

UDP is described as unreliable, connectionless, and message-oriented. A common


analogy that elucidates UDP is that of communicating with postcards. A dialog with
UDP must be quanticized into small messages that fit within a small packet of a
specific size, although some packets can hold more data than others. When you
send out a message, you can never be certain that you will receive a return
message. Unless you do receive a return message, you have no idea if your
message was received—your message could have been lost en route, the recipient’s
confirmation could have been lost, or the recipient might be ignoring your message.

The postcards you will be exchanging between network programs are referred to as
datagrams. Within a datagram, you can store an array of bytes. A receiving
application can extract this array and decode your message, possibly sending a
return datagram response. As with TCP, you will program in UDP using the socket
programming abstraction. However, UDP sockets are very different from TCP
sockets. Extending the analogy, UDP sockets are much like creating a mailbox. A
mailbox is identified by your address, but you don't construct a new one for each
person to whom you will be sending a message. Instead, you place an address on
the postcard that indicates to whom the message is intended. You place the postcard
in the mailbox and it is (eventually) sent on its way.

When receiving a message, you could potentially wait forever until one arrives in your
mailbox. Once one does, you can read the postcard. Meta-information appears on
the postcard that identifies the sender through the return address. As the previous
analogies suggest, UDP programming involves the following general tasks:
• Creating an appropriately addressed datagram to send.
• Setting up a socket to send and receive datagrams for a particular
application.
• Inserting datagrams into a socket for transmission.
• Waiting to receive datagrams from a socket.
• Decoding a datagram to extract the message, its recipient, and other meta-
information.

Java UDP Classes


The java.net package has the tools that are necessary to perform UDP
communications. For working with datagrams, Java provides the DatagramPacket
and DatagramSocket classes. When receiving a UDP datagram, you also use the
DatagramPacket class to read the data, sender, and meta-information.

THE DATAGRAMPACKET CLASS

This class represents a datagram packet. Datagram packets are used to implement a
connectionless packet delivery service. Each message is routed from one machine to
another based solely on information contained within that packet. Multiple packets
sent from one machine to another might be routed differently, and might arrive in any
order.

Basic Java 130


.

Example for DatagramPacket

import java.net.*;
import java.io.*;

public class DatagramClient


{
public static void main(String args[])
{
if(args.length == 0)
{
System.out.println("Usage : java DatagramClient <server
address>");
System.exit(0);
}
String address = args[0];
DatagramPacket dgp = null;
DatagramSocket dgs = null;
byte receive[] = new byte[50];
try
{
dgs = new
DatagramSocket(5000,InetAddress.getByName(address));
dgp = new DatagramPacket(receive,receive.length);
dgs.receive(dgp);
System.out.println("data received : "+(new
String(receive)));
dgs.close();
}
catch(Exception err) {
System.out.println("Exception in client");
}
}
}

THE DATAGRAMSOCKET CLASS

This class represents a socket for sending and receiving datagram packets. A
datagram socket is the sending or receiving point for a connectionless packet
delivery service. Each packet sent or received on a datagram socket is individually
addressed and routed. Multiple packets sent from one machine to another may be
routed differently, and may arrive in any order.

Basic Java 131


.
CHAPTER – 8: Java Database Connectivity
JDBCTM - Connecting Java and Databases
Java Database Connectivity is a standard SQL database access interface,
providing uniform access to a wide range of relational databases. It also provides
a common base on which higher-level tools and interfaces can be built. This
comes with an "ODBC Bridge". The Bridge is a library which implements JDBC in
terms of the ODBC standard C API.

What Is JDBCTM?
JDBCTM is a JavaTM API for executing SQL statements. (As a point of interest, JDBC
is a trademarked name and is not an acronym; nevertheless, JDBC is often thought
of as standing for "Java Database Connectivity".) It consists of a set of classes and
interfaces written in the Java programming language. JDBC provides a standard API
for tool/database developers and makes it possible to write database applications
using a pure Java API.

Using JDBC, it is easy to send SQL statements to virtually any relational database. In
other words, with the JDBC API, it isn't necessary to write one program to access a
Sybase database, another program to access an Oracle database, another program
to access an Informix database, and so on. One can write a single program using the
JDBC API, and the program will be able to send SQL statements to the appropriate
database. And, with an application written in the Java programming language, one
also doesn't have to worry about writing different applications to run on different
platforms. The combination of Java and JDBC lets a programmer write it once and
run it anywhere.

Java, being robust, secure, easy to use, easy to understand, and automatically
downloadable on a network, is an excellent language basis for database applications.
What is needed is a way for Java applications to talk to a variety of different
databases. JDBC is the mechanism for doing this.

JDBC extends what can be done in Java. For example, with Java and the JDBC API,
it is possible to publish a web page containing an applet that uses information
obtained from a remote database. Or an enterprise can use JDBC to connect all its
employees (even if they are using a conglomeration of Windows, Macintosh, and
UNIX machines) to one or more internal databases via an intranet. With more and
more programmers using the Java programming language, the need for easy
database access from Java is continuing to grow.

MIS managers like the combination of Java and JDBC because it makes
disseminating information easy and economical. Businesses can continue to use
their installed databases and access information easily even if it is stored on different
database management systems. Development time for new applications is short.
Installation and version control are greatly simplified. A programmer can write an
application or an update once, put it on the server, and everybody has access to the
latest version. And for businesses selling information services, Java and JDBC offer
a better way of getting out information updates to external customers.

Basic Java 132


.
What Does JDBC Do?
Simply put, JDBC makes it possible to do three things:

• establish a connection with a database


• send SQL statements
• process the results.

The following code fragment gives a basic example of these three steps:
Connection con = DriverManager.getConnection (
"jdbc:odbc:wombat", "login", "password");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (rs.next()) {
int x = getInt("a");
String s = getString("b");
float f = getFloat("c");
}

JDBC Is a Low-level API and a Base for Higher-level APIs


JDBC is a "low-level" interface, which means that it is used to invoke (or "call") SQL
commands directly. It works very well in this capacity and is easier to use than other
database connectivity APIs, but it was designed also to be a base upon which to
build higher-level interfaces and tools. A higher-level interface is "user-friendly," using
a more understandable or more convenient API that is translated behind the scenes
into a low-level interface such as JDBC. At the time of this writing, two kinds of
higher-level APIs are under development on top of JDBC:
3. an embedded SQL for Java. At least one vendor plans to build this. DBMSs
implement SQL, a language designed specifically for use with databases.
JDBC requires that the SQL statements be passed as Strings to Java
methods. An embedded SQL preprocessor allows a programmer to instead
mix SQL statements directly with Java: for example, a Java variable can be
used in a SQL statement to receive or provide SQL values. The embedded
SQL preprocessor then translates this Java/SQL mix into Java with JDBC
calls.
4. a direct mapping of relational database tables to Java classes. JavaSoft and
others have announced plans to implement this. In this "object/relational"
mapping, each row of the table becomes an instance of that class, and each
column value corresponds to an attribute of that instance. Programmers can
then operate directly on Java objects; the required SQL calls to fetch and
store data are automatically generated "beneath the covers." More
sophisticated mappings are also provided, for example, where rows of
multiple tables are combined in a Java class.

As interest in JDBC has grown, more developers have been working on JDBC-based
tools to make building programs easier, as well. Programmers have also been writing
applications that make accessing a database easier for the end user. For example,
an application might present a menu of database tasks from which to choose. After a
task is selected, the application presents prompts and blanks for filling in information
needed to carry out the selected task. With the requested input typed in, the
application then automatically invokes the necessary SQL commands. With the help
of such an application, users can perform database tasks even when they have little
or no knowledge of SQL syntax.

Basic Java 133


.

JDBC versus ODBC and other APIs


At this point, Microsoft's ODBC (Open DataBase Connectivity) API is probably the
most widely used programming interface for accessing relational databases. It offers
the ability to connect to almost all databases on almost all platforms. So why not just
use ODBC from Java?

The answer is that you can use ODBC from Java, but this is best done with the help
of JDBC in the form of the JDBC-ODBC Bridge, which we will cover shortly. The
question now becomes, "Why do you need JDBC?" There are several answers to
this question:

1. ODBC is not appropriate for direct use from Java because it uses a C
interface. Calls from Java to native C code have a number of drawbacks in
the security, implementation, robustness, and automatic portability of
applications.
2. A literal translation of the ODBC C API into a Java API would not be
desirable. For example, Java has no pointers, and ODBC makes copious use
of them, including the notoriously error-prone generic pointer "void *". You
can think of JDBC as ODBC translated into an object-oriented interface that is
natural for Java programmers.
3. ODBC is hard to learn. It mixes simple and advanced features together, and it
has complex options even for simple queries. JDBC, on the other hand, was
designed to keep simple things simple while allowing more advanced
capabilities where required.
4. A Java API like JDBC is needed in order to enable a "pure Java" solution.
When ODBC is used, the ODBC driver manager and drivers must be
manually installed on every client machine. When the JDBC driver is written
completely in Java, however, JDBC code is automatically installable, portable,
and secure on all Java platforms from network computers to mainframes.

In summary, the JDBC API is a natural Java interface to the basic SQL abstractions
and concepts. It builds on ODBC rather than starting from scratch, so programmers
familiar with ODBC will find it very easy to learn JDBC. JDBC retains the basic
design features of ODBC; in fact, both interfaces are based on the X/Open SQL CLI
(Call Level Interface). The big difference is that JDBC builds on and reinforces the
style and virtues of Java, and, of course, it is easy to use.

More recently, Microsoft has introduced new APIs beyond ODBC: RDO, ADO, and
OLE DB. These designs move in the same direction as JDBC in many ways, that is,
in being an object-oriented database interface based on classes that can be
implemented on ODBC. However, we did not see compelling functionality in any of
these interfaces to make them an alternative basis to ODBC, especially with the
ODBC driver market well-established. Mostly they represent a thin veneer on ODBC.
This is not to say that JDBC does not need to evolve from the initial release;
however, we feel that most new functionality belongs in higher- level APIs such as
the object/relational mappings and embedded SQL mentioned in the previous
section.

Basic Java 134


.

Two-tier and Three-tier Models

The JDBC API supports both two-tier and three-tier models for database access.
In the two-tier model, a Java applet or application talks directly to the database. This
requires a JDBC driver that can communicate with the particular database
management system being accessed. A user's SQL statements are delivered to the
database, and the results of those statements are sent back to the user. The
database may be located on another machine to which the user is connected via a
network. This is referred to as a client/server configuration, with the user's machine
as the client, and the machine housing the database as the server. The network can
be an intranet, which, for example, connects employees within a corporation, or it can
be the Internet.

Java
Application
Client Machine
JDBC

DBMS Proprietary Protocol

DBMS Database Server

In the three-tier model, commands are sent to a "middle tier" of services, which then
send SQL statements to the database. The database processes the SQL statements
and sends the results back to the middle tier, which then sends them to the user. MIS
directors find the three-tier model very attractive because the middle tier makes it
possible to maintain control over access and the kinds of updates that can be made
to corporate data. Another advantage is that when there is a middle tier, the user can
employ an easy-to-use higher-level API which is translated by the middle tier into the
appropriate low-level calls. Finally, in many cases the three-tier architecture can
provide performance advantages.

Java Applet or
HTML Browser

Application
Server (Java)

JDBC

DBMS

Basic Java 135


.

Until now the middle tier has typically been written in languages such as C or C++,
which offer fast performance. However, with the introduction of optimizing compilers
that translate Java bytecode into efficient machine-specific code, it is becoming
practical to implement the middle tier in Java. This is a big plus, making it possible to
take advantage of Java's robustness, multithreading, and security features. JDBC is
important to allow database access from a Java middle tier.

SQL Conformance
Structured Query Language (SQL) is the standard language for accessing relational
databases. One area of difficulty is that although most DBMSs (DataBase
Management Systems) use a standard form of SQL for basic functionality, they do
not conform to the more recently-defined standard SQL syntax or semantics for more
advanced functionality. For example, not all databases support stored procedures or
outer joins, and those that do are not consistent with each other. It is hoped that the
portion of SQL that is truly standard will expand to include more and more
functionality. In the meantime, however, the JDBC API must support SQL as it is.

One way the JDBC API deals with this problem is to allow any query string to be
passed through to an underlying DBMS driver. This means that an application is free
to use as much SQL functionality as desired, but it runs the risk of receiving an error
on some DBMSs. In fact, an application query need not even be SQL, or it may be a
specialized derivative of SQL designed for specific DBMSs (for document or image
queries, for example).

A second way JDBC deals with problems of SQL conformance is to provide ODBC-
style escape clauses.
The escape syntax provides a standard JDBC syntax for several of the more
common areas of SQL divergence. For example, there are escapes for date literals
and for stored procedure calls.

For complex applications, JDBC deals with SQL conformance in a third way. It
provides descriptive information about the DBMS by means of the
DatabaseMetaData interface so that applications can adapt to the requirements and
capabilities of each DBMS.

Because the JDBC API will be used as a base API for developing higher-level
database access tools and APIs, it also has to address the problem of conformance
for anything built on it. The designation "JDBC COMPLIANTTM" was created to set a
standard level of JDBC functionality on which users can rely. In order to use this
designation, a driver must support at least ANSI SQL-2 Entry Level. (ANSI SQL-2
refers to the standards adopted by the American National Standards Institute in
1992. Entry Level refers to a specific list of SQL capabilities.) Driver developers can
ascertain that their drivers meet these standards by using the test suite available with
the JDBC API.

The "JDBC COMPLIANTTM" designation indicates that a vendor's JDBC


implementation has passed the conformance tests provided by JavaSoft. These
conformance tests check for the existence of all of the classes and methods defined
in the JDBC API, and check as much as possible that the SQL Entry Level
functionality is available. Such tests are not exhaustive, of course, and JavaSoft is
not currently branding vendor implementations, but this compliance definition

Basic Java 136


.
provides some degree of confidence in a JDBC implementation. With wider and
wider acceptance of the JDBC API by database vendors, connectivity vendors,
Internet service vendors, and application writers, JDBC is quickly becoming the
standard for Java database access.

JavaSoft Framework
JavaSoft provides three JDBC product components as part of the Java Development
Kit (JDK):
• the JDBC driver manager,
• the JDBC driver test suite, and
• the JDBC-ODBC bridge.
The JDBC driver manager is the backbone of the JDBC architecture. It actually is
quite small and simple; its primary function is to connect Java applications to the
correct JDBC driver and then get out of the way.

The JDBC driver test suite provides some confidence that JDBC drivers will run your
program. Only drivers that pass the JDBC driver test suite can be designated JDBC
COMPLIANTTM.

The JDBC-ODBC bridge allows ODBC drivers to be used as JDBC drivers. It was
implemented as a way to get JDBC off the ground quickly, and long term will provide
a way to access some of the less popular DBMSs if JDBC drivers are not
implemented for them.

JDBC Driver Types


The JDBC drivers that we are aware of at this time fit into one of four categories:
1. JDBC-ODBC bridge plus ODBC driver: The JavaSoft bridge product
provides JDBC access via ODBC drivers. Note that ODBC binary code, and
in many cases database client code, must be loaded on each client machine
that uses this driver. As a result, this kind of driver is most appropriate on a
corporate network where client installations are not a major problem, or for
application server code written in Java in a three-tier architecture.
2. Native-API partly-Java driver: This kind of driver converts JDBC calls into
calls on the client API for Oracle, Sybase, Informix, DB2, or other DBMS.
Note that, like the bridge driver, this style of driver requires that some binary
code be loaded on each client machine.
3. JDBC-Net pure Java driver: This driver translates JDBC calls into a DBMS-
independent net protocol which is then translated to a DBMS protocol by a
server. This net server middleware is able to connect its pure Java clients to
many different databases. The specific protocol used depends on the vendor.
In general, this is the most flexible JDBC alternative. It is likely that all
vendors of this solution will provide products suitable for Intranet use. In order
for these products to also support Internet access, they must handle the
additional requirements for security, access through firewalls, and so on, that
the Web imposes. Several vendors are adding JDBC drivers to their existing
database middleware products.
4. Native-protocol pure Java driver: This kind of driver converts JDBC calls
into the network protcol used by DBMSs directly. This allows a direct call from
the client machine to the DBMS server and is a practical solution for Intranet
access. Since many of these protocols are proprietary, the database vendors
themselves will be the primary source, and several database vendors have
these in progress.

Basic Java 137


.
Eventually, we expect that driver categories 3 and 4 will be the preferred way to
access databases from JDBC. Driver categories 1 and 2 are interim solutions where
direct pure Java drivers are not yet available. There are possible variations on
categories 1 and 2 (not shown in the table below) that require a connector, but these
are generally less desirable solutions. Categories 3 and 4 offer all the advantages of
Java, including automatic installation (for example, downloading the JDBC driver with
an applet that uses it).
The following chart shows the four categories and their properties:

DRIVER CATEGORY ALL JAVA? NET PROTOCOL


1 – JDBC-OCBC Bridge No Direct
2 – Native API as basis No Direct
3 – JDBC-Net Yes Requires Connector
4 – Native protocol as basis Yes Direct

Obtaining JDBC Drivers


The first vendors with Category 3 drivers available were SCO, Open Horizon,
Visigenic, and WebLogic. JavaSoft and Intersolv, a leading database connectivity
vendor, worked together to produce the JDBC-ODBC Bridge and the JDBC Driver
Test Suite.

Connection
A Connection object represents a connection with a database. A connection session
includes the SQL statements that are executed and the results that are returned over
that connection. A single application can have one or more connections with a single
database, or it can have connections with many different databases.

Opening a Connection
The standard way to establish a connection with a database is to call the method
DriverManager.getConnection. This method takes a string containing a URL. The
DriverManager class, referred to as the JDBC management layer, attempts to locate
a driver than can connect to the database represented by that URL. The
DriverManager class maintains a list of registered Driver classes, and when the
method getConnection is called, it checks with each driver in the list until it finds one
that can connect to the database specified in the URL. The Driver method connect
uses this URL to actually establish the connection.

A user can bypass the JDBC management layer and call Driver methods directly.
This could be useful in the rare case that two drivers can connect to a database and
the user wants to explicitly select a particular driver. Normally, however, it is much
easier to just let the DriverManager class handle opening a connection.
The following code exemplifies opening a connection to a database located at the
URL "jdbc:odbc:wombat" with a user ID of "oboy" and "12Java" as the password :
String url = "jdbc:odbc:wombat";
Connection con = DriverManager.getConnection(url, "oboy", "12Java");

Basic Java 138


.
URLs in General Use

Since URLs often cause some confusion, we will first give a brief explanation of
URLs in general and then go on to a discussion of JDBC URLs.
A URL (Uniform Resource Locator) gives information for locating a resource on the
Internet. It can be thought of as an address.

The first part of a URL specifies the protocol used to access information, and it is
always followed by a colon. Some common protocols are "ftp", which specifies "file
transfer protocol," and "http," which specifies "hypertext transfer protocol." If the
protocol is "file," it indicates that the resource is in a local file system rather than on
the Internet.

ftp://javasoft.com/docs/JDK-1_apidocs.zip
http://java.sun.com/products/JDK/CurrentRelease
file:/home/haroldw/docs/tutorial.html
The rest of a URL, everything after the first colon, gives information about where the
data source is located. If the protocol is file, the rest of the URL is the path to a file.
For the protocols ftp and http, the rest of the URL identifies the host and may
optionally give a path to a more specific site. For example, below is the URL for the
JavaSoft home page. This URL identifies only the host:
http://www.javasoft.com

By navigating from this home page, one can go to many other pages, one of which is
the JDBC home page. The URL for the JDBC home page is more specific and looks
like this:

http://www.javasoft.com/products/jdbc

JDBC URLs

A JDBC URL provides a way of identifying a database so that the appropriate driver
will recognize it and establish a connection with it. Driver writers are the ones who
actually determine what the JDBC URL that identifies their particular driver will be.
Users do not need to worry about how to form a JDBC URL; they simply use the URL
supplied with the drivers they are using. JDBC's role is to recommend some
conventions for driver writers to follow in structuring their JDBC URLs.
Since JDBC URLs are used with various kinds of drivers, the conventions are of
necessity very flexible. First, they allow different drivers to use different schemes for
naming databases. The odbc subprotocol, for example, lets the URL contain attribute
values (but does not require them).

Second, JDBC URLs allow driver writers to encode all necessary connection
information within them. This makes it possible, for example, for an applet that wants
to talk to a given database to open the database connection without requiring the
user to do any system administration chores.

Third, JDBC URLs allow a level of indirection. This means that the JDBC URL may
refer to a logical host or database name that is dynamically translated to the actual
name by a network naming system. This allows system administrators to avoid
specifying particular hosts as part of the JDBC name. There are a number of different

Basic Java 139


.
network name services (such as DNS, NIS, and DCE), and there is no restriction
about which ones can be used.

The standard syntax for JDBC URLs is shown below. It has three parts, which are
separated by colons:

jdbc:<subprotocol>:<subname>

The three parts of a JDBC URL are broken down as follows:


5. jdbc-the protocol. The protocol in a JDBC URL is always jdbc.
6. <subprotocol>-the name of the driver or the name of a database connectivity
mechanism, which may be supported by one or more drivers. A prominent
example of a subprotocol name is "odbc", which has been reserved for URLs
that specify ODBC-style data source names. For example, to access a
database through a JDBC-ODBC bridge, one might use a URL such as the
following:
jdbc:odbc:fred

In this example, the subprotocol is "odbc", and the subname "fred" is a local
ODBC data source.
If one wants to use a network name service (so that the database
name in the JDBC URL does not have to be its actual name), the
naming service can be the subprotocol. So, for example, one
might have a URL like:
jdbc:dcenaming:accounts-payable

In this example, the URL specifies that the local DCE naming service should
resolve the database name "accounts-payable" into a more specific name
that can be used to connect to the real database.

7. <subname>-a way to identify the database. The subname can vary,


depending on the subprotocol, and it can have a subsubname with any
internal syntax the driver writer chooses. The point of a subname is to give
enough information to locate the database. In the previous example, "fred" is
enough because ODBC provides the remainder of the information. A
database on a remote server requires more information, however. If the
database is to be accessed over the Internet, for example, the network
address should be included in the JDBC URL as part of the subname and
should follow the standard URL naming convention of
//hostname:port/subsubname

Supposing that "dbnet" is a protocol for connecting to a host on the Internet, a


JDBC URL might look like this:

jdbc:dbnet://wombat:356/fred

The "odbc" Subprotocol


The subprotocol odbc is a special case. It has been reserved for URLs that specify
ODBC-style data source names and has the special feature of allowing any number
of attribute values to be specified after the subname (the data source name). The full
syntax for the odbc subprotocol is:
jdbc:odbc:<data-source-name>[;<attribute-name>=<attribute-value>]*

Basic Java 140


.
Thus all of the following are valid jdbc:odbc names:
jdbc:odbc:qeor7
jdbc:odbc:wombat
jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER
jdbc:odbc:qeora;UID=kgh;PWD=fooey

Registering Subprotocols
A driver developer can reserve a name to be used as the subprotocol in a JDBC
URL. When the DriverManager class presents this name to its list of registered
drivers, the driver for which this name is reserved should recognize it and establish a
connection to the database it identifies. For example, odbc is reserved for the JDBC-
ODBC Bridge. If there were, for another example, a Miracle Corporation, it might
want to register "miracle" as the subprotocol for the JDBC driver that connects to its
Miracle DBMS so that no one else would use that name.
JavaSoft is acting as an informal registry for JDBC subprotocol names. To register a
subprotocol name, send email to:
jdbc@wombat.eng.sun.com

Sending SQL Statements


Once a connection is established, it is used to pass SQL statements to its underlying
database. JDBC does not put any restrictions on the kinds of SQL statements that
can be sent; this provides a great deal of flexibility, allowing the use of database-
specific statements or even non-SQL statements. It requires, however, that the user
be responsible for making sure that the underlying database can process the SQL
statements being sent and suffer the consequences if it cannot. For example, an
application that tries to send a stored procedure call to a DBMS that does not support
stored procedures will be unsuccessful and generate an exception. JDBC requires
that a driver provide at least ANSI SQL-2 Entry Level capabilities in order to be
designated JDBC COMPLIANTTM. This means that users can count on at least this
standard level of functionality.

JDBC provides three classes for sending SQL statements to the database, and three
methods in the Connection interface create instances of these classes. These
classes and the methods which create them are listed below:
5. Statement- -created by the method createStatement. A Statement object is
used for sending simple SQL statements.
6. PreparedStatement- -created by the method prepareStatement. A
PreparedStatement object is used for SQL statements that take one or more
parameters as input arguments (IN parameters). PreparedStatement has a
group of methods which set the value of IN parameters, which are sent to the
database when the statement is executed. Instances of PreparedStatement
extend Statement and therefore include Statement methods. A
PreparedStatement object has the potential to be more efficient than a
Statement object because it has been pre-compiled and stored for future use.
7. CallableStatement- -created by the method prepareCall. CallableStatement
objects are used to execute SQL stored procedures- -a group of SQL
statements that is called by name, much like invoking a function. A
CallableStatement object inherits methods for handling IN parameters from
PreparedStatement; it adds methods for handling OUT and INOUT
parameters.
The following list gives a quick way to determine which Connection method is
appropriate for creating different types of SQL statements:

Basic Java 141


.
createStatement method is used for

• simple SQL statements (no parameters)

prepareStatement method is used for

• SQL statements with one or more IN parameters

• simple SQL statements that are executed frequently

prepareCall method is used for

• call to stored procedures

Transactions
A transaction consists of one or more statements that have been executed,
completed, and then either committed or rolled back. When the method commit or
rollback is called, the current transaction ends and another one begins.

A new connection is in auto-commit mode by default, meaning that when a statement


is completed, the method commit will be called on that statement automatically. In
this case, since each statement is committed individually, a transaction consists of
only one statement. If auto-commit mode has been disabled, a transaction will not
terminate until the method commit or rollback is called explicitly, so it will include all
the statements that have been executed since the last invocation of the commit or
rollback method. In this second case, all the statements in the transaction are
committed or rolled back as a group.

The method commit makes permanent any changes an SQL statement makes to a
database, and it also releases any locks held by the transaction. The method rollback
will discard those changes.

Sometimes a user doesn't want one change to take effect unless another one does
also. This can be accomplished by disabling auto-commit and grouping both updates
into one transaction. If both updates are successful, then the commit method is
called, making the effects of both updates permanent; if one fails or both fail, then the
rollback method is called, restoring the values that existed before the updates were
executed.

Most JDBC drivers will support transactions. In fact, a JDBC-compliant driver must
support transactions. DatabaseMetaData supplies information describing the level of
transaction support a DBMS provides.

Transaction Isolation Levels


If a DBMS supports transaction processing, it will have some way of managing
potential conflicts that can arise when two transactions are operating on a database
at the same time. A user can specify a transaction isolation level to indicate what
level of care the DBMS should exercise in resolving potential conflicts. For example,
what happens when one transaction changes a value and a second transaction
reads that value before the change has been committed or rolled back? Should that
be allowed, given that the changed value read by the second transaction will be
invalid if the first transaction is rolled back? A JDBC user can instruct the DBMS to

Basic Java 142


.
allow a value to be read before it has been committed ("dirty reads") with the
following code, where con is the current connection:
con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);

The higher the transaction isolation level, the more care is taken to avoid conflicts.
The Connection interface defines five levels, with the lowest specifying that
transactions are not supported at all and the highest specifying that while one
transaction is operating on a database, no other transactions may make any changes
to the data read by that transaction. Typically, the higher the level of isolation, the
slower the application executes (due to increased locking overhead and decreased
concurrency between users). The developer must balance the need for performance
with the need for data consistency when making a decision about what isolation level
to use. Of course, the level that can actually be supported depends on the
capabilities of the underlying DBMS.

When a new Connection object is created, its transaction isolation level depends on
the driver, but normally it is the default for the underlying database. A user may call
the method setIsolationLevel to change the transaction isolation level, and the new
level will be in effect for the rest of the connection session. To change the transaction
isolation level for just one transaction, one needs to set it before the transaction
begins and reset it after the transaction terminates. Changing the transaction
isolation level during a transaction is not recommended, for it will trigger an
immediate call to the method commit, causing any changes up to that point to be
made permanent.

DriverManager

The DriverManager class is the management layer of JDBC, working between the
user and the drivers. It keeps track of the drivers that are available and handles
establishing a connection between a database and the appropriate driver. In addition,
the DriverManager class attends to things like driver login time limits and the printing
of log and tracing messages.

For simple applications, the only method in this class that a general programmer
needs to use directly is DriverManager.getConnection. As its name implies, this
method establishes a connection to a database. JDBC allows the user to call the
DriverManager methods getDriver, getDrivers, and registerDriver as well as the
Driver method connect, but in most cases it is better to let the DriverManager class
manage the details of establishing a connection.

Keeping Track of Available Drivers

The DriverManager class maintains a list of Driver classes that have registered
themselves by calling the method DriverManager.registerDriver. All Driver classes
should be written with a static section that creates an instance of the class and then
registers it with the DriverManager class when it is loaded. Thus, a user would not
normally call DriverManager.registerDriver directly; it should be called automatically
by a driver when it is loaded. A Driver class is loaded, and therefore automatically
registered with the DriverManager, in two ways:
8. By calling the method Class.forName. This explicitly loads the driver class.
Since it does not depend on any external setup, this way of loading a driver is
recommended. The following code loads the class acme.db.Driver:

Basic Java 143


.
Class.forName("acme.db.Driver");
If acme.db.Driver has been written so that loading it causes an instance to be
created and also calls DriverManager.registerDriver with that instance as the
parameter (as it should do), then it is in the DriverManager's list of drivers and
available for creating a connection.
9. By adding the driver to the java.lang.System property jdbc.drivers. This is a
list of driver classnames, separated by colons, that the DriverManager class
loads. When the DriverManager class is intialized, it looks for the system
property jdbc.drivers, and if the user has entered one or more drivers, the
DriverManager class attempts to load them. The following code illustrates
how a programmer might enter three driver classes in ~/.hotjava/properties
(HotJava loads these into the system properties list on startup):
jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.test.ourDriver;

The first call to a DriverManager method will automatically cause these driver classes
to be loaded.

Note that this second way of loading drivers requires a preset environment that is
persistent. If there is any doubt about that being the case, it is safer to call the
method Class.forName to explicitly load each driver. This is also the method to use to
bring in a particular driver since once the DriverManager class has been initialized, it
will never recheck the jdbc.drivers property list.

In both of the cases listed above, it is the responsibility of the newly-loaded Driver
class to register itself by calling DriverManager.registerDriver. As mentioned above,
this should be done automatically when the class is loaded.

For security reasons, the JDBC management layer will keep track of which class
loader provided which driver. Then when the DriverManager class is opening a
connection, it will use only drivers that come from the local file system or from the
same class loader as the code issuing the request for a connection.

Establishing a Connection
Once the Driver classes have been loaded and registered with the DriverManager
class, they are available for establishing a connection with a database. When a
request for a connection is made with a call to the DriverManager.getConnection
method, the DriverManager tests each driver in turn to see if it can establish a
connection.

It may sometimes be the case that more than one JDBC driver is capable of
connecting to a given URL. For example, when connecting to a given remote
database, it might be possible to use a JDBC-ODBC bridge driver, a JDBC-to-
generic-network-protocol driver, or a driver supplied by the database vendor. In such
cases, the order in which the drivers are tested is significant because the
DriverManager will use the first driver it finds that can successfully connect to the
given URL.

First the DriverManager tries to use each of the drivers in the order they were
registered. (The drivers listed in jdbc.drivers are always registered first.) It will skip
any drivers which are untrusted code, unless they have been loaded from the same
source as the code that is trying to open the connection.

Basic Java 144


.
It tests the drivers by calling the method Driver.connect on each one in turn, passing
them the URL that the user originally passed to the method
DriverManager.getConnection. The first driver that recognizes the URL makes the
connection.

At first glance this may seem inefficient, but it requires only a few procedure calls and
string comparisons per connection since it is unlikely that dozens of drivers will be
loaded concurrently.

The following code is an example of all that is normally needed to set up a


connection with a driver such as a JDBC-ODBC bridge driver:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //loads the driver
String url = "jdbc:odbc:fred";
DriverManager.getConnection(url, "userID", "passwd");

Statement
A Statement object is used to send SQL statements to a database. There are
actually three kinds of Statement objects, all of which act as containers for executing
SQL statements on a given connection: Statement, PreparedStatement, which
inherits from Statement, and CallableStatement, which inherits from
PreparedStatement. They are specialized for sending particular types of SQL
statements: a Statement object is used to execute a simple SQL statement with no
parameters; a PreparedStatement object is used to execute a precompiled SQL
statement with or without IN parameters; and a CallableStatement object is used to
execute a call to a database stored procedure.

The Statement interface provides basic methods for executing statements and
retrieving results. The PreparedStatement interface adds methods for dealing with IN
parameters; CallableStatement adds methods for dealing with OUT parameters.

Creating Statement Objects


Once a connection to a particular database is established, that connection can be
used to send SQL statements. A Statement object is created with the Connection
method createStatement, as in the following code fragment:
Connection con = DriverManager.getConnection(url, "sunny", "");
Statement stmt = con.createStatement();
The SQL statement that will be sent to the database is supplied as the argument to
one of the methods for executing a Statement object:
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2);

Executing Statements Using Statement objects


The Statement interface provides three different methods for executing SQL
statements, executeQuery, executeUpdate, and execute. The one to use is
determined by what the SQL statement produces.
The method executeQuery is designed for statements that produce a single result
set, such as SELECT statements.

The method executeUpdate is used to execute INSERT, UPDATE, or DELETE


statements and also SQL DDL (Data Definition Language) statements like CREATE
TABLE and DROP TABLE. The effect of an INSERT, UPDATE, or DELETE

Basic Java 145


.
statement is a modification of one or more columns in zero or more rows in a table.
The return value of executeUpdate is an integer indicating the number of rows that
were affected (referred to as the update count). For statements such as CREATE
TABLE or DROP TABLE, which do not operate on rows, the return value of
executeUpdate is always zero.

The method execute is used to execute statements that return more than one result
set, more than one update count, or a combination of the two. Because it is an
advanced feature that most programmers will never need, it is explained in its own
section later in this overview.

All of the methods for executing statements close the calling Statement object's
current result set if there is one open. This means that one needs to complete any
processing of the current ResultSet object before re-executing a Statement object.
It should be noted that the PreparedStatement interface, which inherits all of the
methods in the Statement interface, has its own versions of the methods
executeQuery, executeUpdate and execute. Statement objects do not themselves
contain an SQL statement; therefore, one must be provided as the argument to the
Statement.execute methods. PreparedStatement objects do not supply an SQL
statement as a parameter to these methods because they already contain a
precompiled SQL statement. CallableStatement objects inherit the
PreparedStatement forms of these methods. Using a query parameter with the
PreparedStatement or CallableStatement versions of these methods will cause an
SQLException to be thrown.

Statement Completion
When a connection is in auto-commit mode, the statements being executed within it
are committed or rolled back when they are completed. A statement is considered
complete when it has been executed and all its results have been returned. For the
method executeQuery, which returns one result set, the statement is completed
when all the rows of the ResultSet object have been retrieved. For the method
executeUpdate, a statement is completed when it is executed. In the rare cases
where the method execute is called, however, a statement is not complete until all of
the result sets or update counts it generated have been retrieved.

Some DBMSs treat each statement in a stored procedure as a separate statement;


others treat the entire procedure as one compound statement. This difference
becomes important when auto-commit is enabled because it affects when the
method commit is called. In the first case, each statement is individually committed;
in the second, all are committed together.

Closing Statement Objects


Statement objects will be closed automatically by the Java garbage collector.
Nevertheless, it is recommended as good programming practice that they be closed
explicitly when they are no longer needed. This frees DBMS resources immediately
and helps avoid potential memory problems.

Basic Java 146


.

Using the Method execute

The execute method should be used only when it is possible that a statement may
return more than one ResultSet object, more than one update count, or a
combination of ResultSet objects and update counts. These multiple possibilities for
results, though rare, are possible when one is executing certain stored procedures or
dynamically executing an unknown SQL string (that is, unknown to the application
programmer at compile time). For example, a user might execute a stored procedure
and that stored procedure could perform an update, then a select, then an update,
then a select, and so on. Typically, someone using a stored procedure will know what
it returns.

Because the method execute handles the cases that are out of the ordinary, it is no
surprise that retrieving its results requires some special handling. For instance,
suppose it is known that a procedure returns two result sets. After using the method
execute to execute the procedure, one must call the method getResultSet to get the
first result set and then the appropriate getXXX methods to retrieve values from it. To
get the second result set, one needs to call getMoreResults and then getResultSet a
second time. If it is known that a procedure returns two update counts, the method
getUpdateCount is called first, followed by getMoreResults and a second call to
getUpdateCount.

Those cases where one does not know what will be returned present a more
complicated situation. The method execute returns true if the result is a ResultSet
object and false if it is a Java int. If it returns an int, that means that the result is either
an update count or that the statement executed was a DDL command. The first thing
to do after calling the method execute, is to call either getResultSet or
getUpdateCount. The method getResultSet is called to get what might be the first of
two or more ResultSet objects; the method getUpdateCount is called to get what
might be the first of two or more update counts.

When the result of an SQL statement is not a result set, the method getResultSet will
return null. This can mean that the result is an update count or that there are no more
results. The only way to find out what the null really means in this case is to call the
method getUpdateCount, which will return an integer. This integer will be the number
of rows affected by the calling statement or -1 to indicate either that the result is a
result set or that there are no results. If the method getResultSet has already
returned null, which means that the result is not a ResultSet object, then a return
value of -1 has to mean that there are no more results. In other words, there are no
results (or no more results) when the following is true:

((stmt.getResultSet() == null) && (stmt.getUpdateCount() == -1))

If one has called the method getResultSet and processed the ResultSet object it
returned, it is necessary to call the method getMoreResults to see if there is another
result set or update count. If getMoreResults returns true, then one needs to again
call getResultSet to actually retrieve the next result set. As already stated above, if
getResultSet returns null, one has to call getUpdateCount to find out whether null
means that the result is an update count or that there are no more results.
When getMoreResults returns false, it means that the SQL statement returned an
update count or that there are no more results. So one needs to call the method

Basic Java 147


.
getUpdateCount to find out which is the case. In this situation, there are no more
results when the following is true:
((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
The code below demonstrates one way to be sure that one has accessed all the
result sets and update counts generated by a call to the method execute:

stmt.execute(queryStringWithUnknownResults);
while (true) {
int rowCount = stmt.getUpdateCount();
if (rowCount > 0) { // this is an update count
System.out.println("Rows changed = " + count);
stmt.getMoreResults();
continue;
}
if (rowCount == 0) { // DDL command or 0 updates
System.out.println(" No rows changed or statement was DDL
command");
stmt.getMoreResults();
continue;
}

// if we have gotten this far, we have either a result set


// or no more results

ResultSet rs = stmt.getResultSet;
if (rs != null) {
. . . // use metadata to get info about result set columns
while (rs.next()) {
. . . // process results
stmt.getMoreResults();
continue;
}
break; // there are no more results

ResultSet
A ResultSet contains all of the rows which satisfied the conditions in an SQL
statement, and it provides access to the data in those rows through a set of get
methods that allow access to the various columns of the current row. The
ResultSet.next method is used to move to the next row of the ResultSet, making the
next row become the current row.

The general form of a result set is a table with column headings and the
corresponding values returned by a query. For example, if your query is SELECT a,
b, c FROM Table1, your result set will have the following form:
a b c
------ --------- -------
12345 Cupertino CA

83472 Redmond WA
83492 Boston MA

Basic Java 148


.

The following code fragment is an example of executing an SQL statement that will
return a collection of rows, with column 1 as an int, column 2 as a String, and column
3 as an array of bytes:

java.sql.Statement stmt = conn.createStatement();


ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (r.next())
{
// print the values for the current row.
int i = r.getInt("a");
String s = r.getString("b");
float f = r.getFloat("c");
System.out.println("ROW = " + i + " " + s + " " + f);
}

Rows and Cursors


A ResultSet maintains a cursor which points to its current row of data. The cursor
moves down one row each time the method next is called. Initially it is positioned
before the first row, so that the first call to next puts the cursor on the first row,
making it the current row. ResultSet rows are retrieved in sequence from the top row
down as the cursor moves down one row with each successive call to next.
A cursor remains valid until the ResultSet object or its parent Statement object is
closed.

In SQL, the cursor for a result table is named. If a database allows positioned
updates or positioned deletes, the name of the cursor needs to be supplied as a
parameter to the update or delete command. This cursor name can be obtained by
calling the method getCursorName.

Note that not all DBMSs support positioned update and delete. The
DatabaseMetaData.supportsPositionedDelete and supportsPositionedUpdate
methods can be used to discover whether a particular connection supports these
operations. When they are supported, the DBMS/driver must ensure that rows
selected are properly locked so that positioned updates do not result in update
anomalies or other concurrency problems.

Columns
The getXXX methods provide the means for retrieving column values from the
current row. Within each row, column values may be retrieved in any order, but for
maximum portability, one should retrieve values from left to right and read column
values only once.

Either the column name or the column number can be used to designate the column
from which to retrieve data. For example, if the second column of a ResultSet object
rs is named "title" and stores values as strings, either of the following will retrieve the
value stored in that column:
String s = rs.getString("title");
String s = rs.getString(2);

Basic Java 149


.
Note that columns are numbered from left to right starting with column 1. Also,
column names used as input to getXXX methods are case insensitive.
The option of using the column name was provided so that a user who specifies
column names in a query can use those same names as the arguments to getXXX
methods. If, on the other hand, the select statement does not specify column names
(as in "select * from table1" or in cases where a column is derived), column numbers
should be used. In such situations, there is no way for the user to know for sure what
the column names are.

In some cases, it is possible for a SQL query to return a result set that has more than
one column with the same name. If a column name is used as the parameter to a
getXXX method, getXXX will return the value of the first matching column name.
Thus, if there are multi0ple columns with the same name, one needs to use a column
index to be sure that the correct column value is retrieved. It may also be slightly
more efficient to use column numbers.

Information about the columns in a ResultSet is available by calling the method


ResultSet.getMetaData. The ResultSetMetaData object returned gives the number,
types, and properties of its ResultSet object's columns.
If the name of a column is known, but not its index, the method findColumn can be
used to find the column number.

Data Types and Conversions


For the getXXX methods, the JDBC driver attempts to convert the underlying data to
the specified Java type and then returns a suitable Java value. For example, if the
getXXX method is getString, and the data type of the data in the underlying database
is VARCHAR, the JDBC driver will convert VARCHAR to Java String. The return
value of getString will be a Java String object.

The following table shows which JDBC types a getXXX method is allowed to retrieve
and which JDBC types (generic SQL types) are recommended for it to retrieve. A
small x indicates a legal getXXX method for a particular data type; a large X indicates
the recommended getXXX method for a data type. For example, any getXXX method
except getBytes or getBinaryStream can be used to retrieve the value of a
LONGVARCHAR, but getAsciiStream or getUnicodeStream are recommended,
depending on which data type is being returned. The method getObject will return
any data type as a Java Object and is useful when the underlying data type is a
database-specific abstract type or when a generic application needs to be able to
accept any data type.

Use of ResultSet.getXXX methods to retrieve common JDBC data types.


An "x" indicates that the getXXX method may legally be used to retrieve the given
JDBC type.
An "X" indicates that the getXXX method is recommended for retrieving the given
JDBC type.

Basic Java 150


.

T S I N B C V L B V L
B R F D D D T T
I M N U I H A O I A O
I E L O E A I I
N A T M T A R N N R N
G A O U C T M M
Y L E E
L A B R C G A B G
I E E E
I L G N R
T L H V R I V
M S
N I E T I E A A Y N A
A T
T N R C R RL A R A
T C R B M
H Y I P
A N
R A
R
Y
getByte X x x x x x x x x x x x x
getShort x X x x x x x x x x x x x
getInt x x X x x x x x x x x x x
getLong x x x X x x x x x x x x x
getFloat x x x x X x x x x x x x x
getDouble x x x x x X X x x x x x x
getBigDecimal x x x x x x x X X x x x x
getBoolean x x x x x x x x x X x x x
getString x x x x x x x x x x X X x x x x x x x
getBytes X X x
getDate x x x X x
getTime x x x X x
getTimestamp x x x x X
getAsciiStream x x X x x x
getUnicodeStream x x X x x x
getBinaryStream x x X
GetObject x x x x x x x x x x x x x x x x x x x

Using Streams for Very Large Row Values


ResultSet makes it possible to retrieve arbitrarily large LONGVARBINARY or
LONGVARCHAR data. The methods getBytes and getString return data as one large
chunk (up to the limits imposed by the return value of Statement.getMaxFieldSize).
However, it may be more convenient to retrieve very large data in smaller, fixed-size
chunks. This is done by having the ResultSet class return java.io.Input streams from
which data can be read in chunks. Note that these streams must be accessed
immediately because they will be closed automatically on the next getXXX call on
ResultSet. (This behavior is imposed by underlying implementation constraints on
large blob access.)

The JDBC API has three separate methods for getting streams, each with a different
return value:
• getBinaryStream returns a stream which simply provides the raw bytes from
the database without any conversion.
• getAsciiStream returns a stream which provides one-byte ASCII characters.

Basic Java 151


.
• getUnicodeStream returns a stream which provides two-byte Unicode
characters.

Note that this differs from Java streams, which return untyped bytes and can (for
example) be used for both ASCII and Unicode characters.
The following code gives an example of using getAsciiStream:
java.sql.Statement stmt = con.createStatement();
ResultSet r = stmt.executeQuery("SELECT x FROM Table2");
// Now retrieve the column 1 results in 4 K chunks:
byte buff = new byte[4096];
while (r.next()) {
Java.io.InputStream fin = r.getAsciiStream(1);
for (;;) {
int size = fin.read(buff);
if (size == -1) { // at end of stream
break;
}
// Send the newly-filled buffer to some ASCII output stream:
output.write(buff, 0, size);
}
}

NULL Result Values


To determine if a given result value is JDBC NULL, one must first read the column
and then use the ResultSet.wasNull method to discover if the read returned a JDBC
NULL.
When one has read a JDBC NULL using one of the ResultSet.getXXX methods, the
method wasNull will return one of the following:
• A Java null value for those getXXX methods that return Java objects
(methods such as getString, getBigDecimal, getBytes, getDate, getTime,
getTimestamp, getAsciiStream, getUnicodeStream, getBinaryStream,
getObject).
• A zero value for getByte, getShort, getInt, getLong, getFloat, and getDouble.
• A false value for getBoolean.

Optional or Multiple Result Sets


Normally SQL statements are executed using either executeQuery (which returns a
single ResultSet) or executeUpdate (which can be used for any kind of database
modification statement and which returns a count of the rows updated). However,
under some circumstances an application may not know whether a given statement
will return a result set until the statement has executed. In addition, some stored
procedures may return several different result sets and/or update counts.

To accommodate these situations, JDBC provides a mechanism so that an


application can execute a statement and then process an arbitrary collection of result
sets and update counts. This mechanism is based on first calling a fully general
execute method, and then calling three other methods, getResultSet,
getUpdateCount, and getMoreResults. These methods allow an application to
explore the statement results one at a time and to determine if a given result was a
ResultSet or an update count.

Basic Java 152


.
You do not need to do anything to close a ResultSet; it is automatically closed by the
Statement that generated it when that Statement is closed, is re-executed, or is used
to retrieve the next result from a sequence of multiple results.

PreparedStatement
The PreparedStatement interface inherits from Statement and differs from it in two
ways:
10. Instances of PreparedStatement contain an SQL statement that has already
been compiled. This is what makes a statement "prepared."
11. The SQL statement contained in a PreparedStatement object may have one
or more IN parameters. An IN parameter is a parameter whose value is not
specified when the SQL statement is created. Instead the statement has a
question mark ("?") as a placeholder for each IN parameter. A value for each
question mark must be supplied by the appropriate setXXX method before the
statement is executed.

Because PreparedStatement objects are precompiled, their execution can be faster


than that of Statement objects. Consequently, an SQL statement that is executed
many times is often created as a PreparedStatement object to increase efficiency.
Being a subclass of Statement, PreparedStatement inherits all the functionality of
Statement. In addition, it adds a whole set of methods which are needed for setting
the values to be sent to the database in place of the placeholders for IN parameters.
Also, the three methods execute, executeQuery, and executeUpdate are modified so
that they take no argument. The Statement forms of these methods (the forms that
take an SQL statement parameter) should never be used with a PreparedStatement
object.

Creating PreparedStatement Objects


The following code fragment, where con is a Connection object, creates a
PreparedStatement object containing an SQL statement with two placeholders for IN
parameters:
PreparedStatement pstmt = con.prepareStatement(
"UPDATE table4 SET m = ? WHERE x = ?");
The object pstmt now contains the statement "UPDATE table4 SET m = ? WHERE x
= ?", which has already been sent to the DBMS and been prepared for execution.

Passing IN Parameters
Before a PreparedStatement object is executed, the value of each ? parameter must
be set. This is done by calling a setXXX method, where XXX is the appropriate type
for the parameter. For example, if the parameter has a Java type of long, the method
to use is setLong. The first argument to the setXXX methods is the ordinal position of
the parameter to be set, and the second argument is the value to which the
parameter is to be set. For example, the following code sets the first parameter to
123456789 and the second parameter to 100000000:
pstmt.setLong(1, 123456789);
pstmt.setLong(2, 100000000);
Once a parameter value has been set for a given statement, it can be used for
multiple executions of that statement until it is cleared by a call to the method
clearParameters.
In the default mode for a connection (auto-commit enabled), each statement is
commited or rolled back automatically when it is completed.

Basic Java 153


.
The same PreparedStatement object may be executed multiple times if the
underlying database and driver will keep statements open after they have been
committed. Unless this is the case, however, there is no point in trying to improve
performance by using a PreparedStatement object in place of a Statement object.
Using pstmt, the PreparedStatement object created above, the following code
illustrates setting values for the two parameter placeholders and executing pstmt 10
times. As stated above, for this to work, the database must not close pstmt. In this
example, the first parameter is set to "Hi" and remains constant. The second
parameter is set to a different value each time around the for loop, starting with 0 and
ending with 9.
pstmt.setString(1, "Hi");
for (int i = 0; i < 10; i++) {
pstmt.setInt(2, i);
int rowCount = pstmt.executeUpdate();
}

Data Type Conformance on IN Parameters


The XXX in a setXXX method is a Java type. It is implicitly a JDBC type (a generic
SQL type) because the driver will map the Java type to its corresponding JDBC type
and send that JDBC type to the database. For example, the following code fragment
sets the second parameter of the PreparedStatement object pstmt to 44, with a Java
type of short:
pstmt.setShort(2, 44);

The driver will send 44 to the database as a JDBC SMALLINT, which is the standard
mapping from a Java short.
It is the programmer's responsibility to make sure that the Java type of each IN
parameter maps to a JDBC type that is compatible with the JDBC data type expected
by the database. Consider the case where the database expects a JDBC SMALLINT.
If the method setByte is used, the driver will send a JDBC TINYINT to the database.
This will probably work because many databases convert from one related type to
another, and generally a TINYINT can be used anywhere a SMALLINT is used.
However, for an application to work with the most databases possible, it is best to
use Java types that correspond to the exact JDBC types expected by the database. If
the expected JDBC type is SMALLINT, using setShort instead of setByte will make
an application more portable.

Using setObject
A programmer can explicitly convert an input parameter to a particular JDBC type by
using the method setObject. This method can take a third argument, which specifies
the target JDBC type. The driver will convert the Java Object to the specified JDBC
type before sending it to the database.

If no JDBC type is given, the driver will simply map the Java Object to its default
JDBC type and then send it to the database. This is similar to what happens with the
regular setXXX methods; in both cases, the driver maps the Java type of the value to
the appropriate JDBC type before sending it to the database. The difference is that
the setXXX methods use the standard mapping from Java types to JDBC types
whereas the setObject method uses the mapping from Java Object types to JDBC
types

Basic Java 154


.
The capability of the method setObject to accept any Java object allows an
application to be generic and accept input for a parameter at run time. In this
situation the type of the input is not known when the application is compiled. By using
setObject, the application can accept any Java object type as input and convert it to
the JDBC type expected by the database.

Sending JDBC NULL as an IN parameter


The setNull method allows a programmer to send a JDBC NULL value to the
database as an IN parameter. Note, however, that one must still specify the JDBC
type of the parameter.
A JDBC NULL will also be sent to the database when a Java null value is passed to a
setXXX method (if it takes Java objects as arguments). The method setObject,
however, can take a null value only if the JDBC type is specified.

Sending Very Large IN Parameters


The methods setBytes and setString are capable of sending unlimited amounts of
data. Sometimes, however, programmers prefer to pass in large blobs of data in
smaller chunks. This can be accomplished by setting an IN parameter to a Java input
stream. When the statement is executed, the JDBC driver will make repeated calls to
this input stream, reading its contents and transmitting those contents as the actual
parameter data.
JDBC provides three methods for setting IN parameters to input streams:
setBinaryStream for streams containing uninterpreted bytes, setAsciiStream for
streams containing ASCII characters, and setUnicodeStream for streams containing
Unicode characters. These methods take one more argument than the other setXXX
methods because the total length of the stream must be specified. This is necessary
because some databases need to know the total transfer size before any data is
sent.

The following code illustrates using a stream to send the contents of a file as an IN
parameter:
java.io.File file = new java.io.File("/tmp/data");
int fileLength = file.length();
java.io.InputStream fin = new java.io.FileInputStream(file);
java.sql.PreparedStatement pstmt = con.prepareStatement(
"UPDATE Table5 SET stuff = ? WHERE index = 4");
pstmt.setBinaryStream (1, fin, fileLength);
pstmt.executeUpdate();
When the statement executes, the input stream fin will get called repeatedly to
deliver up its data.

CallableStatement
A CallableStatement object provides a way to call stored procedures in a standard
way for all DBMSs. A stored procedure is stored in a database; the call to the stored
procedure is what a CallableStatement object contains. This call is written in an
escape syntax that may take one of two forms: one form with a result parameter, and
the other without one. A result parameter, a kind of OUT parameter, is the return
value for the stored procedure. Both forms may have a variable number of
parameters used for input (IN parameters), output (OUT parameters), or both
(INOUT parameters). A question mark serves as a placeholder for a parameter.

Basic Java 155


.
The syntax for invoking a stored procedure in JDBC is shown below. Note that the
square brackets indicate that what is between them is optional; they are not
themselves part of the syntax.
{call procedure_name[(?, ?, ...)]}
The syntax for a procedure that returns a result parameter is:
{? = call procedure_name[(?, ?, ...)]}
The syntax for a stored procedure with no parameters would look like this:
{call procedure_name}

Normally, anyone creating a CallableStatement object would already know that the
DBMS being used supports stored procedures and what those procedures are. If one
needed to check, however, various DatabaseMetaData methods will supply such
information. For instance, the method supportsStoredProcedures will return true if the
DBMS supports stored procedure calls, and the method getProcedures will return a
description of the stored procedures available.

CallableStatement inherits Statement methods, which deal with SQL statements in


general, and it also inherits PreparedStatement methods, which deal with IN
parameters. All of the methods defined in CallableStatement deal with OUT
parameters or the output aspect of INOUT parameters: registering the JDBC types
(generic SQL types) of the OUT parameters, retrieving values from them, or checking
whether a returned value was JDBC NULL.

Creating a CallableStatement Object


CallableStatement objects are created with the Connection method prepareCall. The
example below creates an instance of CallableStatement that contains a call to the
stored procedure getTestData, which has two arguments and no result parameter:
CallableStatement cstmt = con.prepareCall(
"{call getTestData(?, ?)}");
Whether the ? placeholders are IN, OUT, or INOUT parameters depends on the
stored procedure getTestData.

IN and OUT Parameters


Passing in any IN parameter values to a CallableStatement object is done using the
setXXX methods inherited from PreparedStatement. The type of the value being
passed in determines which setXXX method to use (setFloat to pass in a float value,
and so on).

If the stored procedure returns OUT parameters, the JDBC type of each OUT
parameter must be registered before the CallableStatement object can be executed.
(This is necessary because some DBMSs require the JDBC type.) Registering the
JDBC type is done with the method registerOutParameter. Then after the statement
has been executed, CallableStatement's getXXX methods retrieve the parameter
value. The correct getXXX method to use is the Java type that corresponds to the
JDBC type registered for that parameter. In other words, registerOutParameter uses
a JDBC type (so that it matches the JDBC type that the database will return), and
getXXX casts this to a Java type.

To illustrate, the following code registers the OUT parameters, executes the stored
procedure called by cstmt, and then retrieves the values returned in the OUT
parameters. The method getByte retrieves a Java byte from the first OUT parameter,

Basic Java 156


.
and getBigDecimal retrieves a BigDecimal object (with three digits after the decimal
point) from the second OUT parameter:
CallableStatement cstmt = con.prepareCall(
"{call getTestData(?, ?)}");
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3);
cstmt.executeQuery();
byte x = cstmt.getByte(1);
java.math.BigDecimal n = cstmt.getBigDecimal(2, 3);
Unlike ResultSet, CallableStatement does not provide a special mechanism for
retrieving large OUT values incrementally.

INOUT Parameters
A parameter that supplies input as well as accepts output (an INOUT parameter)
requires a call to the appropriate setXXX method (inherited from PreparedStatement)
in addition to a call to the method registerOutParameter. The setXXX method sets a
parameter's value as an input parameter, and the method registerOutParameter
registers its JDBC type as an output parameter. The setXXX method provides a Java
value which the driver converts to a JDBC value before sending it to the database.
The JDBC type of this IN value and the JDBC type supplied to the method
registerOutParameter should be the same. Then to retrieve the output value, a
corresponding getXXX method is used. For example, a parameter whose Java type
is byte should use the method setByte to assign the input value, should supply a
TINYINT as the JDBC type to registerOutParameter, and should use getByte to
retrieve the output value.

The following example assumes that there is a stored procedure reviseTotal whose
only parameter is an INOUT parameter. The method setByte sets the parameter to
25, which the driver will send to the database as a JDBC TINYINT. Next
registerOutParameter registers the parameter as a JDBC TINYINT. After the stored
procedure is executed, a new JDBC TINYINT value is returned, and the method
getByte will retrieve this new value as a Java byte.
CallableStatement cstmt = con.prepareCall(
"{call reviseTotal(?)}");
cstmt.setByte(1, 25);
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.executeUpdate();
byte x = cstmt.getByte(1);

Retrieve OUT Parameters after Results


Because of limitations imposed by some DBMSs, it is recommended that for
maximum portability, all of the results generated by the execution of a
CallableStatement object should be retrieved before OUT parameters are retrieved
using CallableStatement.getXXX methods.
If a CallableStatement object returns multiple ResultSet objects (using a call to the
method execute), all of the results should be retrieved before OUT parameters are
retrieved. In this case, to be sure that all results have been accessed, the Statement
methods getResultSet, getUpdateCount, and getMoreResults need to be called until
there are no more results.

Basic Java 157


.
After this is done, values from OUT parameters can be retrieved using the
CallableStatement.getXXX methods.

Retrieving NULL Values as OUT Parameters


The value returned to an OUT parameter may be JDBC NULL. When this happens,
the JDBC NULL value will be converted so that the value returned by a getXXX
method will be null, 0, or false, depending on the getXXX method type. As with
ResultSet objects, the only way to know if a value of 0 or false was originally JDBC
NULL is to test it with the method wasNull, which returns true if the last value read by
a getXXX method was JDBC NULL and false otherwise.

Mapping SQL and Java Types


Since SQL data types and Java data types are not identical, there needs to be some
mechanism for reading and writing data between an application using Java types and
a database using SQL types.
To accomplish this, JDBC provides sets of getXXX and setXXX methods, the method
registerOutParameter, and the class Types.
This section brings together information about data types affecting various classes
and interfaces and puts all the tables showing the mappings between SQL types and
Java types in one place for easy reference.

Mapping SQL Data Types into Java


Unfortunately there are significant variations between the SQL types supported by
different database products. Even when different databases support SQL types with
the same semantics, they may give those types different names. For example, most
of the major databases support an SQL data type for large binary values, but Oracle
calls this type LONG RAW, Sybase calls it IMAGE, Informix calls it BYTE, and DB2
calls it LONG VARCHAR FOR BIT DATA.

Fortunately, JDBC programmers will normally not need to concern themselves with
the actual SQL type names used by a target database. Most of the time JDBC
programmers will be programming against existing database tables, and they need
not concern themselves with the exact SQL type names that were used to create
these tables.

JDBC defines a set of generic SQL type identifiers in the class java.sql.Types. These
types have been designed to represent the most commonly used SQL types. In
programming with the JDBC API, programmers will normally be able to use these
JDBC types to reference generic SQL types, without having to be concerned about
the exact SQL type name used by the target database. These JDBC types are fully
described in the next section.

The one major place where programmers may need to use SQL type names is in the
SQL CREATE TABLE statement when they are creating a new database table. In
this case programmers must take care to use SQL type names that are supported by
their target database. We recommend that you consult your database documentation
if you need exact definitions of the behavior of the various SQL types on a particular
database.

Basic Java 158


.
If you want to be able to write portable JDBC programs that can create tables on a
variety of different databases, you have two main choices. First, you can restrict
yourself to using only very widely accepted SQL type names such as INTEGER,
NUMERIC, or VARCHAR, which are likely to work for all databases.
Or second, you can use the java.sql.DatabaseMetaData.getTypeInfo method to
discover which SQL types are actually supported by a given database and select a
database-specific SQL type name that matches a given JDBC type.

JDBC defines a standard mapping from the JDBC database types to Java types. For
example, a JDBC INTEGER is normally mapped to a Java int. This supports a simple
interface for reading and writing JDBC values as simple Java types.

The Java types do not need to be exactly isomorphic to the JDBC types; they just
need to be able to represent them with enough type information to correctly store and
retrieve parameters and recover results from SQL statements. For example, a Java
String object does not precisely match any of the JDBC CHAR types, but it gives
enough type information to represent CHAR, VARCHAR, or LONGVARCHAR
successfully.

Examples of Mapping
In any situation where a Java program retrieves data from a database, there has to
be some form of mapping and data conversion. In most cases, JDBC programmers
will be programming with knowledge of their target database's schema. They would
know, for example, what tables the database contains and the data type for each
column in those tables. They can therefore use the strongly-typed access methods in
the interfaces ResultSet, PreparedStatement, and CallableStatement. This section
presents three different scenarios, describing the data mapping and conversion
required in each.

Simple SQL Statement


In the most common case, a user executes a simple SQL statement and gets back a
ResultSet object with the results. The value returned by the database and stored in a
ResultSet column will have a JDBC data type. A call to a ResultSet.getXXX method
will retrieve that value as a Java data type. For example, if a ResultSet column
contains a JDBC FLOAT value, the method getDouble will retrieve that value as a
Java double. The getXXX methods may be used to retrieve which JDBC types. (A
user who does not know the type of a ResultSet column can get that information by
calling the method ResultSet.getMetaData and then invoking the ResultSetMetaData
methods getColumnType or getColumnTypeName.) The following code fragment
demonstrates getting the column type names for the columns in a result set:

String query = "select * from Table1";


ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String s = rsmd.getColumnTypeName(i);
System.out.println ("Column " + i + " is type " + s);
}

Basic Java 159


.
SQL Statement with IN Parameters
In another possible scenario, the user sends an SQL statement which takes input
parameters. In this case, the user calls the PreparedStatement.setXXX methods to
assign a value to each input parameter. For example, PreparedStatement.setLong(1,
2345678) will assign the value 2345678 to the first parameter as a Java long. The
driver will convert 2345678 to a JDBC BIGINT in order to send it to the database.
Which JDBC type the driver sends to the database is determined by the standard
mapping from Java types to JDBC types.

SQL Statement with INOUT Parameters


In yet another scenario, a user wants to call a stored procedure, assign values to its
INOUT parameters, retrieve values from the results, and retrieve values from the
parameters. This case is rather uncommon and more complicated than most, but it
gives a good illustration of mapping and data conversion.

In this scenario, the first thing to do is to assign values to the INOUT parameters
using PreparedStatement.setXXX methods. In addition, since the parameters will
also be used for output, the programmer must register each parameter with the
JDBC type of the value that the database will return to it. This is done with the
method CallableStatement.registerOutParameter, which takes one of the JDBC types
defined in the class Types. A programmer retrieves the results returned to a
ResultSet object with ResultSet.getXXX methods and retrieves the values stored in
the output parameters with CallableStatement.getXXX methods.

The XXX type used for ResultSet.getXXX methods is fairly flexible in some cases.
The XXX type used for CallableStatement.getXXX must map to the JDBC type
registered for that parameter. For example, if the database is expected to return an
output value whose type is JDBC REAL, the parameter should have been registered
as java.sql.Types.REAL. Then to retrieve the JDBC REAL value, the method
CallableStatement.getFloat should be called. The method getFloat will return the
value stored in the output parameter after converting it from a JDBC REAL to a Java
float. To accommodate various databases and make an application more portable, it
is recommended that values be retrieved from ResultSet objects before values are
retrieved from output parameters.

The following code demonstrates calling a stored procedure named getTestData,


which has two parameters that are both INOUT parameters. First the Connection
object con creates the CallableStatement object cstmt. Then the method setByte sets
the first parameter to 25 as a Java byte. The driver will convert 25 to a JDBC
TINYINT and send it to the database. The method setBigDecimal sets the second
parameter with an input value of 83.75. The driver will convert this
java.math.BigDecimal object to a JDBC NUMERIC value. Next the two parameters
are registered as OUT parameters, the first parameter as a JDBC TINYINT and the
second parameter as a JDBC DECIMAL with two digits after the decimal point. After
cstmt is executed, the values are retrieved from the ResultSet object using
ResultSet.getXXX methods. The method getString gets the value in the first column
as a Java String object, getInt gets the value in the second column as a Java int, and
getInt gets the value in the third column as a Java int.

Then CallableStatement.getXXX methods retrieve the values stored in the output


parameters. The method getByte retrieves the JDBC TINYINT as a Java byte, and
getBigDecimal retrieves the JDBC DECIMAL as a java.math.BigDecimal object with

Basic Java 160


.
two digits after the decimal point. Note that when a parameter is both an input and an
output parameter, the setXXX method uses the same Java type as the getXXX
method (as in setByte and getByte). The registerOutParameter method registers it to
the JDBC type that is mapped from the Java type

CallableStatement cstmt = con.prepareCall(


"{call getTestData(?, ?)}");
cstmt.setByte(1, 25);
cstmt.setBigDecimal(2, 83.75);
// register the first parameter as a JDBC TINYINT and the second
//parameter as a JDBC DECIMAL with two digits after the decimal point
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 2);
ResultSet rs = cstmt.executeUpdate();
// retrieve and print values in result set
while(rs.next()) {
String name = rs.getString(1);
int score = rs.getInt(2);
int percentile = rs.getInt(3);
System.out.print("name = " + name + ", score = " + score + ", "
System.out.println("percentile = " + percentile);
// retrieve values in output parameters
byte x = cstmt.getByte(1);
java.math.BigDecimal n = cstmt.getBigDecimal(2, 2);

To generalize, the XXX in CallableStatement.getXXX and


PreparedStatement.setXXX methods is a Java type. For setXXX methods, the driver
converts the Java type to a JDBC type before sending it to the database. For getXXX
methods, the driver converts the JDBC type returned by the database to a Java type
before returning it to the getXXX method.

The method registerOutParameter always takes a JDBC type as an argument, and


the method setObject may take a JDBC type as an argument.

Note that if a JDBC type is supplied in its optional third argument, the method
setObject will cause an explicit conversion of the parameter value from a Java type to
the JDBC type specified. If no target JDBC type is supplied to setObject, the
parameter value will be converted to the JDBC type that is the standard mapping
from the Java. The driver will perform the explicit or implicit conversion before
sending the parameter to the database.

Dynamic Data Access


In most cases, the user wants to access results or parameters whose data types are
known at compile time. However, some applications, such as generic browsers or
query tools, are compiled with no knowledge of the database schema they will
access. For this reason, JDBC provides support for fully dynamically-typed data
access in addition to static data type access.
Three methods and one constant facilitate accessing values whose data types are
not known at compile time:
• ResultSet.getObject
• PreparedStatement.setObject
• CallableStatement.getObject

Basic Java 161


.
• java.sql.Types.OTHER (used as an argument to
CallableStatement.registerOutParameter)

If, for example, an application wants to be able to accept a variety of types as results
in a ResultSet object, it can use the method ResultSet.getObject.

The methods ResultSet.getObject and CallableStatement.getObject retrieve a value


as a Java Object. Since Object is the base class for all Java objects, an instance of
any Java class can be retrieved as an instance of Object. However, the following
Java types are built-in "primitive" types and are therefore not instances of the class
Object: boolean, char, byte, short, int, long, float, and double. As a result, these types
cannot be retrieved by getObject methods. However, each of these primitive types
has a corresponding class that serves as a wrapper. Instances of these classes are
objects, which means that they can be retrieved with the methods
ResultSet.getObject and CallableStatement.getObject

The method getObject can also be used to retrieve user-defined Java types. With the
advent of abstract data types (ADTs) or other user-defined types in some database
systems, some vendors may find it convenient to use getObject for retrieving these
types.

Tables for Data Type Mapping


Java type
JDBC type
CHAR String
VARCHAR String
LONGVARCHAR String
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT boolean
TINYINT byte
SMALLINT short
INTEGER int
BIGINT long
REAL float
FLOAT double
DOUBLE double
BINARY byte[]
VARBINARY byte[]
LONGVARBINARY byte[]
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp

Basic Java 162


.

Java Types Mapped to JDBC Types


Java Type JDBC type
String VARCHAR or LONGVARCHAR
java.math.BigDecimal NUMERIC
boolean BIT
byte TINYINT
short SMALLINT
int INTEGER
long BIGINT
float REAL
double DOUBLE
byte[] VARBINARY or LONGVARBINARY
java.sql.Date DATE
java.sql.Time TIME
java.sql.Timestamp TIMESTAMP

The mapping for String will normally be VARCHAR but will turn into LONGVARCHAR
if the given value exceeds the driver's limit on VARCHAR values. The same is true
for byte[] and VARBINARY and LONGVARBINARY values.

JDBC Types Mapped to Java Object Types


Since the Java built-in types such as boolean and int are not subtypes of Object,
there is a slightly different mapping from JDBC types to Java object types for the
getObject/setObject methods. This mapping is shown in the following table:

JDBC Type Java Object Type


CHAR String
VARCHAR String
LONGVARCHAR String
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT Boolean
TINYINT Integer
SMALLINT Integer
INTEGER Integer
BIGINT Long
REAL Float
FLOAT Double
DOUBLE Double
BINARY byte[]
VARBINARY byte[]
LONGVARBINARY byte[]
DATE java.sql.Date
TIME java.sql.Time

Basic Java 163


.
TIMESTAMP java.sql.Timestamp
Java Object Types Mapped to JDBC Types
Java Object Type JDBC Type
String VARCHAR or LONGVARCHAR
java.math.BigDecimal NUMERIC
Boolean BIT
Integer INTEGER
Long BIGINT
Float REAL
Double DOUBLE
byte[] VARBINARY or LONGVARBINARY
java.sql.Date DATE
java.sql.Time TIME
java.sql.Timestamp TIMESTAMP

Note that the mapping for String will normaly be VARCHAR but will turn into
LONGVARCHAR if the given value exceeds the driver's limit on VARCHAR values.
The case is similar for byte[] and VARBINARY and LONGVARBINARY values.

Conversions by setObject
The method setObject converts Java object types to JDBC types.

T S I B R F D D N B C V L B V L D T T
I M N I E L O E U I H A O I A O A I I
N A T G A O U C M T A R N N R N T M M
Y L E I L A B I E R C G A B G E E E
I L G N T L M R H V R I V S
N I E T E A I A A Y N A T
T N R L C R R A R A
T C R B M
H Y I P
A N
R A
R
Y
String x x x x x x x x x x x x x x x x x x x
java.math.BigDecimal x x x x x x x x x x x x x
Boolean x x x x x x x x x x x x x
Integer x x x x x x x x x x x x x
Long x x x x x x x x x x x x x
Float x x x x x x x x x x x x x
Double x x x x x x x x x x x x x
byte[] x x x
java.sql.Date x x x x x
java.sql.Time x x x x
java.sql.Time- stamp x x x x x x

Basic Java 164


.
JDBC Types Retrieved by ResultSet.getXXX Methods
An "x" means that the method can retrieve the JDBC type. An "X" means that the
method is recommended for the JDBC type.
T S I B R N B C V L B V L
F D D D T T
I M N I E U I H A O I A O
L O E A I I
N A T G A M T A R N N R N
O U C T M M
Y L E I L E AR C G A B G
B I E E E
I L G N R T H V R I V
L M S
N I E T I A A Y N A
E A T
T N R C R R LA R A
T C R B M
H Y I P
A N
R A
R
Y
getByte X x x x x x x x x x x x x
getShort x X x x x x x x x x x x x
getInt x x X x x x x x x x x x x
getLong x x x X x x x x x x x x x
getFloat x x x x X x x x x x x x x
getDouble x x x x x X X x x x x x x
getBigDecimal x x x x x x x X X x x x x
getBoolean x x x x x x x x x X x x x
getString x x x x x x x x x x X X x x x x x x x
getBytes X X x
getDate x x x X x
getTime x x x X x
getTimestamp x x x x X
getAsciiStream x x X x x x
getUnicodeStream x x X x x x
getBinaryStream x x X
getObject x x x x x x x x x x x x x x x x x x x

Basic Java 165


.
Sample Code
// The following code can be used as a template. Simply
// substitute the appropriate url, login, and password, and
then substitute //the
// SQL statement you want to send to the database.
//----------------------------------------------------------
------------------
//
// Module: SimpleSelect.java
//
// Description:
//Test program for ODBC API interface.
//This java application will connect to
//a JDBC driver,
//issue a select statement
// and display all result columns and rows
//----------------------------------------------------------
------------------
import java.net.URL;
import java.sql.*;

class SimpleSelect
{
public static void main (String args[])
{
String url = "jdbc:odbc:my-dsn";
String query = "SELECT * FROM emp";
try
{
// Load the jdbc-odbc bridge driver
Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver");
DriverManager.setLogStream(System.out);
// Attempt to connect to a driver. Each one
// of the registered drivers will be loaded until
// one is found that can process this URL
Connection con = DriverManager.getConnection (
url, "my-user", "my-passwd");
// If we were unable to connect, an exception
// would have been thrown. So, if we get here,
// we are successfully connected to the URL
// Check for, and display and warnings generated
// by the connect.

checkForWarning (con.getWarnings ());

// Get the DatabaseMetaData object and display


// some information about the connection

DatabaseMetaData dma = con.getMetaData ();


System.out.println("\nConnected to " + dma.getURL());
System.out.println("Driver " + dma.getDrive
System.out.println("Version "
+dma.getDriverVersion());
System.out.println("");

Basic Java 166


.

// Create a Statement object so we can submit


// SQL statements to the driver

Statement stmt = con.createStatement ();

// Submit a query, creating a ResultSet object

ResultSet rs = stmt.executeQuery (query);

// Display all columns and rows from the result set

dispResultSet (rs);

// Close the result set

rs.close();

// Close the statement

stmt.close();

// Close the connection

con.close();
}
catch (SQLException ex)
{
// A SQLException was generated. Catch it and
// display the error information. Note that there
// could be multiple error objects chained
// together
System.out.println ("\n*** SQLException caught ***\n");
while (ex != null)
{
System.out.println ("SQLState: " +ex.getSQLState ());
System.out.println ("Message: " + ex.getMessage ());
System.out.println ("Vendor: " +ex.getErrorCode ());
ex = ex.getNextException ();
System.out.println ("");
}
}
catch (java.lang.Exception ex)
{
// Got some other type of exception. Dump it.
ex.printStackTrace ();
}
}

//----------------------------------------------------------
---------
// checkForWarning
// Checks for and displays warnings. Returns true if a
warning
// existed

Basic Java 167


.
//----------------------------------------------------------
---------

private static boolean checkForWarning (SQLWarning warn)


throws SQLException
{
boolean rc = false;

// If a SQLWarning object was given, display the


// warning messages. Note that there could be
// multiple warnings chained together

if (warn != null)
{
System.out.println ("\n *** Warning ***\n");
rc = true;
while (warn != null)
{
System.out.println ("SQLState: "
+warn.getSQLState ());
System.out.println ("Message: "
+warn.getMessage ());
System.out.println ("Vendor: "
+warn.getErrorCode ());
System.out.println ("");
warn = warn.getNextWarning ();
}
}
return rc;
}

//----------------------------------------------------------
---------
// dispResultSet
// Displays all columns and rows in the given result set
//----------------------------------------------------------
---------

private static void dispResultSet (ResultSet rs)


throws SQLException
{
int i;
// Get the ResultSetMetaData. This will be used for
// the column headings

ResultSetMetaData rsmd = rs.getMetaData ();

// Get the number of columns in the result set

int numCols = rsmd.getColumnCount ();

// Display column headings

for (i=1; i<=numCols; i++)


{

Basic Java 168


.
if (i > 1) System.out.print(",");
System.out.print(rsmd.getColumnLabel(i));
}
System.out.println("");

// Display data, fetching until end of the result set

boolean more = rs.next ();


while (more)
{
// Loop through each column, getting the
// column data and displaying
for (i=1; i<=numCols; i++)
{
if (i > 1)
System.out.print(",");
System.out.print(rs.getString(i));
}
System.out.println("");
// Fetch the next result set row
more = rs.next ();
}
}
}

JDBC-ODBC Bridge Driver


If possible, use a Pure Java JDBC driver instead of the Bridge and an ODBC driver.
This completely eliminates the client configuration required by ODBC. It also
eliminates the potential that the Java VM could be corrupted by an error in the native
code brought in by the Bridge (that is, the Bridge native library, the ODBC driver
manager library, the ODBC driver library, and the database client library).

What Is the JDBC-ODBC Bridge?


The JDBC-ODBC Bridge is a JDBC driver which implements JDBC operations by
translating them into ODBC operations. To ODBC it appears as a normal application
program. The Bridge implements JDBC for any database for which an ODBC driver
is available. The Bridge is implemented as the sun.jdbc.odbc Java package and
contains a native library used to access ODBC. The Bridge is a joint development of
Intersolv and JavaSoft.

What Version of ODBC Is Supported?


The bridge supports ODBC 2.x. This is the version that most ODBC drivers currently
support. It will also likely work with most forthcoming ODBC 3.x drivers; however, this
has not been tested.

Basic Java 169


.
The Bridge Implementation
The Bridge is implemented in Java and uses Java native methods to call ODBC.

Installation
The Bridge is installed automatically with the JDK as package sun.jdbc.odbc. See
your ODBC driver vendor for information on installing and configuring ODBC. No
special configuration is required for the Bridge. See your database vendor for client
installation and configuration information. On Solaris, some ODBC driver managers
name their libs libodbcinst.so and libodbc.so. The Bridge expects these libraries to be
named libodbcinst.so.1 and libodbc.so.1, so symbolic links for these names must be
created.

Using the Bridge


The Bridge is used by opening a JDBC connection using a URL with the odbc
subprotocol. See below for URL examples. Before a connection can be established,
the bridge driver class, sun.jdbc.odbc.JdbcOdbcDriver, must either be added to the
java.lang.System property named jdbc.drivers, or it must be explicitly loaded using
the Java class loader. Explicit loading is done with the following line of code:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
When loaded, the ODBC driver (like all good JDBC drivers) creates an instance of
itself and registers this with the JDBC driver manager.

Using the Bridge from an Applet


JDBC used with a Pure Java JDBC driver works well with applets. The Bridge driver
does not work well with applets.

Most Browsers Do Not Support the Bridge


Since the Bridge is an optional component of the JDK, it may not be provided by a
browser. Even if it is provided, only trusted applets (those allowed to write to files) will
be able to use the Bridge. This is required in order to preserve the security of the
applet sandbox. Finally, even if the applet is trusted, ODBC and the DBMS client
library must be configured on each client.

Tested Configurations
From Solaris, we have used the Bridge to access Oracle 7.1.6 and Sybase Version
10 running on Solaris. From NT, we have used the Bridge to access SQL Server 6.x.

ODBC Drivers Known to Work with the Bridge


Visigenic provides ODBC drivers which have been tested with the the Bridge. Drivers
are available for Oracle, Sybase, Informix, Microsoft SQL Server, and Ingres. To
purchase the ODBC DriverSet 2.0, please contact Visigenic sales at 415-312-7197,
or visit the web site www.visigenic.com. The INTERSOLV ODBC driver suite should
be completely compatible with the JDBC-ODBC Bridge. The following drivers have
successfully passed a minimal test suite: Oracle, xBASE, Sybase (Windows NT/95

Basic Java 170


.
only), Microsoft SQL-Server, and Informix. To evaluate or purchase INTERSOLV
ODBC drivers, please contact INTERSOLV DataDirect Sales at 1- 800-547-4000
Option 2 or via the World Wide Web at http:\\www.intersolv.com. The MS SQL Server
driver has also been used successfully on NT. Many other ODBC drivers will likely
work.

ODBC Driver Incompatibilities


On Solaris, we have found that the Sybase ctlib-based drivers don't work because
ctlib has a signal-handling conflict with the Java VM. This is likely not a problem on
NT due to differences in the NT Java VM; however, this has not been verified. Some
ODBC drivers only allow a single result set to be active per connection.

What Is the JDBC URL Supported by the Bridge?


The Bridge driver uses the odbc subprotocol. URLs for this subprotocol are of the
form:
jdbc:odbc:<data-source-name>[<attribute-name>=<attribute-value>]*
For example:
jdbc:odbc:sybase
jdbc:odbc:mydb;UID=me;PWD=secret
jdbc:odbc:ora123;Cachesize=300

Debugging
The Bridge provides extensive tracing when DriverManager tracing is enabled. The
following line of code enables tracing and sends it to standard out:

java.sql.DriverManager.setLogStream(java.lang.System.out);

General Notes
The Bridge assumes that ODBC drivers are not reentrant. This means the Bridge
must synchronize access to these drivers. The result is that the Bridge provides
limited concurrency. This is a limitation of the Bridge. Most Pure Java JDBC drivers
provide the expected level of concurrent access.

Basic Java 171

You might also like