360 Digrii Java Hand Book Final V1.0
360 Digrii Java Hand Book Final V1.0
CONTENTS
1|Page
360digrii
Java course material
Chapter 1 - History and Evolution of Java
Genesis of Modern Programming
Modern programming languages are identified with their dynamic applications, real-time usage,
coherence, structure and conforming language features. With the development of different forms of
languages, language designs and with the graduating need of interconnectivity of data, program patterns
changed. Imperative programming was replaced by functional programming and attention was given to
the evaluation of expressions rather than on the execution of commands. Since 70’s of the 20th century,
there was a paradigm shift in terms of real-time programming and programs were identified on the basis
of their real-time use and long-term benefits. Focus was mainly given on data application and management
rather than processes and systems.
The most comprehensive use and application of structured and systematic programming started with “C”.
The genesis of “C” language dates back to the early 70’s of the 20th century. The language “C” has derived
its fundamental characteristics from two major languages: BPCL & B respectively. BPCL emerged as a
path-breaker language providing all conventional features for dynamic programming. Developed in the
year 1967, BPCL was used to program applications. While BPCL focused mainly on numeric computations
“B”, the other language developed in the year 1972 focused on non-numeric and logical computations.
“C” language was the first language that incorporated multiple dimensions of controlled and organized
programming. “C” consisted of simplified data structures: distinct data types and a strong macro
processor. Initially the language was used to program structured events and concepts. But “C” did not have
an object-oriented interface. “C” was replaced by a more organized and structured programming called
C++. C++ provided the use of objects.
JAVA
PROGRAMMING PLATFORMS
LANGUAGE
The development of Java, incorporated certain conspicuous attributes and also evolved it into a platform
independent language.Programs developed in Java could run on any computer system and could be
executed on any environment that supported language interpreter software in the form of Virtual Java
Machine (JVM). Platform independence was attained by using a special format for compiled Java programs.
This file format, called byte-code, could be read and executed by any computer system with a Java Virtual
Machine (JVM).
3|Page
360digrii
Java course material
In 1993, after the World Wide Web had transformed the text-based Internet into a graphics-rich
environment, the Java developers realized that the language they had developed would be perfect for Web
programming.
In the second quarter of 1995, Sun Microsystems officially announced the launch of Java. This "new"
language in the name of ‘Java’ was quickly embraced as a prevailing tool for developing Internet
applications and other web-based applications. Netscape Communications, the developer of the popular
Netscape Navigator Web browser, added support for Java to its new Netscape Navigator 2.0. Other
Internet software developers including Microsoft followed the suit. Evolution and creation of Java can be
traced to certain pertinent reasons. These are:
Changes in the programming environment
Advances in the art of object based and object-oriented programming
Invention and development of World Wide Web and other web-based applications
Shift in user needs and demands
According to Sun Microsystems, Java is "simple, object-oriented, statically typed, compiled, architecture
neutral, multi-threaded, garbage collected, robust, secure, and extensible." The chief component of java
language is ‘class’ and all variables, methods and data types are defined within the dimensions of class.
In a nutshell, Java is a general-purpose, high-level programming language with a dominant software
platform.
Foundation of Java
As you already know, Java was conceived of in the hands of people like James Gosling, Patrick Naughton,
Chris Warth, and Mike Sheridan. Gosling and others started working on a portable, self-regulating
language that could be used to produce code that would run on a variety of CPUs under differing
environments and under varied electronic and telecommunication conditions. This effort ultimately led to
the creation of Java. Apart from these people who instrumentally helped in the development of Java
language, many other people like Bill Joy, Arthur van Hoff, Jonathan Payne, and Tim Lindholm also
contributed towards the design and improvement of this language.
Java as a programming language was not initially targeted to fulfill the need of the Internet users. It was
developed to generate new software to be embedded in various consumer electronic devices, such as
microwave ovens and remote controls. By the mid 90’s, it became obvious to members of the Java
competency team that the tribulations of portability frequently encountered when creating code for
embedded controllers are also found when attempting to create code for the Internet. This realization
urged the java team to switch focus from consumer electronics to Internet programming. So, while the
desire for an architecture-independently programming language provided the initial spark, the Internet
ultimately led to Java’s large-scale success.
Applets are sub-sets of applications. They are miniature programs dynamically downloaded across the
network, just like an image, video clip or sound file. They are embedded sub-programs that can react
dynamically to user choices and other functional inputs. An applet is an application transmitted over the
interwoven network and executed by a Java-compatible web browser. For example, when you use Java to
augment a World Wide Web page, the Java code is embedded within HTML code. On the other hand,
applications cannot be embedded into HTML pages for any Internet user to view with a Java-capable
browser. Applets and applications overlap in many areas, but they are specifically designed for different
environments.
Another specialized form of a program exists within Java. This type of a program is called as “servlet”.
Servlets are similar to applets in that they are runtime extensions of applications. Instead of working in
browsers, though, servlets run within Java servers.
The Bytecode
One of the key features that distinguish Java from other programming languages is the ‘bytecode’.
Bytecode is a highly optimized set of binary instructions designed to be executed by the Java run-time
system (also known as the Java Virtual Machine (JVM)). The same binary code can be executed in different
platforms and environments making the code user friendly. JVM performs the role of an interpreter for
bytecode. And as we all know that when a program is interpreted, it generally runs substantially slower
than it would have run if compiled to executable code. But with Java this is not the case and the run-time is
in fact faster. However, the fact that a Java program is executed by the JVM helps solve the major problems
associated with downloading files, programs and applications over the Internet.
5|Page
360digrii
Java course material
Note: Though functional details of Java Virtual Machine differ from platform to platform, yet all platforms
are able to interpret the same Java bytecode.
Bytecode ensures:
Portability
Safety
Security of the platform
Speedy execution of programs with faster run-time
Consistent and uninterrupted process of file downloading
Although Java was intended for interpretation, there is technically nothing about Java that checks on-the-
fly compilation of bytecode into native code. Sun supplies its Just In Time (JIT) compiler for bytecode.
When the JIT compiler is part of the JVM, it compiles bytecode into a form of an executable code mainly on
the basis of user demands.
Note: It is not technically feasible to compile an entire Java program into executable code all at once,
because Java performs various run-time checks that can be done only at run time. Instead during
execution, the JIT compiles code in accordance with the functional needs and user demand.
6|Page
360digrii
Java course material
object model in Java is simple and easy to stretch, while simple types, such as integers, are kept as
high-performance non-objects.
Statically typed: All objects used in a program must be stated before they are used. This not only
enhances upon the writability features of Java, it also enables the Java compiler to locate and report
type conflicts.
Compiled: Java is both a compiled and interpreted language. Before you can run a program written in
the Java language, the program must be compiled by the Java compiler. The compilation results in a
"byte-code" file that, while similar to a machine-code file, can be executed under any operating system
that has a Java interpreter. This interpreter reads in the byte-code file and translates the byte-code
commands into machine-language commands that can be directly executed by the machine that's
running the Java program.
Multi-threaded: Java programs are multi-threaded and contain several threads of execution. Threads
initiate the execution of the lightest tasks within a program and share memory space and resources
with each other. These threads not only enable programs to handle several tasks concurrently but also
support two or more activities that can be performed in parallel within the same application.
Effectively used, they can prevent the user interface from being tied up while the program is
performing a lengthy operation.
All applications have at least one thread, which represents the program's main path of execution. Support
for multiple, synchronized threads is built directly into the Java language and runtime environment.
Synchronized threads are extremely useful in creating distributed, network-aware applications. Such an
application may be communicating with a remote server in one thread while interacting with a user in a
different thread.
Garbage collected: Java supports garbage collection. The garbage collector checks to see if there are
any objects that are no longer being used by the application. If such objects are present, then the
memory used by these objects can be reclaimed. Java programs do their own garbage collection, which
means that programs are not required to delete objects that they allocate in memory.
Robust: Java language supports some features and sub-systems that make it robust. The language also
solves certain pertinent programming problems. Java programs can be executed on a number of
platforms that use various forms of operating systems. With the aid of Java bytecode, Java can be run
on any system that contains a Virtual Java Machine.
Memory management has been simplified in Java in two ways. First, Java does not support direct pointer
manipulation or arithmetic. This makes it impossible for a Java program to overwrite memory or corrupt
data. Second, Java uses runtime garbage collection instead of explicit freeing of memory.
Because the Java interpreter checks all system access performed within a program, Java programs cannot
crash the system. Instead, when a serious error is revealed, Java programs create an exception.
Secure: Java incorporates advanced security features. The Java system not only authenticates all
memory access but also ensures that no viruses are affecting the system during an applet application.
Because Java does not use pointers to directly reference memory locations, as is prevalent in C and C++,
Java has a great deal of control over the code that exists within the Java environment. It was anticipated
that Java applications would run on the Internet and they could dynamically incorporate or execute code
found at remote locations on the Internet. Because of this, the developers of Java hypothesized the
7|Page
360digrii
Java course material
existence of a hostile Java compiler that would generate Java byte codes with the Internet of bypassing
Java's runtime security. This led to the concept of a byte-code verifier. The byte-code verifier examines
all incoming code to ensure that the code plays by the rules and is safe to execute. In addition to other
properties, the byte code verifier ensures the following:
No pointers are forged
No illegal object casts are performed
All parameters passed to functions are of the proper types
Rules regarding private, protected, and public class membership are followed
Extensible: Java programs support indigenous methods, which are functions written in another
language, usually C++. Support for indigenous methods enables programmers to write functions that
may execute faster than the other functions. Indigenous methods are dynamically linked to the Java
program; that is, they are associated with the program at runtime.
High performance: Java was designed and developed in order to achieve high performance. The Java
bytecode as well as the compilation features make the language easy to be assessed, translated and
interpreted. Java programming can be executed in even in low-power Central Processing Units. Though
a Java application is unlikely to achieve the performance of fully compiled language such as C or C++,
yet, for most applications, including graphics-intensive ones, such as are commonly found on the World
Wide Web, the performance of Java is more than adequate. For some applications, there may be no
discernible difference in performance between C and Java.
Interpreted: Because of performance concerns and other related issues modern programming
languages are designed to be compiled, not interpreted. Even C++ is compiled to an executable code.
Because Java is interpreted, once the Java interpreter has been ported to a specific machine, it can
instantly run the growing body of Java applications. As an example of the usefulness of this, imagine a
hypothetical chip manufacturer, Etnal that has just finished its newest CPU chip. This new chip named
as the Zintium serves as the foundation of new line of computer. Once Etnal ports the Java interpreter
to work on the Zintium, the new machine will be able to run all of Java development utilities-compiler,
the debugger and so on. Contrast this with a traditional language. If Etnal wants to release a C++
compiler with its new computer it must port, or create from scratch, the compiler, the debugger, the
runtime library, and so on. Another advantage is that the time-consuming edit-compile-link-test cycle
is broken. Without the compile and link steps, working in an interpreted environment is a much
simpler edit-test cycle. Without having to wait for lengthy compiles and links, Java promotes
prototyping and easier debugging.
Architecture-neutral: Java is architecture-neutral. Architecture neutrality is achieved in the
implementation of the Java interpreter for every new architecture. The Java compiler creates byte code
instructions that are consequently interpreted by the Java interpreter.
Portable: Java is a portable language and you can carry the entire java environment along with you.
The primary objective of the Java developers was to create a language that when written once is run
anywhere, any time, forever. To a large extent, this objective was accomplished. Java is also regarded as
portable because the compiler itself is written in Java. You can run Java programs on any machine or
operating system that supports a Virtual Java Machine.
8|Page
360digrii
Java course material
Distributed: Java aids in the building of distributed applications by a collection of classes for use in
networked applications. By using Java's URL (Uniform Resource Locator) class, an application can
easily access a remote server over an existing network.
Dynamic: Java is one of the languages, which is dynamically built. Java programs carry with them
significant amounts of run-time type information that is used to verify and resolve accesses to objects
at run time. At runtime, the Java environment can extend itself by linking classes that may be located
on remote servers on a network (for example, the Internet). This is a tremendous advantage over a
language like C++ that links classes prior to runtime.
Platform-independent: The programs written in C or C++ create object codes on compilation. The
object code keeps information about the platform where the language is initially compiled. The object
code can’t be executed in a heterogeneous platform; rather it can be executed in a platform wherever it
is created. Programs written in Java are converted into Bytecode after compilation. The Bytecode
format can be assessable from a heterogeneous platform thus making Java platform independent. In
order to execute Bytecode, the platform needs a JVM to be installed, which will interpret the Bytecode
to its corresponding platform dependent code.
Reconfiguration of the java library and addition of new elements to the library
Redefinition of the way events are handled by applets
The next major release of Java was Java 2. Java 2 carried the version number 1.2. Java 2 had certain new
features like Swing and Collections framework in the offing. It also contained a few deprecations. From the
‘Thread class’ certain methods like suspend (), resume (), and stop () were deprecated. The next release
of Java was Java version 1.3. Though this version did not integrate much of changes, yet it was the first
major improvement upon the original Java 2 release.
Java 2, version 1.4 contained several important amendments and supplements. Certain changes were
initiated with regard to collection framework. It appended:
the new keyword assert,
chained exceptions,
channel-based I/O subsystem.
Java 2, version 1.4 finally gave rise to J2SE 5. J2SE 5 contained varied forms of classes and some useful
programs for servers and workstations.
Java Programs
Java can be used to create two types of programs: applets and stand-alone applications. An Applet is
simply a part of a Web page, just as an image or a line of text can be. Just as a browser takes care of
displaying an image referenced in an HTML document, a Java-enabled browser locates and runs an Applet.
9|Page
360digrii
Java course material
When your Java-capable Web browser loads the HTML document, the Java applet is also loaded and
executed.
Using applets, you can do everything from adding animated graphics to your Web pages to creating
complete games and utilities that can be executed over the Internet. Some applets that have already been
created with Java include Bar Chart, which embeds a configurable bar chart in an HTML document;
Crossword Puzzle, which enables users to solve a crossword puzzle on the Web; and LED Sign, which
presents a scrolling, computerized message to viewers of the Web page within which the applet is
embedded.
Although most Java programmers are excited by the ability to create applets, Java can also be used to
create stand-alone applications-that is, applications that don't need to be embedded in a HTML document.
The most well known application is the Hot Java Web browser itself. This basic browser is completely
written in the Java language, showing how Java handles not only normal programming tasks such as
looping and evaluating mathematical expressions, but also how it can handle the complexities of
telecommunications programming.
class Hello
10 | P a g e
360digrii
Java course material
filenames. This means that DOS and Windows 3.1 are not capable of supporting Java. However, this is not a
problem with Windows 95 or Windows 98 or Windows NT.
As you can see by looking at the program, the name of the class defined by the program is also Hello. This
is not a coincidence but rather deliberate. In Java, a unit of code or a program must reside in a class. By
convention, the name of that class should match the name for the file that holds the program. You should
also make sure that the capitalization of the filename matches the class name, as Java is case-sensitive.
Compiling the Program
To compile the Hello program execute the compiler, javac specifying the name for the source file along
with it on the command as shown below:
C:\>javac Hello.java
The javac compiler creates file called Hello.class that contains the bytecode version of the program. The
Java bytecode is the intermediate representation of your program that contains platform neutral
instructions that the Java interpreter will execute. Thus the output of javac is not code than can be directly
executed.
To run the program, you must run the java interpreter, called java. To do so, pass the Hello.class file (only
the primary name is enough; the java interpreter will anyway look for a Hello.class file) as a command line
argument to the java interpreter as shown below:
C:\>java Hello
When the program is run, the following output is displayed:
Hello World
When Java source code is compiled, each individual class is put into its own output file named after the
class and using the .class extension. That is why it is a good idea to ascribe the java source files to the same
name as the class. When you execute the Java interpreter, you are actually specifying the name of the class
that you want the interpreter to execute. It will automatically search for a file by that name that has the
.class extension. If it finds the file, it will execute the code contained in the specified .class file.
Although Hello.java is quite short, it includes several key features that are central to all Java programs. You
will now closely examine each line of code in this program and appreciate its ramifications.
The program begins with the following lines:
/* This is a simple Java program.
Call this file Hello.java*/
This is a comment. Like most programming languages, Java lets you enter a remark into a program's
source file. Instead, comment explains or describes the operation of the program to anyone who is reading
its source code. Comments therefore enhance the readability of the code in its proper context. In this case
the comments describes the program and reminds you that the source file should be called Hello.java. The
use of the aforesaid comment is an example of a style of commenting that is referred to as multi-line
comment that runs into multiple lines.
11 | P a g e
360digrii
Java course material
Note: The compiler ignores the contents of a comment.
The next line of code in the program is shown below:
class Hello{
This line uses the keyword class to declare that a new class is being defined. Hello is an identifier that is
the name of the class. The entire class declaration, including all of its members (data and methods) will be
between the opening curly brace ({) and the closing curly brace (}). For the time being do not get into the
fundamentals of a class except to note that in Java, all program activity occurs within a class.
The next line in the program is the single-line comment, shown below:
//Your program starts executing from main:
This is the second style of comment supported by Java. A single-line comment begins with a // and
concludes at the end of the line. As a general rule, programmers use multi-line comments for longer
remarks and single-line comments for brief line-by-line descriptions.
The next line of code is shown below:
public static void main(String args[])
This line begins the main() method. As the comment preceding it indicates, this is the line at which the
program will begin executing. All Java applications begin execution by calling main(). The exact meaning of
each part of this line cannot be given now, since it involves a detailed understanding of Java's approach to
encapsulation. However, since most of the example in Java applications use this line of code, it is
appropriate that we broadly comprehend them right now.
The public keyword is an access specifier that allows the programmer to control visibility of class
members. When the keyword public precedes a class member, then the member is visible outside the class
in which it is declared (abstracting interfaces for the object of the class using which the external world can
interact with an object of that class). The opposite of public is private, which prevents a member from
being used by code outside of its class (keeping the implementation of an object of the class hidden or
encapsulating the inner working of an object of the class).
Generally, the variables and methods defined in a class come into existence and therefore can be used only
when an object of that class is created. It is customary therefore to first create an object of the class and
then use the variables and the methods defined in the class. In the light of this, the following paragraphs
should make it possible to arrive at a much clearer comprehension of the keyword static.
As you know by now, Java mandates that a unit of program be defined as a class. You also know that a Java
program commences execution at main(). Strictly speaking the main() function has so semantic relation to
the class in which it is defined. But the requirements of Java have forced the main() function to be defined
as a part of the class and not defined outside the class.
Otherwise we would be violating the rule of the Java language that a unit of code or a java program has to
be defined as a class we would have a class definition as well as a main() function outside of the class
resident in the same program file. This presents a dilemma when the Java Runtime Environment tries
execution of the main() method.
12 | P a g e
360digrii
Java course material
If the main() function were to be defined as a normal method of the class, it would be possible to invoke
main() only after instantiating an object of the class in which it is defined. But the trick is to initiate the
execution of the function main() prior to its class instantiation and then venture to create an object of the
class to which main() belongs to.
The key point to gather from the preceding paragraph is that there must be mechanism to initiate the
execution of the function main() even before instantiating an object of thee class to which it belongs to.
This can be accomplished provided the main() function’s invocation is not dependent on its class
instantiation as would normally have been the case. The answer lies in declaring the main() method in the
class as a static function. The moment a class member is declared static, it becomes class specific and is no
longer dependent on the class instance variables or instance methods as the case may be since they come
into existence subsequent to object instantiation.
The Java programming language is a strongly typed language. A strongly typed language is one where the
compiler enforces type checking at the time of compilation. For example, if a function was designed to
accept a float parameter and an integer is passed as an argument, a language like C would implicitly
convert the integer argument to float. This can lead to unpredictable output and undesirable side effects. A
strongly typed language would have caught this inconsistency and reported this error at compile time.
Extending the discussion further, if the aforesaid function were designed to return a float the compiler
would check that the actual value returned by the function is in fact a float value. Any other value returned
by the function would have been caught by the compiler at compile-time.
Type checking by the compiler therefore involves matching the date types for the arguments with the data
type of the parameters and also ensuring that the function's return value matches the return data type of
the function. If a function does not return any value its return data type must be declared to be of type
void.
Any information that you need to pass to method is received by variables specified within the set of
parentheses that follow the name of the method. These variables are called parameters. If there are no
parameters required for a given method you still need to include the empty parentheses. In main, there is
only one parameter. String args[] declares a parameter named args, which is an array of instances of the
class String-Arrays are collections of similar variables or objects. Objects of type String store character
strings. In this case, args receives any command-line arguments passed at the time of program execution.
This program does not make use of command-line arguments though it is possible that other programs
make use of them.
The last character on the line is the opening brace ({).This signals the start of main()'s body. All of the code
that comprises a method will occur between the method's opening brace and its closing curly brace. A
point worth reiterating is that main() is simply a starting place for the interpreter. A complex program will
have lots of classes only one of which will need to have a main() method to get things started.
The next line of code is the one that occurs within main(). Here it is:
System.out.println(“Hello World”);
This line outputs the string “Hello World” followed by a new line to screen. Output is accomplished by the
built-in println() method. In this case,println() displays the string that is passed to it. As you will see later,
println() can be used to display other types of information too. The line begins with System. out. While too
13 | P a g e
360digrii
Java course material
complicated to merit detailed discussion at this stage, it should suffice to say that System is a predefined
class that provides access to the system and out is the output stream that is connected to the console.
Console-based input/output is generally a feature of standalone Java applications but the relevance of Java
is more towards. Applets and Graphical user interface based programs. Console-based I/O does not apply
to I/O in Applets to GUI based programs.
You will notice that the println() statements ends with a semicolon. All executable statements in Java end
with a semicolon. The reason that the other lines in the program do not end in a semicolon is that they are
not, technically executable statements. The first closing brace(}) after the println() statement ends main(),
and the last closing brace(}) ends the Hello class definition.
14 | P a g e
360digrii
Java course material
Chapter 2 - Language Fundamentals: Data Types, Variables, Operators
Introduction to Data Types:
Each and every program written to be executed has one thing in common, that is to accept data and
process it depending on the instruction to provide an output. Assume that you have to find out the
summation of 5 & 6 without any computer or calculator. You have to remember the data 5 & 6 in your
memory. While doing the summation you have to recollect the data and apply plus operator in your mind
to come out with the result.
Trying to solve the same through a computer program, you have to find ways to store data so that the set
of instruction to sum two numbers can do their processing correctly and efficiently. In order to keep track
of data, you can use constants and variables in programs. In this chapter, you will discover and implement
constants and variables within your programs.
Here we examine Java’s most fundamental elements such as:
Data types
Variables
Arrays.
Like all modern programming languages, Java supports several types of data. In order to store data we
have to think of types of data to be stored. Hence java provides lot of data types to declare variables and to
create arrays.
Data Types:
Name Types
Character char
Floating-point numbers: This group includes float and double, which represent numbers with fractional
precision.
Characters: This group includes char, which represents symbols in a character set, like letters and
numbers.
Boolean: This group includes boolean, which is a special type for representing true/false values.
15 | P a g e
360digrii
Java course material
You can use these as simple data types, or user defined data types such as constructing arrays, or class
types. Thus, they form the basis for all other types of data that you can create.
The simple types are defined to have an explicit range. Languages such as C and C++ allow the size of an
integer to vary based upon the execution environment as it is not portable among platforms. Because of
Java’s portability feature, all data types have a strictly defined range. For example, an int is always 32 bits,
regardless of the particular platform. This allows programs to be written that are guaranteed to run
without porting on any machine architecture. While strictly specifying the size of an integer may cause a
small loss of performance in some environment, it is necessary in order to achieve portability.
Let’s look at each type of data in turn.
Integers:
Java supports integer types such as
byte
short
int
long
In Languages such as C & C++, you can store positive and negative values to these types of variables.
Java does not support unsigned, positive-only integers.
However, Java’s designers felt that unsigned integers were unnecessary. Specifically, they felt that the
concept of unsigned was used mostly to specify the behavior of the high-order bit, which defined the sign
of an int when expressed as a number. Java manages the meaning of the high-order bit differently, by
adding a special “unsigned right shift” operator. Thus, the need for an unsigned integer type was
eliminated.
The table below discuss about the size and range of values to be kept with the variables of respective
types. You should not think width of an integer type as of the amount of storage it consumes, but rather as
the behaviour it defines for variables and expressions of that type. The Java run-time environment is free
to use whatever size it wants, as long as the types behave as you declared them.
Name Sample
Declaration &
Type Description Size Range
initialization
Byte Signed integer 1 byte -128 to 127 int myInt = 100;
Short Signed integer 2 byte -32768 to 32767 short myShort =
1000;
Int Signed integer 4 byte -2147483648 to 2147483647 int myInt = 100000;
Long Signed integer 8 byte -9223372036854775808 to long myLong = 0;
9223372036854775807
16 | P a g e
360digrii
Java course material
byte
The type is byte. This is a signed 8-bit type that has a range from
–128 to 127. Variables of type byte are especially useful when you’re working with a stream of data from a
network or file. They are also useful when you’re working with raw binary data that may not be directly
compatible with Java’s other built-in types.
Following example shows declaration of two byte variables called b and c:
byte b, c;
short
short is a signed 16-bit type. It is probably the least-used Java type, since it is defined as having its high
byte first. This type is mostly applicable to 16-bit computers.
Following examples shows declaration of two short variable:
short s;
short t;
int
The most commonly used integer type is int. It is a signed 32-bit type. In addition to other uses, variables
of type int are commonly employed to control loops and to index arrays.
The int type is the most versatile and efficient type. There is a use of this type when you want to create a
number for counting or indexing arrays or doing integer math.
Following examples shows declaration of two short variables:
int s;
int t;
long
long is a signed 64-bit type and is useful for those occasions where an int type is not capable to hold the
desired value. This makes it useful when large whole numbers are needed.
Following examples shows declaration of two short variables:
long s;
long t;
Floating Point Numbers
Floating-point numbers, also known as real numbers, are used for storing fractional precision.
Look at the following example:
Calculations such as square root, sine and cosine, result in a value whose precision requires a floating-
point type. Java implements the standard set of floating-point types and operators. There are two types of
floating-point types, float and double, which represent single- and double-precision numbers,
respectively. Their size and ranges are shown in the following table:
17 | P a g e
360digrii
Java course material
Name Sample Declaration &
initialization
Type Description Size Range
Float IEEE 754 floating 4 bytes ±1.4E-45 to ±3.4028235E+38 float myFloat = 10.0f;
point
Double IEEE 754 floating 8 bytes ±4.9E-324 to double myDouble = 20.0;
point ±1.7976931348623157E+308
class AreaOfCircle {
}}
18 | P a g e
360digrii
Java course material
The output of the program:
Area of the circle is 366.436224
Characters
The data type used to store characters such as any alphabet is char. This data type in Java is not the same
as char in C or C++. In C/C++, char is of 8 bits wide. In Java char data type supports multi byte size. This is
so because while storing some characters of local language it takes more than one byte. It is a unification of
dozens of character sets, such as Latin, Greek, Arabic, Cyrillic, Hebrew, Katakana, Hangul, and many more.
Following table discuss about the char data type.
class CharTypeDemo {
char1 = 65;
char2 = 'Z';
}
CharTypeDemo.java displays the following output:
char1 and char2: A Z
19 | P a g e
360digrii
Java course material
Explaining the program, the variable char1 is assigned with the value 99, which is the ASCII (and Unicode)
value that corresponds to the letter A. As mentioned, the ASCII character set occupies the first 127 values
in the Unicode character set. For this reason, all the “old tricks” that you have used with characters in the
past will work in Java, too.
Even though chars are not integers, in many cases you can operate on them as if they were integers. This
allows you to add two characters together, or to increment the value of a character variable.
Consider the program CharTypeDemo2.java:
// char variables behave like integers.
class CharTypeDemo2 {
char char1;
char1 = 'A';
}
The output generated by CharDemo2.java is shown here:
char1 contains A
char1 is now B
Explaining the program, char1 is first given the value A. Next, char1 is incremented. This results in char1
containing B, the next character in the ASCII (and Unicode) sequence.
Booleans
Java has a simple type for storing logical values, called Boolean. It can consist of one of two possible
values, true or false. This is the type returned by all relational operators, such as a < b. boolean is also the
type required by any conditional expressions that govern the control statements such as if and for.
20 | P a g e
360digrii
Java course material
Following program demonstrates the boolean type:
BoolVarTest.java
// Demonstrate boolean values.
class BoolVarTest {
boolean b1;
b1 = false;
b1 = true;
b1 = false;
}
The output generated by BoolVarTest.java is shown here:
b1 is false
b1 is true
This is executed.
10 > 9 is true
There are three interesting things to notice about this program. First, as you can see, when a boolean
value is output by println( ), “true” or “false” is displayed. Second, the value of a boolean variable is
sufficient, by itself, to control the if statement. There is no need to write an if statement like this:
21 | P a g e
360digrii
Java course material
if(b1 == true) ...
Third, the outcome of a relational operator, such as <, is a boolean value. This is why the expression 10 >
9 displays the value “true.” Further, the extra set of parentheses around 10 > 9 is necessary because the +
operator has a higher precedence than the >.
The first computer languages were developed by mathematicians. For that reason, the calculations and the
variables used in those calculations were modeled after the types of equations mathematicians were
already accustomed to working with. For example, in the old days, the lines in your tax program might
have looked like this:
a = b * c;
d = b + a;
As you can see, this type of variable-naming convention left a lot to be desired. It's virtually impossible to
tell what types of calculations are being performed. In order to understand and remember their own
programs, programmers used tons of comments mixed in with their source code. Such a section of source
code in Java might look like the following example.
An Example of Mathematician's Variables.
a = b * c;
d = b + a;
Although adding comments to the program lines helps a little, the code is still pretty confusing, because
you don't really know what the variables a, b, c, and d stand for. After a while , someone came up with the
idea of allowing more than one character in a variable name, which would enable the programmer to
create mathematical expressions that read more like English. Thus, the confusing example above would be
written as the following example.
An Example Using English-like Variable Names.
// Calculate the amount of sales tax.
22 | P a g e
360digrii
Java course material
By using carefully chosen variable names, you can make your programs self documenting, which means
that the program lines tells anyone reading the program what the program does. If you strip away the
comments from the preceding example, you can still see what calculations are being performed.
Of course, there are rules for choosing constant and variable names (also known as identifiers because
they identify a program object). You can't just type a bunch of characters on your keyboard and expect
Java to accept them. First, every Java identifier must begin with one of these characters:
A-Z
a-z
_
$
The preceding characters are any uppercase letter from A through Z, any lowercase letter from a through
z, an underscore, and the dollar sign.
Following the first character, the rest of the identifier can use any of these characters:
A-Z
a-z
_
$
0-9
As you may have noticed, this second set of characters is very similar to the first. In fact, the only
difference is the addition of the digits from 0 through 9.
Using the rules given, the following are valid identifiers in a Java program:
Number
number2
amount_of_sale
$amount
23 | P a g e
360digrii
Java course material
The following identifiers are not valid in a Java program:
1number
amount of
sale
&amount
item#
Creating Identifiers
24 | P a g e
360digrii
Java course material
the result of the calculation. Again, stating the problem leads to the variable name, which might be
remaining_spaces. The final calculation then looks like this:
remaining_spaces = TOTALSPACES - total_vehicles;
Literals
25 | P a g e
360digrii
Java course material
Boolean Literals
The Boolean values true and false also are literals. These are the only two values you can use when
assigning a value to a boolean variable type or using a Boolean in a statement in other ways.
If you have used another language such as C, you might expect that a value of 1 is equivalent to true and 0
is equivalent to false. This isn't the case in Java—you must use the values true or false to represent
Boolean values. The following statement uses a literal to set up a boolean variable:
boolean chosen = true;
Note: The literal ‘true’ does not have quotation marks around it. If it did, the Java compiler would assume
that it was a string of characters.
Character Literals
Character literals are expressed by a single character surrounded by single quotation marks, such as 'a',
'#', and '3'. You might be familiar with the ASCII character set, which includes 128 characters including
letters, numerals, punctuation, and other characters useful in computing. Java supports thousands of
additional characters through the 16-bit Unicode standard.
Some character literals represent characters that are not readily printable or accessible through a
keyboard. Table 3 lists the special codes that can represent these special characters as well as characters
from the Unicode character set. The letter d in the octal, hex, and Unicode escape codes represents a
number or a hexadecimal digit (a–f or A–F).
Escape Meaning
\n New line
\t Tab
\b Backspace
\r Carriage return
\f Formfeed
\\ Backslash
\' Single quotation mark
\" Double quotation mark
\d Octal
\xd Hexadecimal
\ud Unicode character
Note: C and C++ programmers should know that Java does not include character codes for \a (alert), \v
(vertical tab) and \? (Question mark).
26 | P a g e
360digrii
Java course material
String Literals
A string in Java is an object rather than being a basic data type, and strings are not stored in arrays as they
are in languages such as C.
Because string objects are real objects in Java, methods are available to combine strings, modify strings,
and determine whether two strings have the same value.
String literals consist of a series of characters inside double quotation marks, as in the following
statements:
String svalue = "How are you?”;
Strings can include the character escape codes listed in Table 3, as shown here:
String example = "Ritu asked, \"Is Java a programming Language?\"";
Although string literals are used in a manner similar to other literals in a program, they are handled
differently behind the scenes.
When a string literal is used, Java stores that value as a String object. You don't have to explicitly create a
new object, as you must do when working with other objects, so they are as easy to work with as basic
data types. Strings are unusual in this respect—none of the basic types is stored as an object when used.
Keywords are special reserved words in Java that cannot be used as identifiers (names) for classes,
methods, or variables.
Table 7 shows list of Java keywords and reserved words, which are updated through Java 5.0. ‘const’ and
‘goto’ are reserved but are not implemented. ‘enum’ is the latest keyword and was added to the language
in Java 5.0 (displayed in bold letter in Figure 1). Remember that none of the words in this list can be used
as identifiers in Java programs.
Operators
Now that you've learned how to declare and initialize variables, you probably want to know how to do
something with them. Learning the operators of the Java programming language is a good place to start.
27 | P a g e
360digrii
Java course material
Operators are special symbols that perform specific operations on one, two, or three operands, and then
return a result.
The Simple Assignment Operator
One of the most common operators that you'll come upon is the simple assignment operator "=". You saw
this operator in the Bicycle class; it assigns the value on its right and the operand on its left:
int cadence = 0;
int speed = 0;
int gear = 1;
This operator can also be used on objects to assign object references, as discussed in Simple Data Objects.
The Arithmetic Operators
The Java programming language provides operators that perform addition, subtraction, multiplication,
and division. There's a good chance you'll recognize them by their counterparts in basic mathematics. The
only symbol that might look new to you is "%",. The symbol "%", which divides one operand by another
and returns the remainder as its result.
additive operator +
subtraction operator -
multiplication operator *
division operator /
Remainder operator %
class ArithmeticDemo {
28 | P a g e
360digrii
Java course material
System.out.println(result);
}
}
You can also combine the arithmetic operators with the simple assignment operator to create compound
assignments. For example, x+=1; and x=x+1; both increment the value of x by 1.
The + operator can also be used for concatenating (joining) two strings together, as shown in
ConcatDemo.java:
ConcatDemo.java
class ConcatDemo {
public static void main(String[] args){
String firstString = "This is";
String secondString = " a concatenated string.";
String thirdString = firstString+secondString;
System.out.println(thirdString);
}
}
By the end of ConcatDemo.java, the variable thirdString contains "This is a concatenated string.", which
gets printed to standard output.
The Unary Operators
The unary operators require only one operand; they perform various operations such as
incrementing/decrementing a value by one, negating an expression, or inverting the value of a boolean.
+ Unary plus operator; indicates positive value (numbers are positive without this, however)
- Unary minus operator; negates an expression
++ Increment operator; increments a value by 1
-- Decrement operator; decrements a value by 1
! Logical complement operator; inverts the value of a boolean
The program UnaryDemo.java tests the unary operators:
UnaryDemo.java
class UnaryDemo {
class PrePostDemo {
public static void main(String[] args){
int i = 3;
i++;
System.out.println(i); // "4"
++i;
System.out.println(i); // "5"
System.out.println(++i); // "6"
System.out.println(i++); // "6"
System.out.println(i); // "7"
}
}
30 | P a g e
360digrii
Java course material
== Equal to
!= not equal to
class ComparisonDemo {
31 | P a g e
360digrii
Java course material
ConditionalDemo1.java, tests these operators:
ConditionalDemo1.java
class ConditionalDemo1 {
}
}
Another conditional operator is ?:, which can be thought of as shorthand for an if-then statement
(discussed in the Control Flow Statements section of this lesson). In the following example, this operator
should be read as: "If someCondition is true, assign the value of value1 to result. Otherwise, assign the
value of value2 to result."
ConditionalDemo2.java, tests the ?: operator:
ConditionalDemo2.java
class ConditionalDemo2 {
System.out.println(result);
}
}
Because some Condition is true, this program prints "1" to the screen. Use the ?: operator instead of an if-
then-else statement if it makes your code more readable; for example, when the expressions are compact
and without side-effects (such as assignments).
class Parent{}
interface MyInterface{}
When using the instanceof operator, keep in mind is that null is not an instance of anything.
The Java programming language also provides operators that perform bitwise and bit shift operations on
integral types. The operators discussed in this section are less commonly used. Therefore, their coverage is
brief; the intent is to simply make you aware that these operators exist.
The unary bitwise complement operator "~" inverts a bit pattern; it can be applied to any of the integral
types, making every "0" a "1" and every "1" a "0". For example, a byte contains 8 bits; applying this
operator to a value whose bit pattern is "00000000" would change its pattern to "11111111".
The signed left shift operator "<<" shifts a bit pattern to the left by one position. The signed right shift
operator ">>" shifts a bit pattern to the right by one position. The unsigned right shift operator ">>>"
shifts a zero into the leftmost position, while the leftmost position after ">>" depends on sign extension.
33 | P a g e
360digrii
Java course material
The bitwise & operator performs a bitwise AND operation.
The bitwise ^ operator performs a bitwise exclusive OR operation.
The bitwise | operator performs a bitwise inclusive OR operation.
For & and | above, the result has a 1 in each bit position for which both of the operands have a 1.
The following program named BitDemo.java, uses the bitwise AND operator to print the number "2" to
standard output.
BitDemo.java
class BitDemo {
public static void main(String[] args) {
int bitmask = 0x000F;
int val = 0x2222;
System.out.println(val & bitmask); // prints "2"
}
}
As we explore the operators of the Java programming language, it may be helpful for you to know ahead of
time which operators have the highest precedence/importance. The operators in the following table are
listed according to precedence/importance.
The closer to the top of the table an operator appears, the higher its precedence. Operators with higher
precedence are evaluated before operators with relatively lower precedence.
Operators on the same line have equal precedence. When operators of equal precedence appear in the
same expression, a rule must govern which is evaluated first. All binary operators except for the
assignment operators are evaluated from left to right; assignment operators are evaluated right to left.
Operators Precedence
Postfix expr++ expr--
Unary ++expr --expr +expr -expr ~ !
Multiplicative */%
Additive +-
Shift << >> >>>
Relational < > <= >= instanceof
Equality == ! =
Bitwise AND &
Bitwise exclusive OR ^
Bitwise inclusive OR |
Logical AND &&
Logical OR ||
Conditional ?:
Assignment = += -= *= /= %= &= ^= |= <<= >>= >>>=
Table 10: Operator Precedence Table
34 | P a g e
360digrii
Java course material
Summary of Operators
The following quick reference summarizes the operators supported by the Java programming language.
Simple Assignment Operator
= simple assignment operator
Arithmetic Operators
+ additive operator (also used for String concatenation)
- subtraction operator
* multiplication operator
/ division operator
% remainder operator
Unary Operators
+ Unary plus operator; indicates positive value (numbers are positive without this, however)
- Unary minus operator; negates an expression
++ Increment operator; increments a value by 1
-- Decrement operator; decrements a value by 1
! Logical compliment operator; inverts the value of a boolean
Equality and Relational Operators
== equal to
!= not equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
Conditional Operators
&& Conditional-AND
|| Conditional-OR
Type Comparison Operator
instanceof compares an object to a specified type
Bitwise and Bit Shift Operators
~ unary bitwise complement
<< signed left shift
35 | P a g e
360digrii
Java course material
>> signed right shift
>>> unsigned right shift
& bitwise AND
^ bitwise exclusive OR
| bitwise inclusive OR
In general-purpose programming, certain operators tend to appear more frequently than others; for
example, the assignment operator "=" is far more common than the unsigned right shift operator ">>>".
With that in mind, the following discussion focuses first on the operators that you're most likely to use on
a regular basis, and ends focusing on those that are less common. Each discussion is accompanied by
sample code that you can compile and run. Studying its output will help enforce what you've just learned.
36 | P a g e
360digrii
Java course material
Chapter 3 : Language Fundamentals –Control Statements
Introduction
The computer programs are written with statements which helps in organizing the program structure and
its meaning. When you write a program, you type statements into a file. In programs, the individual
statement, instructions or function calls of an imperative or functional program are executed. With the
increasing demand of conditions and complications arising in a particular work or in solving a program, it
is necessary to control the flow of the program. Without control flow statements, the interpreter executes
the statements in the order they appear in the file from left to right, top to bottom. What if you wanted to
change the flow?
For example, you want the program to take some decisions and do different things depending on different
situations such as printing 'Good Morning' or 'Good Evening' depending on the time of the day?
As you might have guessed, this is achieved using control flow statements.
Table 1 shows categories of control flow statements available in Java and keywords list for each
categories.
Control flow statement category Keyword list
Selection statements if, else, switch, case
37 | P a g e
360digrii
Java course material
Selection statements in Java
A program is a group of statements that are executed to achieve a predetermined task. Statements in a
program are generally executed in a sequential manner, which is called sequential execution or sequential
control flow. Selection statements are used in a program to choose different paths of execution based upon
the outcome of an expression or the state of a variable. Java supports two selection statements: if and
switch.
b>a
The If-else Statement
The "if-else" statement is an extension of if statement that provides another option when 'if' statement
evaluates to "false" i.e. else block is executed if "if" statement is false. You can either have a single
statement or a block of code within if-else blocks. The else statement is optional,but if it is present,it must
be placed immediately after the code block attached to the if statement. The code block attached to the
else statement is executed when the condition to the if statement evaluates to false.
38 | P a g e
360digrii
Java course material
The general form of the if statement is given below:
if (condition)
{
statement1;
}
else
{
statement2;
The following example demonstrates conditional execution based on if-else statement condition.
Output
b>a
The chained If-else Statement
Under the “chained format” the execution evaluates all conditional expressions beginning from
Expression1 (given below) until the first expression is found that evaluates to true. Then the
corresponding statement sequence is executed, or, if none of the expressions evaluated to true, the
statement sequence of the final else part.
The general form of the if statement is given below:
if ( Expression1 ) {
Statement1a
Statement1b
...
} else if ( Expression2 ) {
Statement2a
39 | P a g e
360digrii
Java course material
Statement2b
...
} else if ( Expression3 ) {
Statement3a
Statement3b
...
} else {
Statement4a
Statement4b
...
}
The following example demonstrates conditional execution based on if-else-if statement condition.
IV
The Switch Case Statements
The switch case statement, also called a case statement is a multi-way branch with several choices. A
switch is easier to implement than a series of if/else statements. The switch statement begins with a
keyword, followed by an expression that equates to a no long integral value. Following the controlling
expression is a code block that contains zero or more labeled cases. Each label must equate to an integer
constant and each must be unique. When the switch statement executes, it compares the value of the
controlling expression to the values of each case label. The program will select the value of the case label
40 | P a g e
360digrii
Java course material
that equals the value of the controlling expression and branch down that path to the end of the code block.
If none of the case label values match, then none of the codes within the switch statement code block will
be executed. Java includes a default label to use in cases where there are no matches. We can have a nested
switch within a case block of an outer switch.
The argument to the switch must be an integral expression that must evaluate to a 32-bit or smaller
integer type: byte,short,char,or int. Moreover,the legal range of the argument's data type must cover all the
case constants used in the code block. For example,the following code fragment will not compile
successfully:
byte b = 10;
switch( b ){
case 10 :
System.out.print("ten");
break ;
case 10 :
System.out.print("10") ;
break ;
41 | P a g e
360digrii
Java course material
In the given code, the compiler will object to the second appearance of the value 10 in line 6. An
appropriate example demonstrating the use of switch case to find the greatest among three numbers is
provided below.
public class SwitchCaseStatementDemo {
c is the greatest
Of course, you could also implement the same thing with if-then-else statements. Deciding whether to use
if-then-else statements or a switch statement is sometimes a judgment call. You can decide which one to
use based on readability and other factors. An if-then-else statement can be used to make decisions based
on ranges of values or conditions, whereas a switch statement can make decisions based only on a single
integer or enumerated value.
42 | P a g e
360digrii
Java course material
Iteration Statements in Java
Iteration statements enable program execution to repeat one or more statements, i.e. iteration statements
form loops. In Java, there are three iteration statements: for, while and do. An enhanced for loop has been
added in J2SE 5.
The for statement
The for loop is the most versatile looping construct. It is used to continuously execute a block of code until
a particular condition is satisfied. It comprises three parts: initialization, condition and iteration.
The initialization portion is generally an expression that sets the value of the loop control variable. The
loop control variable acts as a counter and controls the execution of the loop. The initialization portion
executes only once. The condition portion must be a boolean expression. It usually tests the loop control
variable against a target value and hence works as a loop terminator. The iteration portion is usually an
expression that increments or decrements the loop control variable.
The general form of the for loop is:
for(initialization; condition; iteration)
{
//body of the loop
}
All the three components, i.e., initialization, condition and iteration are optional. In case there is only a
single statement in the body of the loop, the curly braces can be omitted.
The for loop executes in the following three steps:
When the loop first starts, the initialization expression is executed and then the control is transferred to step 2.
The condition is evaluated. If the condition evaluates to true, the body of the loop executes and the program control
is transferred to step 3. If the condition evaluates to false, the loop terminates.
The iteration expression executes and then the control is transferred to step 2.
All the sections in the for-header are optional. Any one of them can be left empty, but the two semicolons
are mandatory. In particular, leaving out the <condition> signifies that the loop condition is true. The (;;)
form of for loop is commonly used to construct an infinite loop. Below is an example that demonstrates the
looping construct namely for loop used to print numbers from 1 to 10.
public class ForLoopDemo {
43 | P a g e
360digrii
Java course material
Output:
44 | P a g e
360digrii
Java course material
The general form of the while loop is as follows:
while(condition)
{
block
}
where, the condition may be any expression that evaluates to a boolean value. The code block attached to
the while statement is repeatedly executed unless the condition evaluates to false. Below is an example
that demonstrates the looping construct namely while loop used to print numbers from 1 to 10.
public class WhileLoopDemo {
Jump statements are used to unconditionally transfer the program control to another part of the program.
Java has three jump statements: break, continue and return.
The break statement
A break statement is used to abort the execution of a loop. The general form of the break statement is
given below:
break;
class BreakDemo
{
int count = 5;
while(true) {
if(count == 5) {
break;
}}}}
A break may be used with or without a label. When it is used without a label, it aborts the execution of the
innermost switch, for, do, or while statement enclosing the break statement. When used with a label, the
break statement aborts the execution of any enclosing statement matching the label. When used with a
label the syntax is:
break label;
Note: A label is an identifier that uniquely identifies a block of code.
46 | P a g e
360digrii
Java course material
The continue statement
A continue statement stops the iteration of a loop (while, do or for) and causes execution to resume at the
top of the nearest enclosing loop. You use a continue statement when you do not want to execute the
remaining statements in the loop, but you do not want to exit the loop itself.
The syntax of the continue statement is
continue; // the unlabeled form
continue <label>; // the labeled form
You can also provide a loop with a label and then use the label in your continue statement. The label name
is optional, and is usually only used when you wish to return to the outermost loop in a series of nested
loops.
Below is a program to demonstrate the use of continue statement to print Odd Numbers between 1 to 10.
public class ContinueExample {
Arrays
Why array is needed?
You might come across a situation where you need to store similar type of values for a large number of
data items.
For e.g.
To store the marks of all the students of a university, you need to declare thousands of variables. In
addition, each variable name needs to be unique. It would not be practical to hold each in a separately
named variable. To avoid such situations, you can use arrays. Instead of using individual variables, we will
use a whole number of variables.
An array consists of a name and the number of elements of the array. You can refer to a specific array
element by the array name and the element number, which is known as the index number.
You should always remember that array index element number always starts with 0(zero).
An array is a container object that holds a fixed number of values of a single type. The length of an array is
established when the array is created. After creation, its length is fixed. This section discusses arrays in
greater detail.
48 | P a g e
360digrii
Java course material
Each item in an array is called an element, and each element is accessed by its numerical index. As shown
in the above illustration, numbering begins with 0. The 9th element, for example, would therefore be
accessed at index 8.
Creating Arrays
The length of an array is fixed at the time of its creation. An array represents related entities having the
same data type in contiguous or adjacent memory locations. The related data having data items form a
group and are referred to by the same name.
For e.g.
employee[5];
Here, the employee is the name of the array and of size 5. The complete set of values is known as an array
and the individual entities are called as elements of the array.
A specific value in an array is accessed by placing the index value of the desired element in a square
bracket.
You can refer to a large number of elements by just specifying the index number and the array name.
Arrays make it easy to do calculations in a loop.
One-dimensional Arrays
49 | P a g e
360digrii
Java course material
Length of an array
Each array has a constant (final) instance variable that has its length. You can find out how many elements
an array can hold by writing the array name followed by .length. In the previous example, a.length would
be 100. Remember that this is the number of elements in the array, one more than the maximum subscript.
Accessing Arrays
You need to access various elements of an array to assign, retrieve, and manipulate the values stored in the
array.
Assigning values to the Elements of an Array
To access a specific array,
You need to specify the name of the array and the index number of the element.
The index position of the first element in the array is 0.
For e.g.
String designations[];
designations = new String[2];
designations[0] = “General Manager”;
designations[1]=”Managing Director”;
You can declare and allocate memory to a user-defined array in a single statement.
Syntax:
type arr [] = new type[size];
For e.g.
int employees[] = new int[10];
You can also declare and initialize arrays in the same statement.
For e.g.
String designations[] = {“General Manager”, ”Managing Director”};
Example - ArrayDemo.java
class ArrayDemo {
public static void main(String[] args) {
int[] anArray; // declares an array of integers
anArray = new int[10];// allocates memory for 10 integers
anArray[0] = 100; // initialize first element
anArray[1] = 200; // initialize second element
anArray[2] = 300; // etc.
50 | P a g e
360digrii
Java course material
anArray[3] = 400;
anArray[4] = 500;
anArray[5] = 600;
anArray[6] = 700;
anArray[7] = 800;
anArray[8] = 900;
anArray[9] = 1000;
System.out.println("Element at index 0: " + anArray[0]);
System.out.println("Element at index 1: " + anArray[1]);
System.out.println("Element at index 2: " + anArray[2]);
System.out.println("Element at index 3: " + anArray[3]);
System.out.println("Element at index 4: " + anArray[4]);
System.out.println("Element at index 5: " + anArray[5]);
System.out.println("Element at index 6: " + anArray[6]);
System.out.println("Element at index 7: " + anArray[7]);
System.out.println("Element at index 8: " + anArray[8]);
System.out.println("Element at index 9: " + anArray[9]);
}
}
The output of ArrayDemo.java is:
Element at index 0: 100
Element at index 1: 200
Element at index 2: 300
Element at index 3: 400
Element at index 4: 500
Element at index 5: 600
Element at index 6: 700
Element at index 7: 800
Element at index 8: 900
Element at index 9: 1000
In a real-world programming situation, you would probably use one of the supported looping constructs to
iterate through each element of the array, rather than write each line individually as shown above.
51 | P a g e
360digrii
Java course material
However, this example clearly illustrates the array syntax. You will learn about the various looping
constructs (for, while, and do-while) in the chapter on control statements.
for(int x=0;x<=9;x++)
int y=0;
while(y<=9)
y++;
Two-dimensional Arrays
In addition to one-dimensional arrays, you can create two-dimensional arrays. To declare two-
dimensional arrays, you need to specify multiple square brackets after the array name.
Syntax to declare a two dimensional array
type array_name = new type[rows][cols];
For e.g.
int multidim[] = new int[3][];
In a two-dimensional array,
You need to allocate memory for only the first dimension.
You can allocate the remaining dimensions separately.
When you allocate memory to the second dimension, you can also allocate different number to each dimension.
For e.g.
int multidim[] = new int[3][];
multidim[0] = new int[1];
multidim[1] = new int[4];
If you think of a one-dimensional array as a column of values you can think of a two-dimensional array as a
table of values like so:
53 | P a g e
360digrii
Java course material
c0 c1 c2 c3
r0 0 1 2 3
r1 1 2 3 4
r2 2 3 4 5
r3 4
r4 3 5
4 5 7
6 6
Here we have an array with five rows and four columns. It has twenty total elements. However, we say it
has dimension five by four, not dimension twenty. This array is not the same as a four by five array like
this one:
c0 c1 c2 c3 c4
r0 0 1 2 3 4
r1 1 2 3 4 5
r2 2 3 4 5 6
r3 3 4 5 6 7
We need to use two numbers to identify a position in a two-dimensional array. These are the element's
row and column positions. For instance if the above array is called J then J[0][0] is 0, J[0][1] is 1, J[0][2] is
2, J[0][3] is 3, J[1][0] is 1, and so on.
Here is how the elements in a four by five array called M are referred to:
M[0][0] M[0][1] M[0][2] M[0][3] M[0][4]
Searching in an array
One common task is searching an array for a specified value. Sometimes the value may be known in
advance. Other times you may want to know the largest or smallest element.
Unless you have some special knowledge of the contents of the array (for instance, that it is sorted) the
quickest algorithm for searching an array is straightforward linear search. Use a for loop to look at every
element of the array until you find the element you want. Here's a simple method that prints the largest
and smallest elements of an array:
Sorting
All sorting algorithms rely on two fundamental operations, comparison and swapping. Comparison is
straightforward. Swapping is a little more complex. Consider the following problem. We want to swap the
value of a and b. Most people propose something like this as the solution:
56 | P a g e
360digrii
Java course material
class Swap1 {
public static void main(String args[]) {
int a = 1;
int b = 2;
System.out.println("a = "+a);
System.out.println("b = "+b);
// swap a and b
a = b;
b = a;
System.out.println("a = "+a);
System.out.println("b = "+b);
}
}
This produces the following output:
a=1
b=2
a=2
b=2
That is not what you expected! The problem is that we lost track of the value 1 when we put the value of b
into a. To correct this we need to introduce a third variable, temp, to hold the original value of a.
class Swap2 {
public static void main(String args[]) {
int a = 1;
int b = 2;
int temp;
System.out.println("a = "+a);
System.out.println("b = "+b);
// swap a and b
temp = a;
a = b;
b = temp;
System.out.println("a = "+a);
System.out.println("b = "+b);
}
}
This code produces the output we expect:
a=1
b=2
a=2
b=1
57 | P a g e
360digrii
Java course material
Bubble Sort
Now that we have learned how to properly swap the values of two variables, let us proceed to sorting.
There are many different sorting algorithms. One of the simplest and the most popular algorithms is
referred to as bubble sort. The idea of bubble sort is to start at the top of the array. We compare each
element to the next element. If it’s greater than that element then we swap the two. We pass through the
array as many times as necessary to sort it. The smallest value bubbles up to the top of the array while the
largest value sinks to the bottom. (You could equally well call it a sink sort, but then nobody would know
what you were talking about.) Here is the code:
import java.util.*;
class BubbleSort {
public static void main(String args[]) {
int[] n;
n = new int[10];
Random myRand = new Random();
// initialize the array
for (int i = 0; i < 10; i++) {
n[i] = myRand.nextInt();
}
// print the array's initial order
System.out.println("Before sorting:");
for (int i = 0; i < 10; i++) {
System.out.println("n["+i+"] = " + n[i]);
}
boolean sorted = false;
// sort the array
while (!sorted) {
sorted = true;
for (int i=0; i < 9; i++) {
if (n[i] > n[i+1]) {
int temp = n[i];
n[i] = n[i+1];
n[i+1] = temp;
sorted = false;
}
}
}
// print the sorted array
System.out.println();
System.out.println("After sorting:");
for (int i = 0; i < 10; i++) {
System.out.println("n["+i+"] = " + n[i]);
}
}
58 | P a g e
360digrii
Java course material
}
Example MultiDimArrayDemo.java
class MultiDimArrayDemo {
public static void main(String[] args) {
String[][] names = {{"Mr. ", "Mrs. ", "Ms. "},
{"Smith", "Jones"}};
System.out.println(names[0][0] + names[1][0]); //Mr. Smith
System.out.println(names[0][2] + names[1][1]); //Ms. Jones
}
}
The output of MultiDimArrayDemo.java is:
Mr. Smith
Ms. Jones
Finally, you can use the built-in length property to determine the size of any array. The code
System.out.println(anArray.length);
59 | P a g e
360digrii
Java course material
char[] copyTo = new char[7];
System.arraycopy(copyFrom, 2, copyTo, 0, 7);
System.out.println(new String(copyTo));
}
}
The output of ArrayCopyDemo.java is:
Caffeina
Arrays of Objects
Just as you can have arrays of primitives, so you can have arrays of objects too. The following tells you
your longest and shortest films:
60 | P a g e
360digrii
Java course material
if (mins > longtime) {
longtime=mins;
Longest = Watch[i];
}
}
}
System.out.println("Longest film is " +
Longest.getcalled() +
" at "+longtime+" minutes");
System.out.println("Shortest film is " +
Shortest.getcalled() +
" at "+shorttime+" minutes");
}
}
//The Film class
class Film
{
private String name;
private int duration;
public Film(String nm,int time)
{
name=nm;
duration=time;
}
public int getminutes()
{
return duration;
}
public String getcalled()
{
return name;
}
}
Output:
Longest film is Shrek at 133 minutes
Shortest film is The Truth about Cats and Dogs at 93 minutes
61 | P a g e
360digrii
Java course material
Chapter 5 – Introducing Classes and Objects
Introduction
There is no doubt that ‘Class’ is at the core of object Oriented Architecture. It is a construct that is used in
the entire Java language. ‘Class’ in turn implements the Object Oriented Programming features and defines
the shape and nature of an object. Any concept, code or logic that you wish to implement in a Java program
must be encapsulated within a “Class”. In this chapter you will be introduced to the basic elements of a
class. You will learn how a class can be used to create objects. You will also gain knowledge about the
methods, constructors, Inheritance, Polymorphism and the ‘this’ keyword.
Class Fundamentals
A class is nothing but a blueprint or a template for creating different objects, which defines its properties
and behaviors. Java class objects exhibit the properties and behaviors defined by its class. A class can
contain fields and methods to describe the behavior of an object.
When you define and create a class, you have to declare its exact attributes & behaviors required. You do
this by specifying the attributes that it will contain and the behavior in the form of code that operates on
the same data. While the very simple classes may contain only behavior (methods) or only attributes
(data), most real-world classes contain both.
You can declare a class by using the ‘class’ keyword.
Following is the example of a general form of a class:
class classname {
type instance-variable1;
type instance-variable2;
// ...
type instance-variableN;
type methodname1(parameter-list) {
// body of method
type methodname2(parameter-list) {
// body of method
62 | P a g e
360digrii
Java course material
// ...
type methodnameN(parameter-list) {
// body of method
The data or attributes, defined within a class are called instance variables as each instance of the class
(that is, each object of the class) contains its own copy of these variables. The code is contained within
behavior (methods). A class contains methods and attributes. These methods and attributes are
collectively known as members of a class. Methods (which are accessible outside of the class) that are
defined for the same classes can act upon and access instance variables within that class itself. This
happens for most classes. How the data of a class can be used is thus decided by the method.
The main () method has the same general form as all the other methods. Most of the methods, however, do
not have access specifier as static or public.
You can specify multiple classes within a program. You should keep in mind that every class does not
consist of a main() method. You can only specify one, in that class which will be executed by the Java
Runtime.
Now you may consider that a class is a sort of a template for an object. In this way, a class is equivalent to a
data type such as int. The main difference is that Java already knows what an integer is. However, when
you create a class, you must tell Java about the class's distinctiveness. You define a class by using the ‘class’
keyword along with the class name, like this:
class MyClass
}
Believe it or not, the preceding lines are a complete Java class. If you save the lines in a file called
MyClass.java, you could even compile the class into a .CLASS file, although the file won't actually do
anything if you tried to run it. As you can see, the class definition begins with the keyword ‘class’ followed
by the name of the class. The body of the class is marked off by curly braces just like any other program
block. In this case, the class's body is empty.
Because its body is empty, this example class doesn't do anything. You can, however, compile the class and
even create an object from it. To create an object from a class, you need to type the class's name followed
by the name of the object. For example, the line below creates an object from the MyClass class:
MyClass myObject = new MyClass();
63 | P a g e
360digrii
Java course material
Declaring a Class
class MyClass {
}
In this class declaration, the class body i.e. the area between the braces, contains all the code that provides
for the life cycle of the objects created form the class. This might include constructors for initializing new
objects, declarations for the fields that provide the state of the class and its objects, and methods to
implement the behavior of the class and its objects.
This class declaration is a minimal one, containing only the required components of a class declaration.
More developed instances of class declaration are also available. For instance, you can give more
information about the class –i.e. the name of its superclass, whether any interfaces are implemented by it
and similar information. You need to provide this information at the start of the class declaration. For
example:
Modifiers like public or private can be also be added at the beginning of the declaration. These two
modifiers decide which other classes can access MyClass. However, using these modifiers can make the
opening line of a declaration far too complicated.
Wherever modifiers like public and private (and similar ones) they come first.
Second comes the class name. The convention is to capitalize the initial letter.
After that comes the name of the class’s parent, i.e. the superclass. The keyword extends precedes this
superclass. Remember that a class can extend only one parent, i.e. subclass.
If there is a list of comma-separated interfaces, the keyword implement precedes them. A class can
implement more than one interface.
Finally, the class body. This contains all the information within that class and comes surrounded by
braces.
64 | P a g e
360digrii
Java course material
Declaring Fields for a Class
In order to be useful, a class needs both data fields and methods. You declare fields for your class in much
the same way you declare any variable in a program, by typing the data type of the field followed by the
name of the field, like this:
int myField;
The above line declares a data field of type integer. However, looking at the above line doesn't tell you
much about how data fields are used with classes. In fact, you can't deduce from the above line whether
myField is actually part of an object or just a normal variable. To clear up this ambiguity, you can plug the
above line into the MyClass class definition, as shown below.
class MyClass
int myField;
}
Now you can see that myField is a data field of the MyClass class. Moreover, this data field is by default
accessible only by methods in the same package. You can change the rules of this access by using the
public, protected, and private keywords. A public data field can be accessed by any part of a program,
inside or outside of the class in which it's defined. A protected data field can only be accessed from within
the class or from within a derived class (a subclass). A private data field cannot even be accessed by a
derived class.
Defining a Constructor
You have now added a data field to MyClass. However, the class has no methods and so can do nothing
with its data field. The next step is to create methods. One special type of method, called as constructor,
enables an object to initialize itself when it's created. A constructor is a public method (constructors can
also be private) with the same name as the class. Following code shows the MyClass class with its two
constructors in place.
class MyClass
int myField;
{
myField=20;
}
65 | P a g e
360digrii
Java course material
public MyClass(int myfield) // Constructor with one argument
myField = myfield;
}
As you can see, the class's constructor starts with the ‘public’ keyword. This is important because you
want to be able to create an object from the class anywhere in your program, and when you create an
object, you're actually calling its constructor. After the public keyword comes the name of the constructor
followed by the constructor's arguments in parentheses. When you create an object of the class, you must
also provide the required arguments.
MyClass contains two constructors, one without argument and one with argument. If you want to create
object by calling default constructor, no need to supply any argument. But if you want to create an object
from MyClass by calling Constructor with argument, you must supply an integer value that the class uses
to initialize the myField data field. You can create an object of the class like this:
//argument
Above line not only creates an object of the MyClass class, but also initializes the myField data field to 10.
The first word in the object declaration lines tell Java that myObject1 and myObject2 are going to be
objects of the MyClass class. The next word is the object's name. After the equals sign comes the keyword
‘new’ and the call to the class's constructor.
Introducing Methods
Java method is a series of statements that perform some repeated task. Instead of writing 10 lines of code
we can put those ten lines in a method and just call it in one line. It is like a shortcut.
Object_of_class.printAddress();
The methods that can be called from the outside of the class should be defined as public; the methods that
can be callable only from the class and its derived classes should be defined as protected, and the methods
that is callable only from within the class should be declared as private.
Suppose myField is defined as private, and you now want to set the value of myField from outside the
MyClass class. As data field is defined as private, which means that it can be accessed only within the same
class, you cannot access it directly by name. To solve this problem, you might also want to create a method
that returns the value of the field, as shown in MyClass.java program.
Example: MyClass.java
public MyClass()
myField = 20;
67 | P a g e
360digrii
Java course material
public MyClass(int myfield)
myField = myfield;
return myField;
System.out.println(ob1_value);
System.out.println(ob2_value);
}
Output:
20
100
Objects
What are objects? You can term them as the physical instantiation of the classes i.e. they represent an idea
in the form of an instance of it. Objects have their own independent identities and life cycles of within a
program. Objects are created completely in accordance with the class that describes them. Imagine the
blueprint of a house. You can create as many houses as you want from the one blueprint. Similarly, in JAVA
one class can instantiate many objects. In JAVA, you can create many objects of different classes. Moreover,
you can use them and finally destroy them within the course of the program.
68 | P a g e
360digrii
Java course material
Declaring, Instantiating and Initializing Objects
A class provides the blueprint for objects; you create an object from a class. The following two statements
taken from the Myclass.java program creates an object and assigns it to a variable.
int ob1_value = object1.getField();
Declaration: The code that is set in bold is a variable declaration, associating a variable name with
an object type.
Instantiation: This is done by the new keyword, a JAVA operator that creates the object.
Initialization: A call to the constructor follows this new operator. This in turn, initializes the new
object.
“this” keyword is a reference to the current object within an instance method or constructor. Current
object is the object whose method or constructor is being called. You can use “this” keyword to refer to
any member of the current object from within an instance method or constructor. This solves the variable
shadowing issue.
myField = myfield;
}
}
Now, see what happens if you write this program, using “this” with a field:
69 | P a g e
360digrii
Java course material
private int myField;
this.myField = myfield;
}
}
What is the necessity of using “this” here? Notice that each argument to the constructor shadows one of
the object’s fields. Yet, inside the constructor, “myField” is a local copy of the first argument of the
constructor. Using “this” you can refer to the MyClass field myField. This happens only if the constructor
uses this.myField.
You can use the “this” keyword for further uses as well. For example, you can use it to call another
constructor in the same class. This process is known as explicit constructor invocation. Consider the
following example where Myclass uses “this” with a constructor and notice the difference from the first
instance.
public MyClass() {
this(0, 0, 0, 0);
}
public (int a, int b) {
this(0, 0, a, b);
}
public Myclass(int x, int y, int a, int b) {
this.x = x;
this.y = y;
this.a = a;
this.b = b;
}
...
}
As you can see, a set of constructors is available within this class. Either some, or all of the member
variables are initialized by each of the constructors. A default value for any member variable whose initial
value is not provided by an argument is provided by the constructors. Here, for instance, the four-
argument constructor with four 0 values is called by the no-argument constructor. Similarly, the four
argument constructor with two 0 values is called by the two-argument constructor. You might ask, how is
it determined that which constructor is to be called? The compiler decides that, based on the number and
type of arguments.
70 | P a g e
360digrii
Java course material
The Garbage Collector
In some object-oriented languages you need to keep track of all the objects that you have created as well
as destroy them when they are not needed any longer. This means that managing memory becomes highly
tedious. This might give a lot of errors as well. The JAVA platform handles this situation much more
efficiently. Depending on the system’s handling capacity, you can create as many as objects as you need to
without worrying about destroying them. The JAVA runtime environment determines that for you. It
deletes objects when it determines that they are not in use any more. This process is known as garbage
collection.
How is it determined that an object is eligible for garbage collection? As you might have noticed, when
they are no longer in use, i.e. when there are no more references to that object are available. This can
happen in two ways. Either, references that are held in a variable are dropped when that variable goes out
of scope; or an object reference can be explicitly dropped by setting the variable to the special value null. A
program might have multiple references to the same object. Remember that all the reference to an object
must be dropped to make the object eligible for garbage collection.
The garbage collector in the JAVA runtime environment does this automatically, as it periodically frees the
memory used by un-referenced objects.
The program performance can be affected through garbage collection. Why? It is because the
garbage-collected heap adds an overhead. Moreover, this process might take a bit more of the CPU time
than usual, as the JVM needs to keep track of the objects as they are being referenced by the executing
program as well as finalize and free object at the same time. If you had the option of freeing the
unnecessary memory explicitly, it would have taken less time. In a nutshell, the programmer has less
control over scheduling the CPU time that is reserved for freeing unnecessary objects.
If a programmer really wants to explicitly request a garbage collection at some point, System.gc()
or Runtime.gc() can be invoked, which is a "hint" to the runtime engine that the present moment might be
a good time to run the GC. Some implementations take this into consideration and some do not. Strictly
speaking no one can force GC.
71 | P a g e
360digrii
Java course material
The finalize() Method
Think of a situation when an object might actually perform some actions when it is just about to be
destroyed. For instance, think of the situation, when an object is holding some non-JAVA resources like a
file handle or a window character font. You want to free these resources before the object is destroyed.
JAVA provides the process called finalization for situations like this. Through finalization you can define
the specific actions that will take place when an object is just about ready to go for garbage collection.
To implement this, you simply define the finalize() method. Whenever an object of that class needs to be
recycled, JAVA run time calls the finalize() method. As you know, the garbage collector runs automatic
and periodic checks to find unreferenced objects. Note that the garbage collector runs periodic automatic
checks for those objects that are no longer referenced by any running state. It can also apply the indirect
method of checking through other referenced objects for a long period.
Before an object is ready for destruction by the Garbage Collector, any specified actions within finalize()
will be performed. To do this, the JAVA run time environment calls the finalize() method, just when an
asset is about to be freed.
The GCTest.java illustrates when a string Object becomes available for Garbage Collection.
Runtime rt = Runtime.getRuntime();
}
}
class GC1 {
String str;
int id;
GC1(int i) {
this.str = new String("abcdefghijklmnopqrstuvwxyz");
this.id = i;
}
73 | P a g e
360digrii
Java course material
Chapter 6 - Advance Class Features
Method Overloading
Method overloading is an important feature in Java, which allows the overloading of two or more methods
within the same class.
Creation of several functions with the same name but different signature is called method overloading.
The methods have different parameter declarations. The process of overloading is central to statically
typed programming languages that implement type checking in function calls. Method overloading feature
not only re-uses method names, it also permits the execution of several vital functions.
For example, both the square function of ‘X’ (can be integer) and its return value (can be floating point
number) can have overloading.
From the instrumental point of view, this feature should never be confused with ad-hoc polymorphism
though overloading is one of the ways through which Java implements polymorphism. Java applies the
“one interface, multiple methods” paradigm through method overloading. For those languages, where
method overloading is not supported, each method must be given a unique name. However, frequently you
might want to employ the same method for different types of data.
While invoking an overload method ask yourself why should overload methods differ in the type and/or
number of their parameters? This is done because type and/or number of arguments are used in JAVA to
determine which version of the overloaded method actually needs to be called. Overloaded methods might
have different return types. However, these return types are not enough in themselves to distinguish
between two versions of a method.
In JAVA, you can encounter a call to an overload method. However, remember that while doing so, JAVA
only executes that version of the method whose parameters match the arguments in call.
Note: If in a program, multiple methods are invoked in order to perform diverse tasks, overloading
method should be avoided.
No parameters
a: 20
a and b: 10 30
double a: 100.25
Result of ob.OVtest(100.25): 10050.0625
In OverloadTestDemo.java, OVtest() is overloaded four times. For the first method, no parameters are
defined. The second one takes one integer parameter, the third takes two integer parameters and the
fourth takes one double parameter.
Whenever an overloaded method is called during the course of a program, JAVA searches for a match
between the arguments used to call the method and the method’s parameters. It is not necessary for the
75 | P a g e
360digrii
Java course material
method to be exact all the time. JAVA’s automatic type conversion can play a role in overhead resolution
under certain situations.
For example, consider OverloadTestDemo1.java:
// Automatic type conversions applied to overloading.
class OverloadTestDemo1
{
void OVtest()
{
System.out.println("No parameters");
}
// Overloading test for two integer parameters.
void OVtest(int a, int b)
{
System.out.println("a and b: " + a + " " + b);
}
// overloading test for a double parameter
void OVtest(double a)
{
System.out.println("Inside OVtest(double) a: " + a);
}
}
class OverloadCallDemo1
{
public static void main(String args[])
{
OverloadTestDemo1 ob = new OverloadTestDemo1();
int i = 78;
ob.OVtest();
ob.OVtest(5, 7);
ob.OVtest(i); // this will invoke OVtest(double)
ob.OVtest(1.3); // this will invoke OVtest(double)
}
}
OverloadTestDemo1.java generates the following output:
No parameters
a and b: 5 7
Inside OVtest(double) a: 78.0
Inside OVtest(double) a: 1.3
The OVtest(int) is not defined by OverloadTestDemo1.java. So, no matching method will be found
whenever OVtest() is called with an integer argument inside Overload. What is the way out then? An
integer can be automatically translated into a double in JAVA and this conversion can be used to resolve
the call.
76 | P a g e
360digrii
Java course material
Note: Automatic type conversion in JAVA is employed only if no exact match is found.
“C” language doesn’t support method-overloading feature. Each and every function in “C” should have
different name, even if they execute the same task. In Java, each absolute value method can use the same
name. Infact, Java’s standard class library includes an absolute value method known as abs(), which is
overloaded by Java’s math class to handle all numeric types. On the basis of the argument, Java compiler
can identify and define which version of abs() to call.
In a nutshell, method overloading has certain explicit uses:
Method overloading allows related methods to be assessed by the use of a common name.
Overloading helps you to manage and monitor the complexity of the programs.
Overloading Constructors
In the same way as several methods are employed and adjusted in a single class, you can load two or more
constructors in a single class. Real-time programming actually calls for the induction of different
constructors during the designing of programs. To be more precise, for most of the real-world classes that
you create, overloaded constructors are a norm rather than an exception. Let’s refer to the following
fragment code representing class Cons1.
//using constructors
class Cons1
{
private int x;
private int y;
void calc()
{
int res = x + y;
System.out.println("Result is : "+res);
}
} //class over
77 | P a g e
360digrii
Java course material
class OverConsDemo1
{
public static void main(String args[])
{
Cons1 ob1 = new Cons1();
ob1. calc();
Cons1 ob2 = new Cons1(30,40);
ob2.calc();
}
}
In the code, it is quite manifest that first Cons1() requires no parameter and the other Cons1()
constructor requires two parameters. This further implies that all declarations of Cons1 objects must pass
either no or two arguments to the Cons1() constructor. Since Cons1() requires two arguments, it’s an
error to call it without them.
Following is another example implementing Constructor Overloading and trying to pass dimension for a
Cuboid. Find out the volume of the same. OverConsDemo2.java contains an improved version of
OverConsDemo1.java.
/* Cuboid1 defines three constructors to initialize the dimensions of a box. */
class Cuboid1 {
double width;
double height;
double depth;
class OverConsDemo2 {
public static void main(String args[]) {
// creation of boxes using various constructors
Cuboid1 mycube1 = new Cuboid1(15, 50, 5);
Cuboid1 mycube2 = new Cuboid1();
Cuboid1 mycube3 = new Cuboid1(9);
double vol;
Till now we have learnt how to overload methods and constructors. Now we should learn how to add
objects to methods. For example, consider PassObjectDemo.java:
class ObjTest {
int a, b;
79 | P a g e
360digrii
Java course material
ObjTest(int i, int j) {
a = i;
b = j;
boolean equals(ObjTest o) {
}}
class PassObjectDemo {
}
PassObjectDemo.java generates the following output:
ob1 == ob2: false
80 | P a g e
360digrii
Java course material
// Box allows one object to initialize another object.
class Cuboid2 {
double width;
double height;
double depth;
width = ob.width;
height = ob.height;
depth = ob.depth;
width = w;
height = h;
depth = d;
Cuboid2() {
height = 1; // an uninitialized
depth = 1; // box
81 | P a g e
360digrii
Java course material
}
Cuboid2(double len) {
double volume() {
class OverConsDemo3 {
double vol;
vol = mycube1.volume();
vol = mycube2.volume();
82 | P a g e
360digrii
Java course material
System.out.println("Volume of mycube2 is " + vol);
vol = mycube3.volume();
vol = myclone.volume();
}
OverConsDemo3.java generates the following output:
Volume of mycube1 is 35000.0
Passing Arguments
One important thing that you can do is passing an argument into a subroutine. There are two ways by
which you can do it. The first way is called as ‘call-by-value’ method and the second one is termed as the
‘call-by-reference’ method. The first technique copies the value of an argument into the parameter of a
subroutine whereas following the second method, an argument reference can be passed to the parameter.
For the first method, changes to the parameter of the subroutine have no formal effect on the argument.
For the second method, the reference is used to access the actual argument specified in the call which
further implies that changes initiated to the parameter affects the argument that is used to call the
subroutine.
Note: Java uses both these methods, depending upon what is passed.
When you pass a simple type to a method, it is passed by value. The parameter that accepts the argument
has no effect outside the method. Please refer to CallByValueDemo.java to understand how simple types
are passed by value.
// Simple types are passed by value.
class TestDemo1 {
j /= 2;
}}
class CallByValueDemo {
ob.meth(a, b);
System.out.println("a and b at the end of the call: " + a + " " + b);
}
The output of CallByValueDemo.java is shown here:
a and b before call: 28 29
The operations taking place inside meth() does not have any effect on the values of a and b that are used
in the call. Their values did not change.
This situation, however, changes radically when an object is passed to a method. Why? Because, objects
are passed by reference. Remember that when a variable of a class type is created, you are actually
creating only a reference to an object. Hence, when a reference is passed to this method, the parameter
that receives it will refer only to the same object as that referred to by the argument. Objects are,
therefore, passed to methods by use of call-by-reference. The object used as an argument is affected by the
changes to the object inside the method.
Consider the CallByRefDemo.java as an example:
class TestDemo2 {
int x, y;
TestDemo2(int i, int j) {
84 | P a g e
360digrii
Java course material
x = i;
y = j;
// pass an object
void meth(Test o) {
o.x *= 2;
o.y /= 2;
class CallByRefDemo {
System.out.println("ob.x and ob.y before call: " + ob.x + " " + ob.y);
ob.meth(ob);
System.out.println("ob.x and ob.y after call: " + ob.x + " " + ob.y);
}
CallByRefDemo.java generates the following output:
ob.x and ob.y before call: 7 8
85 | P a g e
360digrii
Java course material
Returning Objects
Returning of objects is one of the marked features in java language. A method can return any form of data,
including class types. In RetObjectDemo.java, the incrementByTen() method returns an object in which
the value of x is seven greater than it is in the invoking object.
// Returning an object.
class TestDemo3 {
int x;
TestDemo3(int y) {
x = y;
TestDemo3 incrementByTen() {
TestDemo3 temp = new TestDemo3(x+7);
return temp;
class RetObjectDemo {
Testdemo3 ob2;
ob2 = ob1.incrementByTen();
ob2 = ob2.incrementByTen();
86 | P a g e
360digrii
Java course material
The output generated by RetObjectDemo.java is shown here:
ob1.x: 2
ob2.x: 9
Note: A new object is created and a reference to it is returned whenever you call incrementByTen(). The
new object created is dynamically allocated to the memory. After returning the object, the method
terminates and the created object continues to exist as long as there is a reference to it somewhere in the
program. What will happen if the object goes un-referenced? Of course, the object will acquire garbage
status and will be reclaimed by the garbage collector when it returns next time.
Noted linguist and political theorist Noam Chomsky was one of the pioneers to use recursion mechanism
in languages. He embedded one or more sentences in sentences. Recursion forms an intrinsic part of
computer programming. In Java Programming language, recursion permits a method to call itself. Thus a
recursive method is considered to be one that can call itself.
Introduction of an ‘if’ statement (to force the method to return without the recursive call being executed)
is mandatory while writing recursive methods. If ‘if’ statement is not implemented once you call the
method, it will never return. The programmers are strongly recommended to use println() statements
liberally during the invocation and execution of recursive methods so that they can watch what is going on
and abort execution if you see that you have made a mistake.
A classic example of recursion is the computation of the factorial of a number. The factorial of a number X
is the product of all the whole numbers between 1 and X. For example, 6 factorial is 1 × 2 × 3 × 4 × 5 × 6, or
720. Here is how a factorial can be computed by use of a recursive method:
// A simple example of recursion:
class FactorialDemo {
int fact(int x) {
int result;
if(x==1)
return 1;
result = fact(x-1) * x;
return result;
87 | P a g e
360digrii
Java course material
}
class RecursionDemo1 {
}
RecursionDemo1.java generates the following output:
Factorial of 6 is 720
Factorial of 7 is 5040
Factorial of 9 is 362880
Note: In the above example, when fact() is called with an argument of 1, the function returns 1; otherwise
it returns the product of fact(x–1)*x. To evaluate this expression, fact() is called with x–1. This process
repeats until x equals 1 and the calls to the method begin returning.
New local variables and parameters are allocated memory storage on the stack, whenever a method calls
itself. The method code is then executed with these new variables from the start. It is important to note
here that a recursive call does not make a new copy of the method and it is only the arguments that are
new. With the return of each recursive call, the old local variables and parameters are removed from the
stack, and the recursive operation resumes at the point of the call inside the method.
Recursive functions have certain invincible advantages. One of the main advantages of using recursion is
that recursive methods can be used to create simpler versions of several algorithms.
A computer programmer might face certain pertinent problems while using recursion. Because of the
added function calls, recursive versions may operate slower in relation to the iterative equivalent. There is
the possibility of a stack overrun. There is also a likelihood of stack collapse because storage for
parameters and local variables is on the stack and each new call creates a new copy of these variables. In
the event of a stock collapse, the Java run-time system will cause an exception.
In order to understand recursion in a more comprehensive way, let us consider another example. The
recursive method printArray() prints the first y elements in the array values.
88 | P a g e
360digrii
Java course material
// Another example that uses recursion.
class RecursiveTestDemo {
int values[];
RecursiveTestDemo(int y) {
void printArray(int y) {
if(y==0) return;
else printArray(y-1);
class RecursionDemo2 {
int y;
ob.values[y] = y;
ob.printArray(10);
}
RecursionDemo2.java generates the following output:
[0] 0
[1] 1
89 | P a g e
360digrii
Java course material
[2] 2
[3] 3
[4] 4
[5] 5
[6] 6
[7] 7
[8] 8
[9] 9
Java, in order to retain the compactness of data, has set definite protocols and levels to manage and access
data. Java defines a default access level. Access control is a very important feature in Java language. Access
control is another form of data encapsulation employing which you can prevent data misuse and data
tampering. To control the access of data as well as to restrict access to the data members of a class you
have certain defined methods. In real-time classes, you allow operations on data only through methods.
When these methods are judicially employed and implemented, a class creates a “black box” which may be
used. It is important to note here that the inner ingredients of the class are not open to tampering. Certain
major and important aspects of access control are principally related to inheritance or packages.
In access control, access specifier plays a pivotal role. Java provides for three different kinds of specifiers
viz. public, private, and protected. The access specifier not only tells you how a member can be accessed,
it also tells you how to create and modify the classes’ declaration statement. An access specifier precedes
the rest of a member’s type specification. Please refer to the following program code to understand access
control specifiers:
public int i;
private double j;
There are moments where the specifier is not categorized. In that event, the member of a class comes (by
default) under ‘public’ within its own package. It is needless to say here that for most of the real-time
programs all members of a class use the default ‘public’.
Note: Member of an unspecified public class cannot be accessed by members of other packages.
Whenever a member of a class is modified with the aid of a public specifier, then that member can be
accessed by any other code. In real-time programming, it is rightly justified to allow an instance variable to
be public. If a member of a class is specified as private, then that member can only be accessed by other
members of the same class. This is the reason why main() has always been preceded by the public
specifier. Specifier ‘protected’ applies only when inheritance is involved.
90 | P a g e
360digrii
Java course material
To comprehend the effects of public and private access, consider AccessTestDemo1.java:
/* This program demonstrates the difference between public and private.
*/
class TestDemo3 {
z = i;
return z;
class AccessTestDemo1 {
ob.x = 17;
ob.setz(19); // OK
System.out.println("x, y, and z: " + ob.x + " " + ob.y + " " + ob.getz());
}
91 | P a g e
360digrii
Java course material
AccessTestDemo1.java generates the following output:
x, y, and z: 17 18 19
In AccessTestDemo1.java, we see that inside the TestDemo class, x uses default access (equivalent to
accessing the public class), y is overtly specified as public and member z is given private access. Member z
can not be accessed by code outside of its class and hence inside AccessTest1 class, z cannot be used
directly. It must be accessed through its public methods: setz() and getz().
TestStackDemo1.java demonstrates the improved Stack class.
import java.io.*;
import java.util.*;
class TestStackDemo1 {
System.out.println("Stack in mystack1:");
System.out.println(mystack1.pop());
System.out.println("Stack in mystack2:");
System.out.println(mystack2.pop());
// mystack1.tos = -2;
// mystack2.stck[3] = 100;
92 | P a g e
360digrii
Java course material
}
}
TestStackDemo1.java generates the following output:
Stack in mystack1:
4
3
2
1
0
Stack in mystack2:
9
8
7
6
5
With regard to the above example, though it is true that the push() and pop() methods provide for a
controlled interface to the stack, yet it is possible for another part of the program to bypass these methods
and access the stack directly.
Understanding Static
It is very important to know how the keyword ‘static’ functions in advanced Java applications. Under
standard conditions, a class member must be accessed in combination with an object of its class. But it is
sometimes feasible to create a member that can be used by itself, without reference to a specific instance.
In order to initialize this sort of a class member, the declaration should be preceded by the keyword
‘static’. A class member, declared as ‘static’, can be accessed without reference to any object and before any
object/objects of its class is/are created. Both methods as well as variables can be defined as static.
‘main()’ is the most common and universal example of a static member and has to be invoked before the
initialization of objects.
Note: In essence, the instance variables declared as static are global variables. No copy of a static variable
is initiated whenever objects of its class are defined. The same static variable is shared by all instances of
the class.
It is important for you to understand that there are certain limitations that are central to methods that are
declared as ‘static’. These are:
The methods are capable of calling only other static methods.
Only static data can be accessed by the methods.
Note: In order to initialize your static variables you may need to do computation because the static block
that you declare gets executed exactly once, when the class is loaded for the first time.
StaticTestDemo.java speaks about a class that includes a static method, some static variables and a static
initialization block.
93 | P a g e
360digrii
Java course material
// Demonstrate static variables, methods, and blocks.
class StaticTestDemo {
static int x = 3;
static int y = 4;
static int z;
static void statmeth(int x) {
System.out.println("x = " + x);
System.out.println("y = " + y);
System.out.println("z = " + z);
}
//Starting of static block
static {
System.out.println("Static block initialized.");
z = y * 8;
}
public static void main(String args[]) {
statmeth(31);
}
}
StaticTestDemo.java generates the following output:
Static block initialized
x = 31
y=4
z = 32
As soon as the StaticTestDemo class is loaded, all of the static statements are run. First, x is set to 3, and y
set to 4 and z set to 0. After this, the static block executes (printing a message) and finally, z is initialized to
y * 8 or 32. Then main() is called, which calls statmeth(), passing 31 to x. The three println() statements
refer to the two static variables x, y and z.
94 | P a g e
360digrii
Java course material
class StaticTestDemo {
static int j = 22;
static int k = 31;
static void callme() {
System.out.println("j = " + j);
}
}
class StaticByNameDemo {
public static void main(String args[]) {
StaticTestDemo.callme();
System.out.println("k = " + StaticTestDemo.j);
System.out.println("k = " + StaticTestDemo.k);
}
}
StaticByNameDemo.java generates the following output:
j = 22
k = 31
Note: In StaticByNameDemo.java, inside main(), static method callme() and static variable j & k are
accessed outside of their class.
Understanding Final
To know classes and methods in a much more simpler way, it is very important to recognize how we can
manipulate variables. In fact to be more precise, we can assert the forms of a variable. We can declare a
variable as ‘final’. In the ‘final’ form of a variable you can’t initiate changes in contents and final variable is
essentially a constant. Those variables that are declared as final do not occupy memory on a per-instance
basis. The omnipresence of the keyword ‘final’ also stretches to methods and we can even declare a
method to be ‘final’. Please refer to the below-mentioned examples:
final int FILE_NEW = 1;
final int FILE_OPEN = 2;
final int FILE_SAVE = 3;
final int FILE_SAVEAS = 4;
final int FILE_QUIT = 5;
Note: If the above fragment codes are applied in real-time java programming, you will see that parts of
your program can use FILE_SAVE, FILE_QUIT etc. (as if they were constants). Please also note that
choosing all uppercase identifiers for final variables is a common coding practice.
95 | P a g e
360digrii
Java course material
Nested and Inner class
As we all know that Java is identified in terms of classes and their functional attributes. Classes in Java
exist in different forms allowing class members to accommodate themselves in different formats and
positions. A class represents object and embodies all the essential features of a particular set of objects. In
real-life terms, you don’t define objects. You rather define classes of objects.
Apart from the general form of existence, classes exist in the form of ‘Nested class’ and ‘Inner class’. Both
‘Nested and Inner classes’ are explained in details in Fig 1.
CLASSIFICATION OF CLASSES
CLASSES
NESTEDCLASSES OTHERCLASSES
NON-STATICNESTEDCLASSESORINNERCLASSES
STATICNESTEDCLASSES
Nested classes
As you can create sub-systems inside systems and sub-sets inside sets, similarly you can create and
initialize sub-classes within classes. Java language authorizes you to define a class within another class.
Please refer to the below-mentioned fragment code to identify and understand a ‘nested class’.
class OuterClass {
...
class NestedClass {
...
}
}
96 | P a g e
360digrii
Java course material
One of the primary attributes of a nested class is that it has access to other members of the enclosing class,
even if they are declared private. Nested classes can be declared private, public, protected, or package
private.
Note: It is important to note here that outer classes can only be declared public or package private.
Nested classes are categorized into two types static and non-static. Those nested classes that are declared
as static are called static nested classes. Non-static nested classes are called inner classes. Refer to the
following fragment code for further details.
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Reasons for using nested Classes
There are certain advatages of using nested classes:
97 | P a g e
360digrii
Java course material
OuterClass.StaticNestedClass
To generate an object for the static nested class the following fragment code is used:
class OuterClass {
...
class InnerClass {
...
}
}
In order to instantiate an inner class, you first have to initialize the outer class. Only after that will you be
able to create the inner object within the outer object. The fragment code for the same would look like:
Please refer to the following Figure to understand how inner and outer classes coexist.
OUTER CLASSES
INNER CLASSES
98 | P a g e
360digrii
Java course material
Command-line Arguments
During intensive programming, times come when you need to infuse (during program execution)
additional information or input into an existing program. This is done with the aid of adding command-
line arguments to main(). Command-line argument is specific information that follows the program’s name
on the command-line when executed. Command-line arguments are stored as strings in the String array
that is passed to main(). During program execution, you have to physically convert numeric values to their
internal forms.
Refer to the following fragment code to know how command-line arguments are infused into a program.
// Display all command-line arguments.
class CommandLineDemo {
99 | P a g e
360digrii
Java course material
Chapter 7 – Inheritance
Introduction
This chapter discusses about inheritance. In the Java language, classes can be derived from other classes,
thereby inheriting fields and methods from those classes.
Inheritance is one of the basic principles of Objected Oriented Programming. The enabling principle of
inheritance is Polymorphism. Inheritance allows you to create hierarchical classifications. You begin the
process of creating a hierarchical classification by defining a general class that defines traits that common
to a set of related objects. This class can then be inherited by other more specific classes, each adding
those things that are unique to it. These classes inherit the general features from the general class.
Generalized class definitions are defined and exist at the top of a class hierarchy, while specialized classes
appear lower down in the hierarchy. In Java terminology, a class that is inherited is called a 'superclass'
and the class that does the inheriting is called the 'subclass'. Inheritance is a concept in object oriented
programming languages that allows you to describe more easily real-world “is-a-kind-of” relationships.
For example, a car (specialized subclass) is a kind of vehicle (generalized superclass). Another example is
that of a manager (specialized subclass) being a kind of employee (generalized superclass).
You therefore encounter more and more generalization as you ascend successive layers up the hierarchy
and more and more specialization is evidenced as you descend successive layers down the hierarchy.
Hierarchy is ranking or ordering of abstractions. That is why you speak of inheritance as being a
generalization/specialization hierarchy. This is an important principle of designing class hierarchies.
Definitions
A class that is derived from another class is called a subclass (also a derived class, extended class, or child
class). The class from which the subclass is derived is called a superclass (also a base class or a parent
class).
Excepting Object, which has no superclass, every class has one and only one direct superclass (single
inheritance). In the absence of any other explicit superclass, every class is implicitly a subclass of Object.
Classes can be derived from classes that are derived from other classes, and so on. These are ultimately to
be derived from the topmost class, Object. Such a class is said to have descended from all the classes in the
inheritance chain stretching back to Object.
The idea of inheritance is simple but powerful. When you want to create a new class and there is already a
class that includes some of the code that you want, you can derive your new class from the existing class.
In doing this, you can reuse the fields and methods of the existing class without having to write (and
debug) them yourself.
A subclass inherits all the members (fields, methods, and nested classes) from its superclass. Constructors
are not members, so they are not inherited by subclasses, but the constructor of the superclass can be
invoked from the subclass.
100 | P a g e
360digrii
Java course material
The Java Platform Class Hierarchy
The Object class, defined in the java.lang package, defines and implements behavior common to all
classes—including the ones that you write. In the Java platform, many classes derive directly from Object,
other classes derive from some of those classes, and so on, forming a hierarchy of classes.
A class declaration for a MountainBike class that is a subclass of Bicycle might look like this:
public class MountainBike extends Bicycle {
// the MountainBike subclass adds one field
public int seatHeight;
}
MountainBike inherits all the fields and methods of Bicycle and adds the field seatHeight and a method to
set it. Except for the constructor, it is as if you had written a new MountainBike class entirely from scratch,
with four fields and five methods. However, you did not have to do all the work. This would be especially
valuable if the methods in the Bicycle class were complex and had taken substantial time to debug.
Inheritance of structure
When designing a class hierarchy, the following strategies can be used by the development team for
inheriting instance variables.
102 | P a g e
360digrii
Java course material
No Redefinition:
In this case, the type of the instance variable of the superclass is inherited as it is. No modifications are
made to the superclass definition.
Constrained Redefinition
In this case, the type of the instance variable in the subclass is a subtype of the type of the variable in the
superclass. This is the instance variable in the subclass. This gives the instance variable in the subclass a
narrowly scoped definition while still retaining its semantic relation to and broadly remaining within the
domain of the superclass instance variable. For example, the class Vehicle might have an instance variable
noOfWheels of type Natural, which is inherited and subtyped by the subclass car to the type {3, 4}.
Arbitrary Redefinition
In this strategy, the name of the instance variable in the subclass is retained, but the type of the instance
variable in the subclass is changed to a type that is unrelated to the type of the instance variable in the
superclass.
Conclusion
The more conservative strategies (no redefinition and constrained redefinition) result in the most
maintainable and reusable inheritance trees.
Inheritance of Behavior
The following strategies can be used by the development team for the inheritance of methods.
Arbitrary Redefinition: The subclass can provide an entirely different and unrelated implementation of
the method.
Constrained Redefinition: The methods in the subclass must have signatures that are subtypes of the
signatures of the methods in the superclass they override. A signature of a method in a subclass is a
subtype of a signature of a method in the superclass if the two methods have the same name and the
arguments. You will see more of constrained redefinition in the section on overriding.
Conclusion
The more conservative strategy (constrained redefinition) results in the most maintainable and
inheritance trees.
Single Versus Multiple Inheritance
Single inheritance is a phenomenon wherein a subclass inherits from one and only one superclass.
Multiple inheritance on the other hand is characterized by a subclass inheriting from more than one
superclass.
Multiple inheritance, therefore provides richer functionality when modeling subclasses for it can inherit
the functionality of more than one superclass. This richer functionality of subclasses, does come with a
cost, however.
The problem is that multiple superclasses can have instance variables and /or methods with the same
name, but with totally unrelated semantics. As a result, the inheritance tree using multiple inheritance will
be less understandable and eventually also less maintainable than an eventually also less maintainable
103 | P a g e
360digrii
Java course material
than an inheritance tree using single inheritance. The following diagram depicting an inheritance tree
points out the ambiguities that can occur in multiple inheritances:
int b
B C
fn1()
int a int a
{//some code}
int b int b
Inherited from A
int c int d
D
fn1() fn1()
int a
{//some code} {//some code}
int b
fn1()
{//some code}
When an object of class D is created, it would have inherited attributes a and b in the method fn1( ) twice
int a
from class A via multiple access paths. Therefore, whenever your code refers to variable a or b in an object
of class D, it becomes an ambiguous reference,
int b because we need to further specify whether we are
referring to variable a or b inherited from Class A or the variable a and b inherited from class B. This
int d
places a considerable overhead on the complier in working around such ambiguities.
Looking at the problems and complexities fn1()
posed by multiple inheritance, Java chose to implement the
single inheritance model. {//some code}
Inheritance Basics
To define a new class from an already existing class, i.e., to inherit a class, you need to incorporate the
definition of an already existing class into the class to be defined by using the extends keyword. You will
now see an example program that creates a superclass called X and a subclass called Y. Pay attention to the
usage of the extends keyword while defining the subclass Y.
class X{
int a, b;
void showab( ){
104 | P a g e
360digrii
Java course material
System.out.println (“a and b are : “+a+” “+b);
}
}
//Defining a class by extending class X
class Y extends X {
int c;
void showc( ){
System.out.println(“c :” + c);
}
void sum() {
System.out.println(“a+b+c = “ + (a+b+c));
}
}
class InheritanceDemo {
public static void main (String args[]){
X superob = new X();
Y subob = new Y();
/* The superclass can be used by itself in a program and need not always be used in the context of a
subclass.*/
superob.a = 10;
superob.b = 20;
System.out.println(“State of object X:”);
superob.showab();
State of object X:
a and b: 10 20
State of object Y:
a and b: 7 8
105 | P a g e
360digrii
Java course material
C: 9
Sum of a, b and c in object Y is:
a+b+c: 24
It is obvious that an object of subclass Y included all of the members of its superclass X. This is why subob
can access a and b and call showab( ). Also, inside sum( ), a and b can be referred to directly, as if they
were part of Y.
Even though X is a superclass for y, it is also a completely independent, standalone class. Being a
superclass for a subclass does not imply that a superclass cannot be used by itself. A subclass can in turn
be a superclass for another subclass.
A subclass inherits all the public and protected members of its parent, no matter what package the
subclass is in. If the subclass is in the same package as its parent, it also inherits the package-private
members of the parent. You can use the inherited members as ihey are, replace them, hide them, or
supplement them with new members:
The inherited fields can be used directly, just like any other fields.
You can declare a field in the subclass with the same name as the one in the superclass, thus hiding it
(not recommended).
You can declare new fields in the subclass that are not in the superclass.
The inherited methods can be used directly as they are.
You can write a new instance method in the subclass that has the same signature as the one in the
superclass, thus overriding it.
You can write a new static method in the subclass that has the same signature as the one in the
superclass, thus hiding it.
You can declare new methods in the subclass that are not in the superclass.
You can write a subclass constructor that invokes the constructor of the superclass, either implicitly or
by using the keyword super.
The following sections in this lesson will expand on these topics.
A subclass does not inherit the private members of its parent class. However, if the superclass has public
or protected methods for accessing its private fields, these can also be used by the subclass.
A nested class has access to all the private members of its enclosing class—both fields and methods.
Therefore, a public or protected nested class inherited by a subclass has indirect access to all the private
members of the superclass.
106 | P a g e
360digrii
Java course material
//Defining a Superclass
class X {
int a; // public by default
private int b;
void sum () {
total = a + b;
//b cannot be accessed outside of its
//class; this line will not compile
}
}
class AccessDemo {
public static void main(String args[]) {
Y subob = new Y ();
subob.setab(10,12);
subob.sum();
System.out.println(“Total: “ + subob.total);
}
}
/* This program will not compile because the reference to b inside sum() method of class Y results in an
access violation. The compiler ensures that the wall of encapsulation built using the private keyword is
not broken.*/
//Defining a Superclass
class X
{
107 | P a g e
360digrii
Java course material
int a; //public by default
private int b;
class Y extends X {
int total;
void sum ( ) {
total = a + getb( );
//getb( )returns the value of b
}
}
class AccessDemo {
public static void main(String args[]) {
Casting Objects
We have seen that an object is of the type of the class from which it was instantiated. For example, if we
write
public MountainBike myBike = new MountainBike();
then myBike is of type MountainBike. MountainBike is descended from Bicycle and Object. Therefore, a
MountainBike is a Bicycle and is also an Object, and it can be used wherever Bicycle or Object objects are
called for.
The reverse is not necessarily true: a Bicycle may be a MountainBike (is not necessarily). Similarly, an
Object may be a Bicycle or a MountainBike (is not necessarily).
108 | P a g e
360digrii
Java course material
Casting shows the use of an object of one type in place of another type, among the objects permitted by
inheritance and implementations. For example, if we write
Object obj = new MountainBike();
Then obj is both an Object and a Mountainbike (until such time as obj is assigned another object that is not
a Mountainbike). This is called implicit casting.
If, on the other hand, we write
MountainBike myBike = obj;
we would get a compile-time error because obj is not known to the compiler to be a MountainBike.
However, we can tell the compiler that we promise to assign a MountainBike to obj by explicit casting:
MountainBike myBike = (MountainBike) obj;
This cast inserts a runtime check that obj is assigned a MountainBike so that the compiler can safely
assume that obj is a MountainBike. If obj is not a Mountainbike at runtime, an exception will be thrown.
Note: You can make a logical test to the type of a particular object using the instanceof operator. This can
save you from a runtime error owing to an improper cast. For example:
if (obj instanceof MountainBike) {
MountainBike myBike = (MountainBike)obj;
}
Here the instanceof operator verifies that obj refers to a MountainBike so that we can make the cast with
the knowledge that no runtime exception will be thrown.
As you know a constructor cannot be inherited by its subclass. A subclass can call a constructor method
defined by its immediate super class by using the following form of super:
super(parameter-list); //parameter list covers parameters of superclass.
Note: super() must be the first statement within the constructor of the sub class. Other statements within
the subclass constructor must follow this.
Here, parameter-list specifies any parameters needed by the constructor in the superclass. super( ) must
always be the first statement executed inside a subclass’ constructor.
Following example illustrates the usage of super( ):
class Cuboid{
double width;
double height;
double depth;
110 | P a g e
360digrii
Java course material
Cuboid() {
width = -1; // use -1 to indicate
height = -1; // an uninitialized
depth = -1; // box
}
// constructor used when cube is created
Cuboid(double len) {
width = height = depth = len;
}
// compute and return volume
double volume() {
return width * height * depth;
}
}
class TestSuperDemo {
public static void main(String args[]) {
CuboidWeight mybox1 = new CuboidWeight(10, 20, 15, 34.3);
CuboidWeight mybox2 = new CuboidWeight(2, 3, 4, 0.076);
111 | P a g e
360digrii
Java course material
CuboidWeight mybox3 = new CuboidWeight(); // default
CuboidWeight mycube = new CuboidWeight(3, 2);
CuboidWeight myclone = new CuboidWeight(mybox1);
double vol;
vol = mybox1.volume();
System.out.println("Volume of mybox1 is " + vol);
System.out.println("Weight of mybox1 is " + mybox1.weight);
System.out.println();
vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
System.out.println("Weight of mybox2 is " + mybox2.weight);
System.out.println();
vol = mybox3.volume();
System.out.println("Volume of mybox3 is " + vol);
System.out.println("Weight of mybox3 is " + mybox3.weight);
System.out.println();
vol = myclone.volume();
System.out.println("Volume of myclone is " + vol);
System.out.println("Weight of myclone is " + myclone.weight);
System.out.println();
vol = mycube.volume();
System.out.println("Volume of mycube is " + vol);
System.out.println("Weight of mycube is " + mycube.weight);
System.out.println();
}
}
TestSuperDemo.java generates the following output:
Volume of mybox1 is 3000.0
Weight of mybox1 is 34.3
Volume of mybox2 is 24.0
Weight of mybox2 is 0.076
Volume of mybox3 is -1.0
Weight of mybox3 is -1.0
Volume of myclone is 3000.0
Weight of myclone is 34.3
Volume of mycube is 27.0
Weight of mycube is 2.0
112 | P a g e
360digrii
Java course material
Pay special attention to this constructor in CuboidWeight( ):
// construct clone of an object
CuboidWeight(CuboidWeight ob) { // pass object to constructor
super(ob);
weight = ob.weight;
}
You can see that super( ) is called with an object of type CuboidWeight—not of type Cuboid. This still
invokes the constructor Cuboid(Cuboid ob). As mentioned earlier, a superclass variable can be used to
reference any object derived from that class. Thus, we are able to pass a CuboidWeight object to the
Cuboid constructor. Of course, Cuboid only has knowledge of its own members.
Let us review the key concepts behind super( ). When a subclass calls super( ), it is calling the constructor
of its immediate superclass. Thus, super( ) always refers to the superclass immediately above the calling
class. This is true even in a multileveled hierarchy. Also, super( ) must always be the first statement
executed inside a subclass constructor.
A Practical Example:
You will now evolve a class description for a closed rectangular solid, which is referred to as a closed
rectangular solid. It has the following attributes- width, height, and depth. Using these attributes, one can
compute its volume. The aforesaid points lead you to the definition of a RectangularSolid class. The code
for the RectangularSolid class is given below:
class RectangularSolid {
double width;
double height;
double depth;
width = w;
height = h;
depth = d;
113 | P a g e
360digrii
Java course material
width = height = depth = length;
double volume() {
double weight;
width = w;
height = h;
depth = d;
weight = wt;
class RectangularSolidImp1 {
RectangularSolidWeight r1 = new
114 | P a g e
360digrii
Java course material
RectangularSolidWeight (10,20,15,35.0);
RectangularSolidWeight r2 = new
RectangularSolidWeight (1,2,3,5.0);
double volume;
volume = r1.volume();
volume = r2.volume( );
}
The output from the program is as follows:
Volume of rectangular solid r1 is 3000.0
115 | P a g e
360digrii
Java course material
// Create a subclass by extending class A.
class B extends A {
int i; // this i hides the i in A
B(int a, int b) {
super.i = a; // i in A
i = b; // i in B
}
void show() {
System.out.println("i in superclass: " + super.i);
System.out.println("i in subclass: " + i);
}
}
class UseSuperDemo {
public static void main(String args[]) {
B subOb = new B(1, 2);
subOb.show();
}
}
UseSuperDemo.java generates the following output:
i in superclass: 1
i in subclass: 2
Although the instance variable i in B hides the i in A, super allows access to the i defined in the superclass.
As you will see, super can also be used to call methods that are hidden by a subclass.
int a ;
class Y extends X {
116 | P a g e
360digrii
Java course material
y(int m, int n) {
super.a = m;
void display() {
class SuperUsage {
subOb.display( );
}}
a in subclass :2
The keyword super can also be used to call methods that are hidden by a subclass.
Java allows you to define multiple layers in an inheritance hierarchy and not just two layers, as you would
have observed till now. You can define a superclass and a subclass where the subclass in turn become a
superclass for another subclass. Given three classes are called X, Y and Z, Z can be a subclass of Y, and Y in
turn can be a subclass of X. In this scenario, each subclass inherits all attributes from its parent. In the
aforesaid example, Z inherits all the attributes and behaviors of X and Y.
You will now extend the RectangularSolidWeight class further to derive a new class called
RectangularSolidShipment class. Shipment inherits all of the traits of RectangularSolid and
117 | P a g e
360digrii
Java course material
RectangularSolidWeight classes, and adds its own specific attribute called cost, which holds the cost of
shipping such a parcel.
Class RectangularSolid {
width = w;
height = h;
depth = d;
double volume ( ) {
double weight;
//constructor for RectangularSolidWeight (double len, double wt) {
super(len);
118 | P a g e
360digrii
Java course material
weight = wt;
public RectangularSolidWeight( ) {
super( );
weight = 0;
double cost;
//constructor when all parameters are specified RectangularSolidShipment (double w, double h, double d,
double wt, double c) {
super (w,h,d,wt);
cost = c;
//default constructor
RectangularSolidShipment () {
super ();
cost = 0;
cost = c;
}
119 | P a g e
360digrii
Java course material
class MultilevelDemo {
RectangularSolidShipment s1 = new
RectangularSolidShipment (10,20,15,10,3.41);
RectangularSolidShipment s2 = new
RectangularSolidShipment(2,3,4,0.76,1.28);
double volume;
volume = s1.volume();
System.out.println();
volume = s2.volume();
System.out.println();
}
The output of the program is as follows:
volume of shipment s1 is :3000.0
120 | P a g e
360digrii
Java course material
Note: In the previous example, all the three classes are placed in a single program file. You could chose to
place all the three classes in their own files and compile them separately. In fact, using separate files is the
generally followed practice.
When a class hierarchy is created, and when an object of the subclass is created, the question that arises is
“In what order are the constructors in a class hierarchy invoked?” Recall from your earlier discussion that
the creation and initialization of the superclass object is a prerequisite to the creation of the subclass
object.
When a subclass object is directly created without initially creating a superclass object explicitly, it first
results in the creation of the superclass object, followed by the initialization of its attributes ensured by
the invocation of a relevant superclass constructor. This is finally followed by the creation of the subclass
object and the initialization of its own specific attributes through a relevant constructor invocation in the
subclass.
Therefore, an important fact that emerges from our discussion is that constructors in a class hierarchy are
invoked in the order of their derivation.
Consider the following example:
class X{
X( ) {
class Y extends X {
Y()
class Z extends Y {
Z ( ){
121 | P a g e
360digrii
Java course material
class OrderOfConstructorCallDemo {
Z z = new Z();
}
The output of the program is as follows:
Inside X's constructor
Method Overriding
Consider a class hierarchy in which a method in a subclass has the same name and type signature (the
same type, the same sequence and the same number of parameters) as a method in superclass. In these
cases the method in the subclass is said to override the method in the superclass. When an overridden
method is called from an object of the subclass, it will always refer to the version of that method defined
by the subclass. The version of the method defined by the superclass will either be hidden or overridden:
Consider the following example:
class X{
int a,b;
X(int m, int n) {
a = m;
b = n;
//display a and b
void display() {
122 | P a g e
360digrii
Java course material
class Y extends X{
int c;
super (m,n);
c = 0;
System.out.println(“c : “ + c);
class OverriddenDemo {
}}
int a,b;
X(int m, int n) {
a = m;
123 | P a g e
360digrii
Java course material
b = n;
//display a and b
void display() {
class Y extends X {
int c;
super(m,n);
c = 0;
System.out.println(“c :“ + c);
class OverrideDemo {
124 | P a g e
360digrii
Java course material
}
}
The following is the output of the aforesaid program:
a and b: 4 5
c: 6
Note: Method overriding occurs only when the names and the types signatures of two methods across at
least two classes (i.e., a superclass and a subclass) in a class hierarchy are identical. If they are not, the two
methods are simply overloaded. Elaborating this theme further, if the method in a subclass has a different
signature than the method in the superclass, then the subclass will have two forms of the same method.
The subclass object will have one method with a specific signature inherited from the superclass and the
other being its own method with the same name as the method in the superclass but with a different
argument or arguments. This is nothing but a case of overloading.
The following example should help clarifying this point:
class X {
int a,b;
X(int m, int n) {
a = m;
b = n;
//display a and b
void display() {
class Y extends X {
int c;
super(m,n);
125 | P a g e
360digrii
Java course material
c = 0;
System.out.println(msg + c);
class OverrideDemo {
//display() in Y
}}
a and b: 4 5
Method overriding forms the basis of one of Java's most powerful concepts: dynamic method dispatch.
Dynamic method dispatch is the phenomenon by which the Java language resolves a call to an overridden
method at runtime and not compile time. Java uses dynamic method dispatch to implement runtime
polymorphism. Java makes runtime polymorphism possible in a class hierarchy with the help of basically
two of its features, namely superclass reference variables and overridden methods.
In retrospect, it is important to restate an important feature of Java at this juncture, especially in the
matter of comprehending runtime polymorphism. It is the capability of a superclass reference. Java
determines which version of the method to call. This decision is based upon the type of the object being
126 | P a g e
360digrii
Java course material
referred to at the time the call occurs. This determines which method is to be called for which object/s
(subclass objects from the same superclass) are method will be called. It is the type of the object that is
being referred to (not the type of the reference variable) that determines which version of an overridden
method will be executed. Therefore, if a superclass contains a method that is overridden by a subclass,
then at the time when different types of subclass objects are being referred to through a superclass
reference variable, different versions of the method are executed.
Here is an example that illustrates dynamic method dispatch:
// Dynamic Method Dispatch
class A {
void callme() {
System.out.println("Inside A's callme method");
}
}
class B extends A {
// override callme()
void callme() {
System.out.println("Inside B's callme method");
}
}
class C extends A {
// override callme()
void callme() {
System.out.println("Inside C's callme method");
}
}
class Dispatch {
public static void main(String args[]) {
A a = new A(); // object of type A
B b = new B(); // object of type B
C c = new C(); // object of type C
A r; // obtain a reference of type A
r = a; // r refers to an A object
r.callme(); // calls A's version of callme
r = b; // r refers to a B object
r.callme(); // calls B's version of callme
r = c; // r refers to a C object
r.callme(); // calls C's version of callme
}
}
127 | P a g e
360digrii
Java course material
The output from the program is shown here:
Inside A’s callme method
Inside B’s callme method
Inside C’s callme method
This program creates one superclass called A and two subclasses of it, called B and C. Subclasses B and C
override callme( ) declared in A. Inside the main( ) method, objects of type A, B, and C are declared. Also, a
reference of type A, called r, is declared. The program then assigns a reference to each type of object to r
and uses that reference to invoke callme( ). As the output shows, the version of callme( ) executed is
determined by the type of object being referred to at the time of the call. Had it been determined by the
type of the reference variable, r, you would see three calls to A’s callme( ) method.
If you are familiar with C++ or C# will recognize that overridden methods in Java are similar to virtual
functions in those languages.
Polymorphism is essential to object-oriented programming for one important reason: it allows a general
class to specify methods that will be common to all of its derivatives or subclasses while allowing
subclasses to define the specific implementation of some or all of those methods. Overridden methods in a
class hierarchy are one of the ways that Java implements the “single interface, multiple methods” aspect of
polymorphism.
Part of the key to successfully applying polymorphism is to understand the fact that the superclasses and
subclasses form a hierarchy, which then moves from lesser to greater specialization. The superclass
provides all elements that a subclass can use directly. It defines those methods that the subclass can use
directly. It also defines those methods that the subclass must implement on its own. This allows the
subclass the flexibility to define its own method implementations, yet still enforce a consistent interface
(keeping the method name and the arguments the same through providing for an overridden function).
Thus by combining inheritance with overridden methods, a superclass can define the general form of the
methods, a superclass can define the general form of the methods that will be used and implemented by all
of its subclasses in their own specific ways.
An Example Demonstrating Overridden Methods and Polymorphism
The following program creates a superclass called Figure that stores the dimensions of various two
dimensional objects. It also defines a method called area() that computes the area of an object. The
program derives two subclasses from Figure. The two subclasses are Rectangle and Triangle. Each of
these subclasses overrides area() so that it returns the area of a rectangle and a triangle respectively.
class Figure {
double dim1;
double dim2;
Figure(double x, double y) {
128 | P a g e
360digrii
Java course material
dim1 = x;
dim2 = y;
double area () {
return 0;
Rectangle(double x,double y) {
super (x,y);
double area() {
class FindArea {
Figure figref;
129 | P a g e
360digrii
Java course material
figref = r;
figref = t;
figref =f;
System.out.println(figref.area());
area of triangle is 40
Quite often, you would want to define a superclass that declares the structure of a given abstraction
without providing the implementation of every method. The objective is to create a superclass that only
defines a generalized form that will be shared by all of its subclasses, leaving it to each subclass to provide
for its own specific implementations. Such a class determines the nature of the methods that the classes
must implement.
Such a superclass is unable to create a meaningful implementation for a method or methods. The class
Figure in the previous example is such a superclass. Figure is a pure geometrical abstraction. You have
only kinds of figures like Rectangle, Triangle etc. that actually are subclasses of class Figure. The class
Figure does not determine the area of a Figure. The Figure class is therefore a partially defined class with
no implementation for the area() method. The definition of area() is simply a placeholder.
It makes little sense for a partially defined superclass to be instantiated for there are going to be some
methods with no implementations. The question that might arise in your mind is regarding the utility of a
partially defined superclass in a class hierarchy that cannot be instantiated. The importance of such
classes cannot be discounted because they define a generalized form (possibly some may be shared by all
of its subclasses, leaving it to each subclass to provide for its own specific implementations of such
methods).
130 | P a g e
360digrii
Java course material
The next design issue that needs to be addressed is the shape that needs to be given to methods with no
implementations that you are bound to encounter in such generalized superclasses. One way is to give a
relevant message when such a method is invoked indicating that it has no implementation. This was the
case with the area() method in the class Figure which when invoked gave the message “ Area for figure is
undefined”. While such an approach may be useful in debugging, it is not appropriate when you are
creating a generalized superclass as part of reusable class libraries that you maybe creating. The right
approach would be to define such methods (i.e., methods with no implementations in a generalized
superclass) in such a way that it becomes mandatory for its subclasses to provide for its own version
(overridden implementation). This should be done in such a way that it becomes mandatory for its
subclasses to provide for its own version (overridden implementation) of such a method if the subclasses
are to have a mechanism to ensure that a subclass does, indeed, override, all necessary methods. This
mechanism comes in the shape of the abstract method.
You can specify that certain methods in a generalized superclass be compulsorily overridden by its
subclasses by defining such methods in a generalized superclass as abstract. These methods are
sometimes referred to as responsibile for the subclasses because they have no implementation specified in
the superclass. It is mandatory for a subclass to override such method or methods, because it cannot
simply use the version of the method defined in the superclass. To use an abstract method, use this general
form:
The abstract class can be used to improve the declaration of the class Figure in the earlier example. Since
there is no meaningful concept of area for an undefined two-dimensional geometrical abstraction such as a
131 | P a g e
360digrii
Java course material
Figure, the following version of the program declares the area() abstract inside class Figure. This, of
course implies that the class Figure be declared abstract, and all subclasses derived from class Figure must
override area():
abstract class Figure {
double dim1;
double dim2;
Figure(double x, double y) {
dim1 = x;
dim2 = y;
Rectangle(double x,double y) {
super (x,y);
double area() {
Triangle(double x, double y) {
super(x,y);
132 | P a g e
360digrii
Java course material
//override area for triangle
double area() {
class FindArea {
figref = r;
figref. = t;
figref =f;
System.out.println(figref.area());
The final keyword has two important uses in the context of class hierarchy. These uses are highlighted as
follows:
While method overriding is one of the most powerful feature of object oriented design, there may be times
when you will want to prevent certain critical methods in a superclass from being overridden by its
subclasses. Rather, you would want the subclasses to use the methods as they are defined in the
133 | P a g e
360digrii
Java course material
superclass. This can be achieved by declaring such critical methods as final. Final methods cannot be
overridden. Any attempt by a subclass to do so will be flagged off as an error by the complier.
class A {
final void meth() {
System.out.println("This is a final method.");
}
}
class B extends A {
void meth() { // ERROR! Can't override.
System.out.println("Illegal!");
}
}
Because meth( ) is declared as final, it cannot be overridden in B. If you attempt to do so, a compile-time
error will result.
Methods declared as final can sometimes provide a performance enhancement. The compiler is free to
inline calls to them because it “knows” they will not be overridden by a subclass. When a small final
method is called, often the Java compiler can copy the bytecode for the subroutine directly inline with the
compiled code of the calling method, thus eliminating the costly overhead associated with a method call.
Inlining is only an option with final methods. Normally, Java resolves calls to methods dynamically, at run
time. This is called late binding. However, since final methods cannot be overridden, a call to one can be
resolved at compile time. This is called early binding.
Sometimes you will want to prevent a class from being inherited. This can be achieved by preceding the
class declaration with final. Declaring a class as final implicitly declares all of its methods as final too. It is
illegal to declare a class as both abstract and final since an abstract class is incomplete by itself and relies
upon its subclasses to provided concrete and complete implementations.
Here is an example of a final class:
final class A {
// ...
}
// The following class is illegal.
class B extends A { // ERROR! Can't subclass A
// ...
}
As the comments imply, it is illegal for B to inherit A since A is declared as final.
Java defines a special class called Object. All other classes are subclasses of Object. Object is a superclass of
all other classes; i.e Java's own classes as well as user-defined classes. This means that a reference
variable of type Object can refer to an object of any other class.
134 | P a g e
360digrii
Java course material
Object defines the following methods, which means that they are available in every object.
Method Explanation
Object clone() Create a new object that is the same as the object
being cloned.
Boolean equals(Object object) Determines whether one object is equal to
another.
Void finalize() Called before an unused object is reclaimed from
the heap by the garbage collector.
Final Class getClass() Obtains the class of an object at runtime.
Int hashCode Returns the hash code associated with the
invoking object.
Final void notify() Resumes execution of all waiting threads on the
invoking object.
Fina void notifyAll() Resumes execution of all waiting threads on the
invoking object.
String toString() Returns a string that describes the object.
Final void wait Waits on another thread of execution.
final void wait(long milliseconds)
final void wait(long milliseconds,long
nanoseconds)
The toString() method returns a string that contains a description of the object on which it is called. Also,
this method is automatically called when an object is output (passed as ab argument ) using println().
Many classes override this method. Doing so allows them to tailor a version specifically suited for the
types of objects that they create.
135 | P a g e
360digrii
Java course material
Chapter 8 – Interfaces and Packages
Interfaces in Java
Interface is a reference type in the Java programming language. It is similar to a class where only
constants, method signatures and nested types can be contained. No method bodies are available. You
cannot instantiate interfaces as they can only be implemented by classes or extended by other interface/s.
// method signatures
int turn(Direction direction,double radius, // An enum with values
RIGHT, LEFT
double startSpeed, double endSpeed);
int changeLanes(Direction direction, double startSpeed, double endSpeed);
int signalTurn(Direction direction, boolean signalOn);
int getRadarFront(double distanceToCar, double speedOfCar);
int getRadarRear(double distanceToCar, double speedOfCar);
......
// more methods
}
Have you noticed something here? The thing to notice here is that method signatures have no braces and
that they are terminated with a semicolon.
You need to write a class that implements the interface, if you want to use an interface. A method body for
each of the methods declared in the interface is provided when an instantiable class implements an
interface. Look at the following example:
Interfaces as APIs
The example of the robotic car shows as interface being used as an industry standard Application
Programming Interface, better known as API. In commercial software products also, APIs are commonly
used. Typically, a company can sell a software package containing complex methods. This can be wanted
by another company to be used in its own software product. Say for instance, package of digital image
processing methods that are sold to companies that make end-user graphics programs. A class is written
by the image processing company to implement an interface, which is made public to its customers. After
this, image-processing methods are invoked by the graphics company, using the signatures and return
types defined in the interface. Note that, only the API of the image processing company is made public to
its customer, not the implementation of this API. This is a tightly guarded secret. The company might also
consider revising the implementation some time later on, as long as the original interface that the
customers have relied on is continued to be implemented by the company.
In Java programming language, interfaces have another very important role. Although interfaces work in
combination with classes, they are not part of the class hierarchy.
A class can inherit from only one class in Java. However, note that more than one interface can be
implemented by it. Objects can, therefore, have multiple types –i.e. the type of their own class and the
types of all the interfaces implemented by them. If a variable is declared to be the type of an interface, its
value can reference any object instantiated from any class implementing the interface.
Defining an Interface
Modifiers, the keyword interface, the interface name, a comma-separated list of parent interfaces (if any),
and the interface body construct an interface declaration. Take a look at the following example:
// constant declarations
double E = 2.718282; // base of natural logs
// method signatures
void doSomething (int i, double x);
137 | P a g e
360digrii
Java course material
int doSomethingElse(String s);
}
That the interface can be used by any class in any package, is indicated by the public access specifier. The
interface will be accessible only to classes defined in the same package as the interface, if it is not specified
that the interface is public.
Interfaces can be extended by another interface, just like a class can be extended or sub-classed by another
class. The difference here is that a class can extend only one other class, but any numbers of interfaces can
be extended by one interface. A comma-separated list of all the interfaces that it extends is included in an
interface declaration.
Constant declarations and method declarations can be contained within an interface. Remember that
every constant values defined in an interface are implicitly public, static and final. Also note that, these
modifiers can be omitted.
Implementing an Interface
You need to include an implements clause in the class declaration in order to declare a class that
implements an interface. More than one interface can be implemented by your class. The implement clause
follows the extend clause, if there is one, by convention.
If there is some way to compare the relative “size” of objects instantiated from the class, then any class can
implement Relatable. For instance, it could be the number of characters for strings; the number of pages
for book; weight for the students and so on. Area for planar geometric objects, and volume for three-
138 | P a g e
360digrii
Java course material
dimensional geometric objects can be good choices. The isLargerThan() method can be implented to all
the classes like this.
You can compare the size of objects instantiated from the class if you know that a class implements
Relatable.
// four constructors
public RectanglePlus() {
rect_origin = new Point(0, 0);
}
public RectanglePlus(Point p) {
rect_origin = p;
}
public RectanglePlus(int w, int h) {
rect_origin = new Point(0, 0);
rect_width = w;
rect_height = h;
}
public RectanglePlus(Point p, int w, int h) {
rect_origin = p;
rect_width = w;
rect_height = h;
}
What does actually happen when a new interface is defined? In that case a new reference datatype is being
defined by you. The interface names can be used wherever any other data type name can be used. In case a
reference variable, the type of which is an interface, is defined. Any object assigned to it must be an
instance of a class that implements the interface.
In the following example, look at the following method for finding the largest object in a pair of objects, for
any objects that are instantiated from a class that implements Relatable:
If Relatable is implemented in a wide variety of classes, you can compare the objects instantiated from any
of those classes with the findLargest() method. However, note that this is possible only when both objects
are of the same class. All of them can also be compared with the following methods:
Rewriting Interfaces
}
If this change is made then all classes that implement the old DoIt interface will be broken down since the
interface is not implemented by them anymore.
Attempting to anticipate all uses of your interface and specifying it from the beginning is a good practice.
However, as this is not always possible, the way out is to create more interfaces later. For instance, a
DoItPlus interface that extends DoIt can be created:
public interface DoItPlus extends DoIt {
141 | P a g e
360digrii
Java course material
Your code can now be chosen by the user to continue to use the old interface or to upgrade the new
interface.
Using Packages
Programmers cluster groups of related types into packages for making it easier to find and use types.
Avoid naming conflicts and control access.
Definition: A package is a grouping of related types providing access protection and name space
management.
Types that are part of the JAVA platform, are members of various packages that bundle classes by function.
In java.lang you will find the fundamental classes. In java.io you will find the classes for reading and
writing (i.e. input and output). Your types can also be put in your packages.
Classes, interfaces, enumerations, and annotation types are referred to by types. Note that types are often
referred to simply as classes and interfaces, since respectively enumerations and annotation types are
special kinds of classes and interfaces.
Suppose a group of classes like circles, rectangles, lines, and points i.e. classes that represent drawing
objects are written. There is also an interface named Movable which other classes implement so that you
can move them with the mouse:
It can be easily determined by you and the other programmers that these types are related.
This enables you and other programmers to know where to find types that can provide drawings related functions.
Names of your types will not conflict with the type names in other packages, since a new namespace is created by the
packages.
Types can be allowed within the package to have unrestricted access to one another. Access for types outside the
package can still be restricted.
Creating a Package
If you want to create a package, you need to choose a name for the package and put a package statement
with that name at the top of every source file which you want to be included in the package. Note that
every source file contains types like classes, interfaces, enumerations and annotation types.
The first line in the source file must be package the statement (package drawings, for instance). Each
source file can have only one package statement and this applies to all the types in the file.
Note: When multiple types are put in a single file, only one can be public and that must have the same
name as the source file. For instance, the public class Circle can be defined in the file Circle.java, public
interface Movable in the Movable.java, public enum Day in the file Day.java and so on.
Note that, non-public types in the same file can be included as a public type. But try to avoid this practice
everywhere, except when the non-public types are small and closely related to the public type. However,
from the outside of the package, only the public type will be accessible. Note that each and every top-level,
non-public types will be package private.
You would need six source files if you put the drawing interface and classes listed in the preceding section
in a package called drawings. Consider the following:
Naming Packages
Given the proliferation of Java programmers throughout the world, it is a pretty likely scenario that many
of them would use the same name for different types. Consider the previous example where a Rectangle
class is defined while it is still in the java.awt package. Note that there is already a Rectangle class. Yet both
the classes are allowed by the compiler to have the same name provided they are in different packages.
The package name is included by the fully qualified name of each Rectangle class. The fully qualified name
of the Rectangle class is drawings.Rectangle in the drawings package and java.awt.Rectangle in the
java.awt package.
But what if the same name is used by two independent programmers in their packages? That is where
convention comes in.
144 | P a g e
360digrii
Java course material
Naming Conventions
How to avoid the conflict with the names of classes or interfaces? Write package names in all lower cases.
Reversed Internet domain names are used by the companies to begin their package names. Consider
com.example.ortel. This is a package name Ortel, created by example.com.
Use convention within a company to handle name collisions that occur within a single company. There
might be different ways to do this. For instance, you can consider including the region or the project name
after the company name (for example, com.company.region.package).
Remember that packages in the Java language itself begin with java. or javax.
There might be cases when the Internet domain contains a hyphen or some other special character. The
package name might begin with a digit or other character that is illegal to use at the beginning of a Java
name. There might be a reserved Java keyword, like “int” contained in the package name. Note that in
these cases the Internet domain name may not be a valid package name. In all these cases the convention
is to add an underscore:
If you need to use a package member from outside its package, then depending on the situation, one of the
following steps has to be taken:
drawings.Rectangle
This qualified name could have been used to create an instance of drawings.Rectangle:
import drawings.Rectangle;
The Rectangle class can be referred by its simple name:
Rectangle myRectangle = new Rectangle();
Note that this works well when only a few members of the drawings package is used. Remember that the
entire package needs to be imported if many types from a package are used.
import drawings.*;
Now to any class or interface in the drawings package can be referred to its simple name. Consider the
following:
146 | P a g e
360digrii
Java course material
Note: You can use a less common form of import to import the public nested classes of an enclosing class.
Consider the case of the drawings.Rectangle class again. If this class had contained useful nested classes,
like Rectangle.DoubleWide and Rectangle.Square, you could use the following two statements to import
both the Rectangle and its nested classes:
import drawings.Rectangle;
import drawings.Rectangle.*;
Note that, here the Rectangle is not imported by the second import statement.
Static import statement is one more among the less common forms of import.
To make things easy three entire packages are imported automatically by the Java compiler for each
source file:
Consider the case of the Java API including a java.awt package, a java.awt.color package, a java.awt.font
package, and many others that begin with java.awt. You might have thought that there is a hierarchy
among packages, but they are actually not so. Notice that the java.awt package doe not include the
java.awt.color package, the java.awt.font package, and whatever other java.awt.xxxx packages are there.
The prefix java.awt (the Java Abstract Window Toolkit) is used only for a number of related packages to
make the relationship evident, but not to show inclusion.
What happens is that when you import the java.awt.* that imports all of the types in the java.awt package.
However, java.awt.color, java.awt.font, or any other java.awt.xxxx packages are not imported with this. You
need to import both the java.awt.color and java.awt packages with all their files if you want use the classes
and other types in both of them. You need to write the following:
import java.awt.*;
import java.awt.color.*;
Name Ambiguities
What happens if the name of a member in one package is shared with a member in another package and
both packages are imported? The answer is that then each member needs to be referred to by its qualified
name. Consider the case of when the drawings package defines a class named Rectangle. A Rectangle class
is also contained by the java.awt package. Now, if you import both the drawings and the java.awt, the
following becomes ambiguous.
Rectangle rect;
147 | P a g e
360digrii
Java course material
How do you indicate, which Rectangle class you exactly want in this kind of a situation? You need to use
the fully qualified name of the member:
drawings.Rectangle rect;
Consider a situation when frequent access to both static final fields (constants) and static methods from
one or two classes are needed. Your code can become a bit cluttered if you prefix the name of these classes
repetitively. Avoid prefixing and use the static import statement to import the constants as well as the
static methods you need.
The PI constant and multiple static methods, like methods for calculating sines, cosines, tangents, square
roots, maxima, minima, exponents, and many others are defined by the java.lang.Math class. Consider the
following example:
Note: You need to be cautious while using static import as overuse of it might result in codes thar are
difficult for both reading and maintaining. For instance, readers will not know that a particular static
object is defined by which class. The only way static import makes a more readable code is when it
removes the class name repetition.
148 | P a g e
360digrii
Java course material
Managing Source and Class Files
To manage source and file classes, many implementations on the Java platform rely on hierarchical file
systems. However, it is not required by the Java Language specification. The strategy is to put the source
code for an interface, enumeration, or annotation type in a text file whose name is the simple name of the
type and whose extension is .java. For instance:
.....\drawings\Rectangle.java
Assuming that the Microsoft Windows file name separator is backslash or the forward slash for Unix, the
qualified name of the package member and the path name to the file are parallel.
A company uses its reversed Internet domain name for its package names by using convention. In the
example of the company whose Internet domain name was example.com, all its package names will be
preceded by com.example. Each component of the package name is correspondent to a subdirectory.
Suppose the company had a com.example.drawings package that contained a Rectangle.java source file.
Now it will be contained in a series of subdirectories:
....\com\example\drawings\Rectangle.java
The compiler creates a different output file for each type when a source file is compiled. The name of the
type is the base name of the output file while the extension is .class. If the source class is like, say:
class Helper{
...
}
then the location of the compiled files will be at:
149 | P a g e
360digrii
Java course material
<path to the parent directory of the output files>\com\example\drawings\Rectangle.class
<path to the parent directory of the output files>\com\example\drawings\Helper.class
The compiled.class files, like the .java source files, should be in a series of directories, that reflect the
package name. The path to the .class files does not necessarily need to be the same as the path to the .java
source files. The source and class directories can be arranged separately:
<path_one>\sources\com\example\drawings\Rectangle.java
<path_two>\classes\com\example\drawings\Rectangle.class
The advantage of this is that the classes directory can be given to other programmers without revealing
the sources. Also the Java Virtual Machine can find all the types used in your program if it manages source
and class files in this manner.
The class path is the full path to the classes directory –i.e. path_two>\classes. This is set with the set
CLASSPATH system variable. The path to your .class files is constructed by both the compiler and the JVM.
They do this by adding the package name to the class path. For instance, if
<path_two>\classes
is your class path, and the package name is
com\example\drawings,
then the compiler and JVM look for .class files in
<path_two>\classes\com\example\drawings.
Several paths, separated by semicolon (in Windows) or a colon (in Unix) may be included in a classpath.
The current directory and the JAR file containing the Java platform classes are searched by the compiler
and the JVM by default. The advantage of this is that these directories automatically come in your program
classpath.
To display the current CLASSPATH variable, use these commands in Windows and Unix (Bourne shell):
150 | P a g e
360digrii
Java course material
Chapter 9 – Exceptions
Exception: An Overview
You are familiar with writing small Java programs. But whether it is a small or a large program, it is
impossible that errors will not occur in programs at some points. Though the complier detects the syntax
errors during compilation yet there are errors that are detected during execution.
Many programming languages like BASIC, PASCAL and C do not provide the facility to detect errors or take
corrective actions during run-time. In the event of an error, the programs written in these languages
terminate abruptly causing the control to be transferred to the operating system. It is the responsibility of
the programmers to ensure that the programs are error-free. Errors should be checked and handled
manually by using error codes. But this kind of programming is very cumbersome and leads to complex
code, that is, a code that is very difficult to manage.
What is an Exception?
An exception is an event that occurs during the execution of a program that disrupts the normal flow of
instructions.
Consider an example in which we try to open a file and read from it.
Example:
151 | P a g e
360digrii
Java course material
There are various situations when an exception could occur:
Exception-Handling Fundamentals
You can provide ability to your program in order to intercept run-time errors, take corrective measures
and also continue the execution without fail is referred to as 'Exception Handling'.
A Java exception is an object automatically dispatched, that describes an exceptional (that is, error)
condition that has occurred in a statement of your program. When an exceptional condition arises in any
statement, an object representing that exception is created and is thrown or dispatched. If the statement is
within a method, then it may choose to handle the exception itself, or pass it on to the default handler.
Either way, at some point, the exception is caught within the method or default handler and it get
processed. If the exception is caught by the default handler, then it provides a message at the console
termed as StackTrace.
The Java run-time system is having the ability to generate an Exception, or your code can manually
generate the Exception. Exceptions thrown by Java, relate to fundamental errors that violate the rules &
regulations of the Java language or the constraints of the Java execution environment. Manually generated
exceptions are typically used to report some error condition to the caller of a method.
Blocks:
try { }
catch () { }
finally { }
Clauses:
throw
throws
The statements within your program, you anticipate to produce errors at runtime and want to monitor the
same, is advised to be kept within a try block. If an exception occurs within the try block, then one object
of corresponding type will be thrown by Java run-time environment. You can catch this exception (using
catch block) and handle it in some rational manner. The exceptions generated by system are
152 | P a g e
360digrii
Java course material
automatically thrown by the Java run-time system. To throw an exception manually within your program,
you have to use the keyword throw.
Any exception that is being thrown within a method and is not handled within it, must be specified by a
throws clause in the method signature. Any code that is to be executed absolutely at any cost, even if the
control of the program goes to it or not, has to be put in a finally block.
try {
// block of code to monitor for errors
}
catch (ExceptionType1 e1) {
// exception handler for ExceptionType1
}
catch (ExceptionType2 e2) {
// exception handler for ExceptionType2
}
// ...
finally {
// block of code to be executed before try block ends
}
Here, ExceptionType is a type of exception that has occurred and being dispatched at run time of the
program, which need to be caught. The remaining chapter describes how to apply this framework.
Exception Types
All types of exceptions present in any hierarchy of Java are subclasses of the built-in class Throwable.
Thus, Throwable is at the top of the exception class hierarchy. Throwable class is followed by two
subclasses that break exceptions into two distinct branches. One branch is headed by Exception and the
other is Error. This class is used for exceptional conditions that user programs should catch. This is also
the class that you will subclass to create your own custom exception types. There is an important subclass
of Exception, called RuntimeException. Exceptions of the types are automatically defined for the programs
that you write and include things such as division by zero and invalid array indexing.
The other branch is topped by Error, which says that you cannot expect to catch the Errors under normal
circumstances within your program.
The Java run-time system uses exceptions of the type Error to indicate errors that are related to the run-
time environment itself. An example of this kind of an error is stack overflow. Note that the Error category
could not be handled within your programs.
153 | P a g e
360digrii
Java course material
Uncaught Exceptions
Before you learn how to implement the exception handling mechanisms in your program, it is advisable to
see what happens when you don’t handle them. The following is a small program that includes an
expression that intentionally causes a divide-by-zero error.
Example: ExceptionTestDemo.java:
java.lang.ArithmeticException: / by zero
at ExceptionTestDemo.main(ExceptionDemo.java:4)
You can notice how the class name, ExceptionTestDemo; the method name, main; the filename,
ExceptionTestDemo; and the line number, 4, are all included in the simple stack trace. Also, you can notice
that the type of the exception thrown is a subclass of Exception class called ArithmeticException, which
describes what type of error happened. Java supplies several built-in exception types that match the
various sorts of run-time errors that can be generated.
The sequence of method invocations that led upto the error will always be shown by the stack trace.
Consider the example of RevisedExceptionTestDemo.java. This is another version of the
ExceptionTestDemo.java program. The same error is introduced here, however, in a separate method from
main( ):
Example: RevisedExceptionDemo.java:
java.lang.ArithmeticException: / by zero
at RevisedExceptionTestDemo.subroutine(RevisedExceptionTestDemo.java:4)
at RevisedExceptionTestDemo.main(RevisedExceptionTestDemo.java:7)
155 | P a g e
360digrii
Java course material
Now after execution, you can see, the bottom of the stack is main’s line 7, which is the call to subroutine(),
which caused the exception at line 4. The call stack is quite useful for debugging because it pinpoints the
precise sequence of steps that led to the error.
As you know Exception Handling can be performed by the default exception handler provided by the Java
run-time system, you can also handle an exception by yourself. This benefits you in two different ways.
First, it allows you to fix the error. Second, it prevents the program from automatically terminating. Most
of the end users would be confused if your program stopped running and prints a stack trace whenever an
error occurred. You need not worry. It is quite easy to prevent this.
In order to guard against this and handle a run-time error, simply enclose the code that you anticipate to
throw errors at run time and want to monitor the same; inside a try block. A catch block must follow the
try block that specifies the exception type that you wish to catch. The following program illustrates how
easily this can be done. The ExceptionDemoTryCatch.java program includes a try block and a catch clause,
which processes the ArithmeticException generated by the division-by-zero error:
Example: ExceptionDemoTryCatch.java
Division by zero.
After catch statement.
What is happening here? The call to println( ) inside the try block will never be executed. Now throw an
exception. With this, the control of the program will transfer itself out of the try block and will enter in the
catch block that follows it. You have noticed that the execution never “returns” to the try block from a
catch since the catch itself is not “called”. Therefore, “This will not be printed.” is not displayed. Once the
catch statement has executed, program control continues with the next line in the program following the
entire try/catch mechanism.
156 | P a g e
360digrii
Java course material
A unit is formed by a try and its catch statement. The immediately preceding try statement restricts the
scope of the catch clause to those statements. The only exception is in the case of the nested try
statements, where an exception thrown by another try statement cannot be caught by a catch block.
Remember that the braces that are protected by try, must be surrounded by curly braces.
In some scenarios, more than one exception could be raised by a single piece of code. To handle this type
of scenarios, you can specify two or more catch blocks, each catching a different type of exception. When
an exception is thrown, each catch statement is inspected in order and the first one whose type matches
with that of the exception is executed. After one catch statement is executed, the others are bypassed and
execution continues after the try/catch block. The MultiCatchTestDemo.java traps two different exception
types:
Example: MultiCatchTestDemo.java:
C:\>java MultiCatchTestDemo
a=0
157 | P a g e
360digrii
Java course material
Divide by 0: java.lang.ArithmeticException: / by zero
After try/catch blocks.
Further, in Java, unreachable code is an error. For example, consider the SuperSubCatchTestDemo.java:
Example: SuperSubCatchTestDemo.java:
158 | P a g e
360digrii
Java course material
Using Throw
So, far you have seen exceptions that are thrown by the Java run-time system. You can also make your
program explicitly throw an exception by using the throw statement.
throw ThrowableObject;
Notice that the above statement throws an object that represents an exception. It is an object of class
Exception or class Throwable or any of its subclasses.
Using Throws
Sometimes, a method may throw an exception but does not handle it itself. Instead, the callers of the
method should provide an exception context in the form of a try block and a corresponding catch handler
for the exception. The method only specifies the exception it is throwing. A method can throw more than
one exception. For example:
If a code contains statements to open and read a file, the corresponding method could throw:
FileNotFoundException
IOException
159 | P a g e
360digrii
Java course material
EOFException
Hence, wherever this method is used, you should guard against these exceptions. That is, this method
should be called in a try block and the respective exceptions should be caught.
Example: ThrowsDemo.java:
import java.io.*;
public class ThrowsDemo{
When you run ThrowsDemo.java, with a filename as the parameter that does not exist, the following
would be printed.
Inside processFileMethod...
Cannot find file (filename)
Using finally
In a program whenever an exception occurs, the execution of the program stops. There could be situations
where you establish a connection with a database and an exception occurs. The program terminates, but
the connection with the database is still open. This is not desirable from security point of view. To handle
such situations, finally blocks should be used.
Irrespective of whether the exception occurs or not, the code inside the finally blocks should be used. This
is because both under the situation of exception and non-exception, the control will go to the finally block.
The finally block is optional, though usually the cleanup code like closing the files, or closing the database
connections are kept in the finally block.
Example: FinallyDemo.java
class FinallyDemo{
160 | P a g e
360digrii
Java course material
public static void main(String args[])
{
try{
int x=Integer.parseInt(args[0]);
int y=Integer.parseInt(args[1]);
System.out.println("Dividing two numbers");
int z=x/y;
//Following line will be skipped if exception occurs
System.out.println("The result is " + z);
}
catch (ArithmeticException e)
{
System.out.println("The denominator was zero");
}
finally
{
System.out.println("In the finally block");
}
}
}
When you will run FinallyDemo.java program along with command line parameter 10 and 0, it will throw
ArithmeticException. If the parameters are given as 10 and 5 then Exception will not be thrown. But in
both the cases, the finally block will be executed.
Built-in Exceptions
You know that the package java.lang is implicitly imported into all Java programs. The java.lang package
contains the exception classes, most of which are of type RuntimeException. Therefore, all these exception
classes are automatically available to our programs. The run time exceptions are further divided into two
categories: 'checked exceptions' and 'unchecked exceptions'.
Checked exceptions are exceptions that should be specified in the throws list of the methods that may
throw these exceptions. The complier checks to see whether any exceptions are specified or not. If they are
not specified, then the compiler gives a compilation error. Following are some of the checked exceptions:
ClassNotFoundException
NoSuchMethodException
InterruptedException
IllegalException
InstantiationException
161 | P a g e
360digrii
Java course material
Unchecked exceptions are exceptions that may not be included in a method's throws list. A method may or
may not throw these exceptions. The complier does not check for these exceptions. Hence, these
exceptions are called unchecked exceptions.
ArithmeticException
ArrayIndexOutOfBoundsException
NegativeArraySizeException
ClassCastException
NullPointerException
SecurityException
User-defined Exceptions
Although the Java language had provided a list of exceptions to handle various situations, it has also
provided the facility of creating your own exceptions. There can be situations when you want to handle a
specific situation and the available exceptions cannot fulfill your need. For example, you are writing a java
program for a company, which recruits people within the age group of 21 and 60 only. In such a case you
can create your own exception class and cause an object of this exception class to be thrown in case the
age of the incumbent is either less than 21 or greater than 60. You have to subclass your exception class
from the class Exception.
In the TestException.java, first a user-defined exception called, MyException is created by extending the
class Exception. Then a class TestException is created which contains a method called checkAge(), that
checks whether the age is between 21 and 60. The checkAge() method is capable of throwing the
exception of type MyException. If checkAge() method is invoked with an invalid age, it throws an object of
the MyException class and the exception is later handled, thus displaying the error message.
Example: TestException.java
Called Program
int age;
AgeException(String message) {
super(message);
AgeException() {
super();
int ageLimit;
163 | P a g e
360digrii
Java course material
OutOfAgeLimitException(int ageLimit, String message) {
super(message);
this.ageLimit = ageLimit;
OutOfAgeLimitException(String message) {
super(message);
this.age = age;
TooYoungException() {
super("too young");
this.age = age;
TooOldException() {
super("too old");
164 | P a g e
360digrii
Java course material
}
IllegalAgeFormatException(String message) {
super(message);
IllegalAgeFormatException() {
NegativeAgeException(String message) {
super(message);
NegativeAgeException(int age) {
this.age = age;
}
Callable Program
import java.io.*;
165 | P a g e
360digrii
Java course material
throws NegativeAgeException, OutOfAgeLimitException {
age + "...");
if (age < 0)
try {
rideRollerCoasterAtAge(ages[i]);
} catch (OutOfAgeLimitException e) {
out.println(e.getMessage());
out.println((e.ageLimit - ages[i]) +
166 | P a g e
360digrii
Java course material
else
out.println((ages[i] - e.ageLimit) +
} catch (NegativeAgeException e) {
out.println(e.getMessage());
} finally {
out.println();
Advantages of Exceptions
Now that you know what are exceptions and how to use them, your next step should be to know the
advantages of using exceptions in programming.
All is well and good if the program runs normally. But what if you suddenly find certain things start
happening outside the main programming logic? Naturally, it becomes a little tiresome working with the
program since detecting error, reporting and handling tend to lead to codes that are confusing if the
programming is done in a traditional fashion. Exceptions help in separating the details of what to do in
such cases. Take a close look at the following example. Note that the pseudocode method has been used
here to read an entire file into memory:
readFile {
open the file;
determine its size;
allocate that much memory;
read the file into memory;
close the file;
}
What is the problem with this function? The problem is that some potential errors are ignored by this
function:
167 | P a g e
360digrii
Java course material
Suppose a situation where you cannot determine the length of the file. What happens then?
Suppose a situation where enough memory cannot be allocated. What happens then?
What if the read fails?
What if the file cannot be closed?
More codes must be contained in the readFile function. Why? Because otherwise, error detection,
reporting and handling become very tedious processes. Take a close look at the following ReadFile.java
example. This illustrates what the function might actually look like:
class ReadFile{
errorCodeType readFile {
initialize errorCode = 0;
168 | P a g e
360digrii
Java course material
lost. Also, can you tell for certain whether the file is really being closed if the function fails to allocate
enough memory? Or can you ensure that the code still continues to do the right things even several
months after it was written? Most of the times these little nuggets are ignored and as a result, the program
itself ultimately crashes!
The advantage of using exceptions is that you can write the main flow of your program and yet deal with
the exceptions in other places. Let us suppose the readFile function uses “except” (in place of the error-
management techniques that are traditionally used). Now take a close look at the following:
readFile {
try {
open the file;
determine its size;
allocate that much memory;
read the file into memory;
close the file;
} catch (fileOpenFailed) {
doSomething;
} catch (sizeDeterminationFailed) {
doSomething;
} catch (memoryAllocationFailed) {
doSomething;
} catch (readFailed) {
doSomething;
} catch (fileCloseFailed) {
doSomething;
}
}
Note: Exceptions help you in organizing your work more effectively, not in the actual process of detecting,
reporting or handling errors.
Error-reporting up the call stack of methods can be distributed by exceptions. Consider the following:
The main program makes calls in a series of nested methods where the readFile is the third method.
Method1 calls method2 and finally the call to readFile is made by method3.
method1 {
call method2;
}
169 | P a g e
360digrii
Java course material
method2 {
call method3;
}
method3 {
call readFile;
}
Now think of method1 as the only relevant method in the errors that might take place within the readFile.
Method 2 and Method 3 would have been forced by the error-notification techniques that are traditional in
nature. These techniques will send the error codes returned by the readFile. This will be sent up the call
stack. This will continue till the error codes finally reach method1, which is the interested method.
method1 {
errorCodeType error;
error = call method2;
if (error)
doErrorProcessing;
else
proceed;
}
errorCodeType method2 {
errorCodeType error;
error = call method3;
if (error)
return error;
else
proceed;
}
errorCodeType method3 {
errorCodeType error;
error = call readFile;
if (error)
return error;
else
proceed;
}
In order to find any methods interested in handling a particular exception, the JRE searches backward
through the call stack. Any exceptions thrown within a method can be ducked by the method itself. This
allows a method further up the call stack to catch it. The advantage is that this allows only those methods
that are interested in detecting and catching errors to do so, leaving the others aside.
method1 {
170 | P a g e
360digrii
Java course material
try {
call method2;
} catch (exception e) {
doErrorProcessing;
}
}
The grouping or categorizing of exceptions is a natural outcome of the class hierarchy since all exceptions
thrown within a program are objects. The exception classes are defined in the Java platform. Note that
these are examples of group or related exception classes. They are defined in the java.io – IOException and
its descendants. The most general exception is the IOException. It represents any type of errors that can
take place while an I/O operation is being performed. More specific errors are represented by its
descendants. Consider how you will represent the case of a file that cannot be located on the disk. Use the
FileNotFoundException.
What about a very specific exception? The specific handler/s can handle this while a method will be used
to write it. The following handler can only handle only one type of exception, since the
FileNotFoundException class does not have any descendants.
Specific handlers can be written by a method. These handlers can then handle a very specific expression.
No descendants are available for the FileNotFoundException class. Therefore, you handle just one type of
exception with the usage of the following handler in this example:
catch (FileNotFoundException e) {
...
}
An exception can be caught by a method. This will be caught on the basis of its group or general type, or by
specifying any of the exception’s superclasses in the catch statement. To catch all the I/O exceptions, an
exception handler will specify an IOException, irrespective of their specific types.
catch (IOException e) {
...
171 | P a g e
360digrii
Java course material
}
All the I/O exceptions will be caught by the handler. The FileNotFoundException, EOFException will also
be caught. How can you find the details of what happenned when you are querying the argument while it
was being passed through the exception handler. Consider the following case.
catch (IOException e) {
e.printStackTrace(); //Output goes to System.err.
e.printStackTrace(System.out); //Send trace to stdout.
}
Set up an exception handler. This exception handler will handle any exception with the handler.
Groups of exceptions can be created and handled in a general fashion. The specific exception type to
differentiate and handle exceptions in exact manner can also be used.
172 | P a g e
360digrii
Java course material
Chapter 10- Multithreading
Introduction
Knowingly or unknowingly in our everyday life we always perform a number of tasks simultaneously.
Have you ever realized that when you are driving a car, at the same time, your hands work on the steering
and gear, your feet work on the brakes and clutch, your eyes see the road you are driving on and most
importantly your mind is aware of all the moving things around your vehicle. This smart synchronization
of different activities at the same time by you is what we call ‘Multitasking’ and this is being implemented
by your brain through ‘Multithreading’.
This chapter discusses about threads and its usage. Assume that you have faced a situation where your
browser cannot skip to the next web page because it is downloading a file? Or that you cannot enter text
into your current document until your word processor completes the task of saving the document to the
disk.
These situations occur when the software you are using like the browser or word processor consists of a
single thread. Threads are separate tasks running within a program. If your program consists of a single
thread it can handle only one activity at a time. Thus it will take huge amount of time to complete multiple
jobs and time management will be an issue.
While designing any computer system or software, the problem lies with managing time. We take for
granted that modern computer systems such as desktop computers can manage many applications
running concurrently and produce the effect that the software is running simultaneously. This is made
possible by CPU time sharing, whereby the OS runs one program for a short duration of time (e.g. a few
milliseconds), and then switches to the other program, and then switches back to the first program. The
operating system can run several programs concurrently by switching back and forth among them.
What is a Process?
Before going into Threads, let us first understand what a process is, since threads have evolved to
overcome certain drawbacks of a process.
A process is an instance of a computer program that is executed sequentially. It is a collection of
instructions, which are executed simultaneously at the run time. Thus several processes may be associated
with the same program. For example, to check the spelling is a single process in the Word Processor
program and you can also use other processes like printing, formatting, drawing, etc. associated with this
program.
What is a Thread?
When you develop and deploy a web application over the net, you require greater concurrency. One can
get it done only by running multiple processes and establishing a communication between them. Handling
such issue/s, using process was a heavy weight approach and not a very efficient one.
Later, the concept of threads was introduced. Threads provide fine-grained concurrency within a process,
under the application's own control. Threads extend the concept of switching among several programs to
switching among different processes in the same program. Under the given context it would be ideal to
understand the relationship between a Process and a Thread. A process can split into multiple threads that
173 | P a g e
360digrii
Java course material
share the same resources using time slices. Admittedly, multiple processes can also share the same
resources but it is simpler using threads.
Process Vs Thread
Both threads and processes are ways to achieve concurrency in an application. However if implemented
correctly, threads have some advantages over processes.
It takes:
Less time to create a new thread than a process, because the newly created thread uses the current
process address space.
Less time to terminate a thread than a process.
Less time to switch between two threads within the same process, partly because the newly created
thread uses the current process address space.
Less communication overheads - Communicating between the threads of one process is simple because
the threads share everything: address space, in particular. So, data produced by one thread is
immediately available to all the other threads.
What is Multitasking?
Even before you enter into multithreading, it would be appropriate for you to learn about multitasking.
There are lots of conceptual similarities between multitasking and multithreading. Multitasking is referred
to as process based multitasking whereas multithreading is referred to as thread based multitasking.
All modern operating systems support multitasking, which is actually process-based multitasking. A
process is an executing instance of a program, i.e., a program in a state of execution. Process based
multitasking is the feature that allows your computer (with the help of the operating system) to run two or
more programs concurrently. Multitasking seemingly creates an illusion of running two or more programs
simultaneously, but in reality, it executes only one program at any given point of time. The operating
system does this so efficiently that it seems that it is handling more than one program simultaneously. Of
course, it is a different connotation when implemented on a multiprocessor architecture or systems
supporting parallel computing like supercomputers. In process-based multitasking, a program is the
smallest unit of code that can be dispatched by the scheduler.
In a thread based multitasking environment, the thread is the smallest unit of code that can be dispatched
by the thread scheduler. This means that a single program can perform two or more tasks concurrently. It
must be noted though that if there are multiple threads in a program, only one thread will be executing at
any given point of time in single processor architecture.
Multitasking threads cost less in terms of processor overhead when compared to multitasking processes.
Each process requires its own separate address space or memory area to run in. Therefore context
switching from one process to another is a CPU intensive task and hence more time-consuming. This is
one of the reasons why process is referred to as a Heavyweight task. Threads, on the other hand, are
lightweight processes. Multiple threads in a program share the same address space and cooperatively
share the same heavyweight process.
Inter-process communication between processes is again expensive, as the communication mechanism
has to span over separate address spaces or memory areas. Inter-thread communication, on the other
174 | P a g e
360digrii
Java course material
hand, is less expensive as it involves a communication wherein multiple threads in a program
communicate within the same address space or memory area.
What is multithreading?
Multithreaded programming is the implementation of an application such as where two or more activities
are performed concurrently within the same application. This is accomplished by having each activity
performed by its own thread.
Threads are the lightest tasks within a program and they share memory space and resources with each
other. When efficiently used, they can prevent the user interface from being tied up while the program is
performing a lengthy operation.
Why Multithreading?
Multithreading enables you to write very efficient programs that make maximum use of the CPU, because
idle time of the CPU can be kept down to a minimum. This is especially important for the interactive,
networked and internet environments in which Java operates, since the idle time is common.
For example, there may be an instruction in a program that is reading a file from a different host on the
network. Knowing that reading from a local file system itself is slow compared to the speed of the CPU,
reading from a file on a different host on the network is an even slower process. In a traditional single-
threaded environment, the rest of the program waits till this I/O instruction returns. Once the CPU
dispatches this I/O instruction, it is free. Ideally this idle time of the CPU should be put to good use by
executing some other discrete part of the program.
In the traditional single-threaded environment with reference to the aforesaid example, the CPU remains
idle till the I/O instruction returns, wasting precious CPU cycles meanwhile.
Multithreading and Multitasking
Java provides built-in support for multithreaded programming. A Multithreaded program contains two or
more parts that can run concurrently. If your application needs to run animations and play music while
scrolling the page and downloading a text file from a server, multithreading is the way to obtain fast,
lightweight concurrency within a single process space. Each thread defines a separate path of execution.
Multithreading is a specialized form of Multitasking.
Multitasking is divided into two types. They are
(1) Process based: Here two or more programs run concurrently. You can run Windows calculator and a
Text editor (Notepad) at the same time.
(2) Thread based: A single program can perform two or more tasks simultaneously. For example, the text
editor can print while formatting is being done.
Multithreading enables you to write very efficient programs that make maximum use of CPU, because idle
time can be kept to minimum by it. This is especially important for the interactive networked application
because idle time is common. In a traditional single threaded environment, your program has to wait for
each of the tasks to finish before it can proceed to the next one. This will result in idle time. Multithreading
lets you gain access to this idle time and put it to good use.
175 | P a g e
360digrii
Java course material
How Java Implements Multithreading?
In Java all the libraries and classes are designed with multithreading in mind. This enables the entire
system to be asynchronous.
The value of multithreading is best understood in contrast to the working of its counterpart, i.e. single-
threaded systems. Single–threaded systems use an approach called event loop with polling. In this model,
a single thread of control runs in an infinite loop, polling a single eventual queue to decide which
instruction to execute next. Once this mechanism returns with, say an instruction from the event queue
that a network file is about to be read, then the event loop dispatches control to that instruction. Until this
instruction returns, nothing else can happen in the system. This results in wastage of precious CPU cycles.
It can also result in one part of a program (say one that deals with the network I/O) dominating and
hogging CPU time and in the process preventing any other part of the program from being processed.
The Java language has steered clear of this problem by completely doing away with the event loop/polling
mechanism. One thread can progress slowly or pause without stopping other parts of your program, as
was the case in the single-threaded model. For example, the idle time created while a thread reads data
from and across a network can be used to handle another discrete part of the program, say printing a file.
In Java the java.lang.Thread class is used to create thread-based code. The Thread class is a member of the
java.lang package and is imported into all Java applications by default.
Each thread has its own stack and program counter (PC). You can think of the PC as keeping track of the
instruction that the thread is currently executing, and the stack as keeping track of the thread's context.
The context is where the thread is executing, and the contents of local variables. Under normal
circumstances, one thread cannot access the stack variables of another, although you could write routines
to pass data back and forth between threads.
Thread Priorities
A thread priority decides how a thread should be treated with respect to other threads. A thread's priority
is set when it is created. Threads can have any of a fixed number of priorities, where higher priority
176 | P a g e
360digrii
Java course material
threads are guaranteed to be scheduled before lower priority threads. A thread's priority is used to decide
when to switch from one running thread to another. This is called a context switch.
The rules for determining when a context switch takes place are as follows:
A thread can voluntarily relinquish control: This occurs as a result of either the thread explicitly yielding,
sleeping or blocking on pending Input/Output. Here, all threads are examined and the highest-priority
thread that is ready to run is given the CPU.
A thread can be pre-empted by a higher priority thread. Here, a lower-priority thread that does not yield
the processor is simply super ceded or preempted by a higher priority thread. Whenever a higher priority
thread wants to run, it does. This is called preemptive multitasking.
In case, two threads with the same priority compete for CPU time, threads are time-sliced in round-robin
fashion.
Synchronization
Since threads allow two or more tasks within the same program to execute at the same time, these threads
can also be sharing objects and data. Hence, you need to be sure that different threads do not try to access
and change the same data at the same time i.e., they must be synchronized in some way.
For example, imagine a Java application where one thread (the producer) writes data to a data structure
while a second thread (the consumer) reads data from the data structure. Or, as you type characters on
the keyboard, the producer thread places key events in an event queue and the consumer thread reads the
events from the same queue. Both of these examples use concurrent threads that share a common
resource: the first shares a data structure; the second shares an event queue.
An explanation of the aforesaid diagram is as follows: Suppose there is the producer thread in the
threaded object that is writing into a data structure within the thread object using a method say M1. While
177 | P a g e
360digrii
Java course material
the producer thread is in method M1 and in the process writing into the data structure, care must be taken
to ensure that while data is in the process of being written to the data structure, no other thread, say a
consumer thread is allowed to read object at the same time while the writing of data is on.
The consumer thread should wait till the producer thread has finished writing into the data structure, i.e.,
till the producer thread returns from method M1. The moment the producer thread returns from method
M1, the consumer thread should be allowed to access the data structure through method M2. As you can
see, the argument is moving towards a mechanism by which you are trying to ensure that no two threads
end up accessing a shared data structure at the same time since that might lead to corrupting the data in
the data structure and might also lead to unpredictable results.
This mechanism will in fact serialize access to shared data by multiple threads, i.e., each thread lines up
behind a running thread till the running thread has finishe its operation. The current thread, operating on
the shared data structure, must be granted mutually exclusive access to the data structure. This can be
done by ensuring that the current thread gets an exclusive lock on the shared data. We see that the
mechanism that we are discussing is a concurrency control mechanism used to ensure the integrity of a
shared data structure.
If the methods in the thread object through which the producer thread and the consumer thread write and
read data into the shared data structure are defined as ordinary methods, then this mechanism is not
guaranteed. It might well lead to a race condition when the producer and the consumer threads will race
with each other to complete their operation. A race condition can be prevented by defining the methods
M1 and M2 used by the producer thread and the consumer thread respectively as synchronized methods.
Synchronized methods are an elegant variation on a time-tested model of inter-process synchronization,
the monitor. The monitor is a thread control mechanism. When a thread enters a monitor (implemented in
Java as a synchronized method), all other threads must wait until that thread exits the monitor. The
monitor, therefore, helps in protecting shared data from being accessed by more than one thread at a time.
Most multithreaded systems expose monitors as objects that your multithreaded programs must explicitly
acquire and manage. Java provides a simpler and cleaner solution. Java does not provide a separate class
“Monitor”, rather, each object has its own implicit monitor that is automatically entered when one of the
object's synchronized methods is called. Once a thread is inside a synchronized method, no other thread
can call any other synchronized method on the same object.
Because Java was developed from the beginning with multithreading in mind, the language defines a
special keyword, synchronize, which can be applied to blocks of code, including entire methods, to prevent
multiple threads from executing the same block of code at the same time.
The synchronized keyword guarantees that only one thread will be able to execute the code segment at
one time and that any other thread will be blocked until the first one has finished.
Messaging
In Java you need not depend on the OS to establish communication between threads. All objects have
predefined methods, which can be called to provide inter thread communication.
178 | P a g e
360digrii
Java course material
The main thread or the parent thread is significant for the following reasons:
Method Description
179 | P a g e
360digrii
Java course material
currentThread() Get the current thread
It is the parent thread from which other child threads will be spawned or created.
The main thread must be the last thread to finish execution. When the main thread stops, the program
terminates.
The Thread class defines the methods you use to manage threads. The following table contains the
commonly used methods of the Thread class. You will see how these are used throughout the examples in
this chapter.
180 | P a g e
360digrii
Java course material
We declare the reference by specifying the name of the class and the name for the reference, which is done
by the following line of code:
Thread t
We acquire a reference to the main thread by calling the currentThread() method member of the Thread
class. The following method call is used:
Thread.currentThread()
The reference returned by the currentThread() method is then assigned to the reference previously
declared in the opening statement. We then display the thread on the screen:
Thread[main, 5,main]
Information within the square brackets tells us something about the thread. The first appearance of the
word main is the name of the thread. Next, the number 5 is known as thread Priority. The last occurrence
of the word main is the name of the group of threads alogside which the thread belongs. A thread group is
a data structure used to control the state of a collection of threads. You do not need to be concerned about
a thread group because the Java run-time environment handles this.
The setName() method is then called to illustrate how you have control over the main thread of your
program. The setName() method is a method member of the Thread class and is used to change the name
of a thread. This example uses the setName() method to change the main thread’s name from main to
Demo Thread. The thread is once again displayed on the screen to show that the name has been changed.
Here is what is displayed:
Renamed Thread: Thread[Demo Thread, 5,main]
In the earlier example, the number 5 is the thread’s priority, which is normal priority. The priority ranges
from 1 to 10, where 1 is the lowest priority and 10 is the highest.
Thread priorities are integers that specify the relative priority of one thread to another. Higher priority
threads do not run any faster than a lower priority thread. Instead, a thread’s priority is used to decide
when to switch from one running thread to the next. This is called the context switch.
Creating a Java Thread
Every thread in Java is created and controlled by the java.lang.Thread class. A Java program can have
many threads, and these threads can run concurrently, either asynchronously or synchronously. Java's
creators have designed two ways of creating threads:
Extending the java.lang.Thread Class
Implementing the java.lang.Runnable Interface
181 | P a g e
360digrii
Java course material
182 | P a g e
360digrii
Java course material
ThreadDemo.java generates the following output:
The thread has been started
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Explanation:
Lines 8 to 14 define a thread in the class Counter, which extends the Thread class.
Line 3 instantiates the thread:
Counter ct = new Counter();
Line 4 starts the thread:
ct.start();
Also note that the method run() of the class Thread is overridden in lines 9 through to 12. This is where
the task to be performed by the thread is coded. Understand that calling the method start() does not
immediately execute the thread. It makes the thread a candidate for running, and the thread has to
contend for the CPU time (remember, the whole idea of multithreading is to have more threads in one
application, and hence they have to share the CPU). Eventually the scheduler will start running the thread
by starting the execution of the method run().
The main execution thread creates and starts another thread in lines 3 and 4.
Without waiting for the control to return back from the method start(), it continues to execute the next
line, as both threads are executing concurrently. Therefore, it is possible that when you run this program,
the output from line 5 will appear before the output of line 4 (the print statement in line 11), as shown
above.
If your thread class already extends another class, it cannot extend the Thread class because Java supports
only single inheritance. In this case, your thread class can implement the Runnable interface.
Defining, instantiating, and starting a thread using the Runnable interface involves the following steps:
Write your class that implements the Runnable interface, and implement the run() method of the
Runnable interface in your class.
Instantiate your class, for example, inside a method of another class.
Make an object of the Thread class by passing your class instance in the argument of the Thread
constructor. This object is your thread object.
Start the thread by invoking the start() method on your Thread object.
183 | P a g e
360digrii
Java course material
The following program presents a simple but complete example of how to define, instantiate, and start a
thread using the Runnable interface:
Source Code:
public class RunnableDemo {
public static void main(String[] args) {
RunCounter rct = new RunCounter(); //line 3
Thread t = new Thread(rct); //line 4
t.start(); //line 5
System.out.println("The thread has been started");//line 6
}
}
class RunCounter implements Runnable { //line 9
public void run() { //line 10
for ( int i=1; i<=5; i++) { //line 11
System.out.println("Count: " + i);//line 12
}
}
}
RunCounter.java program generates the following output:
The thread has been started
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Explanation:
The Runnable interface has just one method, run(), which you implement in your class RunCounter (lines
9 to 15). You actually instantiate the class Thread and pass an instance of your class as an argument (lines
3 and 4) of the constructor, and then call the start() method on the instance of the class Thread. As a result,
the run() method that you implemented is executed.
The Life Cycle of a Thread
The following diagram illustrates the various states that a Java thread can be in at any point during its life.
It also decides which method calls will cause a transition to another state:
184 | P a g e
360digrii
Java course material
A thread’s life starts when the method start() is invoked on it. Subsequently, it goes through various states
before it finishes its task and is considered dead. Upon calling the start() method, the thread does not start
running immediately. The start() method puts it into the runnable state, also called the ready state. It stays
in the runnable state until the scheduler puts it into the running state. When the thread goes into the
running state, the method run() is called.
Even during the execution of the run() method, the thread may temporarily stop executing and may get
into one of the non-running states, and eventually come back to the running state.
The various states of a thread are listed here:
New: This is the state of a thread when it has been instantiated but not yet started.
Ready/runnable: A thread enters the runnable state for the first time when the start() method is invoked
on the thread instance. Later, the thread can come back to this state from one of the non-runnable states.
In the runnable state, the thread is ready to run. In this state it is also waiting to be selected by the
scheduler for running.
Running: This is the state in which the thread is executing.
Non-runnable states: A thread in the running state may go into one of the three non-runnable states
when it is still alive but not eligible to run. These three states are listed here:
Blocked: A thread goes into this state when it is waiting for a resource such as I/O or an object’s
lock. The availability of the resource will send it back to the runnable state.
185 | P a g e
360digrii
Java course material
Sleeping: This state is one of the timed waiting states because the thread stays in this state for a
specific time. A thread goes into this state when its code tells it to sleep for a specific period of time by
calling the sleep(…) method. Expiration of the sleep time sends it back to the runnable state.
Waiting: The thread goes into the waiting state when the object on which it is running invokes
the wait() method. A call to notify() or notifyAll() (by another thread) will bring it back to the runnable
state.
Dead: A thread is considered dead after the execution of its run() method is complete. A dead
thread can never be run as a separate thread again—that is, if you call its start() method, you will
receive a runtime exception. However, it is still an object, and you can still call its methods (other than
the start() method), but they will be executed in the caller’s thread.
Resolving Concurrency Control Problems
Since you cannot be sure whether you will be working with a cooperative or preemptive model, it is
important not to assume that preemption is available. CPU-intensive threads should yield control at
periodic intervals.
There are four different ways through which a thread can give up control and allow other threads to run.
It can block. Blocking occurs when a thread has to wait for an operation to complete. Most commonly
this is an I/O operation, particularly one involving a network connection. It is also possible for a call to
block while waiting for user input. Placing I/O and user input in separate, high priority threads is often
a good idea because it allows the computer to be used more efficiently. Other CPU intensive threads
can get a lot of work done while waiting for data to come in over the network or the user to type a
character or two.
It can call Thread.yield(). When a program calls Thread.yield(), it is signifying that the current
thread, the one which called Thread.yield(), is willing to step aside in favor of another thread. The
Virtual Machine looks to see if any other threads of the same priority are ready to run. If any of them
are, it pauses the currently executing thread and passes the control to the next thread in line. If no
other threads of the same or higher priority are ready to run, control returns to the thread that yielded.
Thus Thread.yeild() only signals a willingness to give up control. It does not guarantee that the thread
will actually stop. That depends completely on the presence of status of other types of threads.
It can go to sleep. A thread may definitely want to give up control for a period of time. Whether or not
there are any other threads of equal or higher priority ready to run, it can call the sleep(). The sleep()
methods put a thread to sleep for a certain amount of time during which even lower priority threads
may have an opportunity to run.
It can be suspended. When a thread calls suspend() (or more commonly when a different thread
invokes the thread's suspend() method,) it is a paused indefinitely until some other thread starts it
running again by invoking its resume() method.
public final void suspend();
public final void resume();
186 | P a g e
360digrii
Java course material
Transition Between Running and Runnable States
When the start() method is called, it puts the thread into the runnable state. You have seen how to use the
start() method in the code listings presented in the previous sections. The scheduler eventually transits
the thread from the runnable state into the running state. A call to the yield() method in the thread code
puts the thread back into the runnable state. The yield() method is a static method of the class Thread.
Therefore, it must be called as shown in the following example:
Thread.yield();
Yielding is important in prioritizing the threads, and especially in a time-consuming thread in order to
allow other threads to share the CPU time. Upon a call to the yield() method, a thread goes into the
runnable state. After that, one of the following happens:
If no other threads are waiting for the CPU, the scheduler puts the thread back into the running state
immediately.
If there are other threads waiting for the CPU, then this thread may have to wait for its turn before it
can be put back into the running state.
Although a yield() call is designed to let the other threads with the same priority take their
turn, it is not guaranteed that it will happen. A thread can hop between the runnable and several non-
runnable states.
Transition Between Runnable and Non-runnable States
There are three non-runnable states of a thread: sleeping, waiting, and blocked. These states may come in
the middle of the runnable and running state.
Sleeping State
A call to the sleep(...) method in the thread code puts a thread into the sleeping state. This method, like the
yield() method is a static method of the Thread class. The thread goes to the runnable state once the sleep
time expiries. Eventually the scheduler puts it back to the running state. During the method call, the sleep
time is passed in as an argument. Note that the time could be passed with a mili or nano seconds level of
precision. The method sleep (...) is overloaded accordingly. Following is the overloaded version of the
method that supports the precision of miliseconds:
public static void sleep(long milliseconds) throws InterruptedException { }
The method signature for the overloaded version to support the precision of nanoseconds is shown in the
following:
public static void sleep(long milliseconds, int nanoseconds) throws
InterruptedException { }
Blocked State
Sometimes a method has to wait for some event to happen before it can finish. This wait state is called
blocking. Following are the situations in which a thread may be blocked:
In Java, all input/output methods are automatically blocked in certain situations.
187 | P a g e
360digrii
Java course material
A thread is blocked if it fails to acquire the lock for a synchronized piece of code. You will learn about
locks later in this chapter, in the section “Synchronization and Locks in Concurrent Access.” When a
thread is running on an object, that object can put the thread into the waiting state by calling wait().
Waiting State
There might be situations when a piece of code may be shared by several threads executing concurrently.
Put a thread into the waiting to state by making a call to the wait() method in the shared code. This helps
you to synchronize some of these things. Sometimes a thread will need to be kept waiting until another
thread has completed. For instance, a thread reading some data must wait until the completion of another
thread that copies the data to the place from where it will read. To bring a thread out of its wait state, use a
call to the notify() method. Else use the notifyAll() method. Note that the methods wait(), notify(), and
notifyAll() are not implemented in the Thread class, but in the Object class. These can only be called in a
synchronized piece of code.
This is accomplished by using the following overloaded method of the thread class:
void join();
void join(long millisec);
void join (long millisec, int nanosec);
The versions of the join method that takes the arguments put the limit on the maximum time the thread
has to wait for this thread to complete.
To summarize, remember the following things about the three non-runnable states:
You call the sleep(…) method in your code to put the thread to sleep for a specified interval, after which
it will automatically get into the runnable state.
A thread automatically enters a blocked state when it cannot get something immediately that it needs
to precede, e.g. I/O or an object lock.
You can put a thread into the waiting state by calling the wait() method from a synchronized piece of
code.
Because the wait() method is called to maintain synchronization before you can understand the details
of the waiting state, you need to explore the concepts of synchronization and locks.
Deprecated methods
We should also mention three deprecated thread control methods: stop( ), suspend( ), and resume( ). The
stop( ) method complements start( ); it destroys the thread. start( ) and the deprecated stop( ) methods
can be called only once in the thread's lifecycle. By contrast, the deprecated suspend( ) and resume( )
methods were used to arbitrarily pause and then restart the execution of a thread.
Note that, even in the latest version of Java, the deprecated methods exist. However, you should avoid
using them in new case development. If you use both stop( ) and suspend( ), the execution of a thread will
be seized in an uncoordinated, complicated way. Programming becomes difficult through this since it is
generally difficult for an application to both anticipate and properly recover from being interrupted at an
arbitrary point during its execution. The Java runtime system must release all its internal locks used for
188 | P a g e
360digrii
Java course material
thread synchronization when a thread is seized using any of these methods. In the case of suspend( ), this
can lead to deadlock. In other cases also it might lead to unexpected behaviors.
There is a better way to affect the execution of a thread. Create some simple logic in your thread's code to
use monitor variables (flags), possibly in conjunction with the interrupt( ) method. This allows you to
awaken a sleeping thread.
Death of a Thread
A thread continues to execute until one of the following happens:
It explicitly returns from its target run( ) method.
It encounters an uncaught runtime exception.
The deprecated stop( ) method is called.
What happens if none of these things occur, and the run( ) method for a thread never terminates? The
answer is that the thread can live on. It lives on even after the part of the application that apparently
created it has finished. This means that you have to be aware of how your threads eventually terminate, or
how can an application end up leaving orphaned threads that unnecessarily consume resources.
The following Examples using various methods of Thread class demonstrate different aspects of Thread
Life cycle:
The Thread.isAlive() method returns a Boolean value indicating whether or not a Thread is alive. The
method returns true if this Thread is alive; false if otherwise. A Thread is alive if it has been started and
has not yet died.
Source Code:
public class IsAliveDemo{
public static void main(String[] args) throws InterruptedException
{
Thread t=Thread.currentThread();
System.out.println("Main thread is alive : " + t.isAlive());
ChildThread c=new ChildThread();
c.start();
System.out.println("Child thread is alive : " + c.isAlive());
System.out.println("Main thread is sleeping : ");
t.sleep(1000);
System.out.println("Child thread is alive : " + c.isAlive());
}
}
189 | P a g e
360digrii
Java course material
class ChildThread extends Thread
{
public void run()
{
System.out.println("I am child");
}
}
Understanding join()
In general, thread join is used for a parent to join with one of its child threads. Thread join has the
following activities, assuming that a parent thread P wants to join with one of its child threads C.
When P executes a thread join in order to join with C, which is still running, P is suspended until C
terminates. Once C terminates, P resumes.
When P executes a thread join and C has already terminated, P continues as if no such thread join has
ever executed (i.e., join has no effect).
public class JoinDemo{
public static void main(String[] args) throws InterruptedException
{
Thread t=Thread.currentThread();
ChildThread c1=new ChildThread();
ChildThread c2=new ChildThread();
c1.setName("Sunny");
c2.setName("Bunny");
c1.start();
System.out.println("Main thread");
c1.join(5000);
System.out.println("Back to Main from Sunny");
c2.start();
c2.join();
System.out.println("Back to Main from Bunny");
System.out.println("Last line of Main");
}
}
190 | P a g e
360digrii
Java course material
class ChildThread extends Thread
{
public void run()
{
try
{
for(int x=0;x<10;x++)
{
System.out.println("I am child and my name is " + getName());
sleep(1000);
}
}catch(Exception e)
{
System.out.println(e);
}
}
}
191 | P a g e
360digrii
Java course material
that first A gets a quantum time to run, then B gets a quantum, then again A gets another quantum, then B
and so on till one thread is completed. The entire power of the processor is then devoted to the remaining
thread, unless another thread of that priority becomes ready. After that, the thread C runs to completion,
assuming that no higher-priority threads arrive. D, E and F each execute for a quantum in round-robin
fashion till all the executions are completed. Again you have to keep in mind the occurrence of higher-
priority threads. Until all the threads run to completion, this process continues.
The following figure illustrates Thread-priority scheduling:
Note: Thread scheduling is platform dependent—an application that uses multithreading could behave
differently on separate Java implementations.
The following example demonstrates how to control the execution of thread by setting its priority:
Source:
class CounterThread extends Thread {
String nm;
public CounterThread(String nm) {
super();
this.nm = nm;
}
public void run() {
int count = 0;
192 | P a g e
360digrii
Java course material
while (true) {
try {
sleep(100);
} catch (InterruptedException e) {
}
if (count == 50)
count = 0;
System.out.println(nm+":" + count++);
}
}
}
public class PriorityDemo{
public static void main(String[] args) {
CounterThread t1 = new CounterThread("Thread1");
t1.setPriority(10);
CounterThread t2 = new CounterThread("Thread2");
t2.setPriority(1);
t2.start();
t1.start();
}
}
193 | P a g e
360digrii
Java course material
In the above program the “Thread1” starts first even if “Thread2” is started first, because the priority of
“Thread1” is higher than “Thread2”;
Synchronizing Threads
So far we have concentrated on cases where all the threads have run independent of each other. One
thread did not need to know what another thread was doing. Sometimes, however, threads need to share
data. In this case it is important to ensure that one thread is writing to a file while another thread is
reading the file, it is likely that the thread that is reading the file will get corrupt data.
The Java programming language supports the coding of programs that, though the use of concurrents, still
exhibit deterministic behavior. They provide mechanisms for synchronizing the concurrent activity of
threads. To synchronize threads, the Java Programming language uses monitors, which are high-level
mechanisms for allowing only one thread at a time to execute a region of code protected by the monitor.
The behavior of monitors is explained in terms of locks; there is a lock associated with each object.
For example, suppose you have a thread that writes data to a file while and at the same time, another
thread is reading data from that same file. When your threads need to share information you need to
synchronize the threads to get the desired results.
Infact, the entire Thread is not likely to be synchronized, but rather it is a method representing a segment
of code, which must be synchronized to all Threads.
194 | P a g e
360digrii
Java course material
}
}
Here variable is an Object which must not be modified by any other synchronized Thread.
public synchronized void anotherMethod()
{
}
As with Threads themselves, synchronization has it’s downfalls due to the potential for deadlock. Java has
implemented ways to avoid this, by allowing a synchronized method to call another, even if they both
require a lock on the same Object.
Source Code:
public class SecondThread{
public SecondThread()
{
FirstThread t1 = new FirstThread();
FirstThread t2= new FirstThread();
t1.start();
t2.start();
}
private class FirstThread extends Thread
{
public void run()
{
myMethod();
}
}
public synchronized void myMethod()
{
{
System.out.println("Entering Synchronized Code");
try
{
Thread.sleep(5000);
195 | P a g e
360digrii
Java course material
}catch(Exception e){ }
}
}
public static void main(String[] args)
{
new SecondThread();
}
}
Note that there is a 5 second wait between displaying the first line and the second. Yet if the myMethod() is
made non-synchronized, they both appear at once This is happening since there is no restriction on the
threads in parallel.
When objects are waiting to execute, due to a lock and synchronized code associated to it, the state of the
object can be either of the following-i.e. entering the monitor, or entering the wait queue. Both terms are
common becasu once the Thread is in waiting, it has become a monitor that is waiting for signals, and also
waiting for the current locked Thread to finish.
If the current Thread requires an operation by another Thread to complete before continuing, you can
reorder the wait queue, by calling wait(long timeout) on the running Thread.
The other option is to use a constant wait(), which waits until the notify() or notifyAll() method is called to
release the wait on a specific Object, it can be any Object - a Java supplied one, or your own.
Consider this Example having Synchronization problem
Source Code:
//demonstrates synchronization problems with threads
class Counter{
int i = 0;
public void count(){
while (i<30){
System.out.println(i);
i++;
}
}
}
public class CounterThread extends Thread {
Counter c;
196 | P a g e
360digrii
Java course material
public static void main(String args[]){
Counter d = new Counter();
CounterThread ct1 = new CounterThread (d);
CounterThread ct2 = new CounterThread(d);
ct1.start();
ct2.start();
}
public CounterThread(Counter d){
this.c = d;
}
public void run() {
c.count();
}
}
Since there is no guarantee when a particular thread will be interrupted by the scheduler you cannot
guarantee that one will not be interrupted in between the statements System.out.println(i) and i++. If this
happens it is possible for the same value to be printed out twice. Other problems can be associated with
the thread being interrupted between reading a variable's value and writing a new value back.
Consider this example solving Synchronization problem
Java solves this problem by implementing the monitor approach to concurrency. A monitor is a special
purpose object, which applies the principle of mutual exclusion to groups of procedures. Monitors in Java
enforce mutually exclusive access to synchronized methods. When a monitor automatically checks to see
whether any other thread is currently executing a synchronized method on that object. If not then the
current thread is allowed to enter the monitor, the current thread must wait until the other thread leaves
the monitor.
To demonstrate how monitors operate, we will rewrite the Counter example from above to take advantage
of monitors:
Source Code
// demonstrates synchronization with threads
class SyncCounter {
int i = 0;
public synchronized void count(){
while (i<30){
197 | P a g e
360digrii
Java course material
System.out.println(i);
i++;
}
}
public synchronized void count(){
while (i <30){
System.out.println(i);
i++;
}
}
}
198 | P a g e
360digrii
Java course material
appropriate methods in such classes does not arise. How can the access to an object of this class be
synchronized? The answer is to put the calls to methods that you want to synchronize inside a
synchronized block. The general form of the synchronized method is as follows:
synchronized(object)
{
// statements to be synchronized
}
Here, object is a reference to the object being synchronized, i.e., the object whose methods you need to
synchronize. If you want to synchronize only a single statement, then the curly braces are not required. A
synchronized block ensures that a call to a method, that is a member of object, occurs only after the
current thread has successfully entered the object's monitor.
When you use the synchronized modifier to specify that a method is synchronized, you are locking on the
particular object whose method is invoked. You can synchronize at a lower level than a method.
For example:
public void count(){
synchronized(this){
int i = this.i;
}
while (i ! = 100) {
System.out.println(i);
i++;
}
synchronized (this){
this.i = i;
}
}
The following example explains you about the Java thread synchronization through a simple
producer/consumer example. For example, imagine a Java application where one thread (the producer)
writes data to a file while a second thread (the consumer) reads data from the same file. Or, as you type
characters on the keyboard, the producer thread places key events in an event queue and the consumer
thread reads the events from the same queue. Both of these examples use concurrent threads that share a
common resource: the first shares a file, the second shares an event queue. Because the threads share a
common resource, they must be synchronized in some way.
199 | P a g e
360digrii
Java course material
A very simple example of wait() and notify() is described in the following three classes.
The first class is named PingPong and consists of a single synchronized method and a state variable. The
method is hit() and the only parameter it takes is the name of the player who will go next.
The algorithm is essentially this:
If it is my turn,
note whose turn it is next,
then PING,
and then notify anyone waiting.
otherwise,
wait to be notified.
Source Code:
1 public class PingPong {
2 // state variable identifying whose turn it is.
3 private String whoseTurn = null;
4
5 public synchronized boolean hit(String opponent) {
6
7 String x = Thread.currentThread().getName();
8
9 if (whoseTurn == null) {
10 whoseTurn = x;
11 return true;
12 }
13
14 if (x.compareTo(whoseTurn) == 0) {
15 System.out.println("PING! ("+x+")");
16 whoseTurn = opponent;
17 notifyAll();
18 } else {
19 try {
20 long t1 = System.currentTimeMillis();
21 wait(2500);
200 | P a g e
360digrii
Java course material
22 if ((System.currentTimeMillis() - t1) > 2500) {
23 System.out.println("****** TIMEOUT! "+x+
24 " is waiting for "+whoseTurn+" to play.");
25 }
26 } catch (InterruptedException e) { }
27 }
28 return true; // keep playing.
29 }
30
}
In line 3 we declare our state variable, whoseTurn. This is declared private since the users of the class do
not need to know it. Line 5 declares our method and it must have the synchronized keyword or the call to
wait() will fail.
In line 7 we get our own name from the thread object. As you will see later, we set this after the thread is
created. This helps in debugging since our thread is named something useful and is a convenient way to
identify the players.
Lines 9 through 12 solve the problem of whose turn it is before anyone has gone. The policy implemented
is that the first thread to invoke this method will get the honor of going first.
Lines 14 through 17 execute when it is the current thread's turn to go. When executed, the thread updates
the state variable with the next thread's turn. This is done before the notify, since the notify may cause
another thread to start running immediately before it knows its turn to run. Then notifyAll() is called to
notify all threads that are waiting on this object, the one that they can run. If you are using only two
threads, simply call notify() since that call will awaken exactly one thread from the set waiting to run. With
two threads, only one thread can be waiting, so the correct thread will wake up. If you extend this to three
or more threads, however, the notify call may not wake up the correct thread and the system will stop
until that thread's wait times out.
Lines 19 through 26 execute when it is not the current thread's turn to go. Line 21 simply calls wait() and
goes to sleep. However, you will notice that in line 20 the code notes the current time. It does this because
when execution continues after the wait call returns. The reason for continuing could be either that the
wait timed out or that our thread was awakened with a call to notify(). The only way to tell the difference
is to measure how long the thread was asleep.
This timeout test is performed in line 22. If a timeout occurs, an informative message is printed to the
console. In practice this will happen only when the time spent in lines 14 through 17 is greater than 2.5
seconds.
Line 26 is where we catch the InterruptedException. This would be thrown if the thread in the wait() call
stops prematurely.
201 | P a g e
360digrii
Java course material
Really, that is all there is to in this part of the code. However, add some additional code (shown below)
between lines 8 and 9 to allow a third thread to cause the threads using this class to exit.
8.01 if (whoseTurn.compareTo("DONE") == 0)
8.02 return false;
8.03
8.04 if (opponent.compareTo("DONE") == 0) {
8.05 whoseTurn = opponent;
8.06 notifyAll();
8.07 return false;
}
As you can see, this is done by setting the special opponent DONE in the call to hit(). When the opponent is
done, line 8.02 makes sure the code returns the boolean false. Once we have the class of type PingPong,
any thread with a reference to an instance of class PingPong can synchronize itself with other threads
holding that same reference. To illustrate this, consider the following Player class designed for use in the
instantiation of a couple of threads:
1 public class Player implements Runnable {
2 PingPong myTable; // Table where they play
3 String myOpponent;
4
5 public Player(String opponent, PingPong table) {
6 myTable = table;
7 myOpponent = opponent;
8 }
9
10 public void run() {
11 while (myTable.hit(myOpponent));
12
13 }
14 }
As you can see, this code is even simpler. All we really need is a class that implements the Runnable
interface. The Thread class provides a constructor that takes a reference to an object implementing
Runnable.
202 | P a g e
360digrii
Java course material
The two instance variables in this class are the reference holding the PingPong object and the name of this
player's opponent. This latter field is used in the hit() method to tell the object which player should go
next.
There is a single constructor taking a PingPong object and the name of an opponent. To satisfy the
Runnable interface, there is the method run in lines 10 through to 13.
The run method runs an infinite loop, calling hit() until it returns false. This method returns true until
some thread calls it with the opponent name DONE.
To complete our example, we have an application class that will create a couple of threads using the Player
class and pit them against each other. This is shown below in the Game class:
1 public class Game {
2
3 public static void main(String args[]) {
4 PingPong table = new PingPong();
5 Thread alice = new Thread(new Player("bob", table));
6 Thread bob = new Thread(new Player("alice", table));
7
8 alice.setName("alice");
9 bob.setName("bob");
10 alice.start(); // alice starts playing
11 bob.start(); // bob starts playing
12 try {
13 // Wait 5 seconds
14 Thread.currentThread().sleep(5000);
15 } catch (InterruptedException e) { }
16
17 table.hit("DONE"); // cause the players to quit their
//threads.
18 try {
19 Thread.currentThread().sleep(100);
20 } catch (InterruptedException e) { }
21 }
22 }
203 | P a g e
360digrii
Java course material
Because we want to execute this class from the command line, it must include a public static method
named main that takes a single argument which is an array of strings. This is the method signature that the
java command keys of when instantiating a class from the command line.
Line 4 is where the code instantiates a copy of our PingPong class and stores the reference in the local
variable table. Line 5 and line 6 are compound object creations, first creating new Player objects and then
using those objects in the creation of new Thread objects. At the time when it is created, the name of the
opponent is specified. So Alice's opponent is Bob and Bob's opponent is Alice. These new threads are
named using the setName method in lines 8 and 9, and then they are started in lines 10 and 11.
After line 11 is executed, there are three user threads running, one named alice, one named bob, and the
main thread. On the system console you will start seeing messages of the form:
PING! (alice)
PING! (bob)
PING! (alice)
...
and so on. The threads alternate which one runs by the state in the PingPong object. This object forces
them to run one after another, however it also ensures that they run as rapidly after one another as
possible since as soon as one is finished, it calls notifyAll() and the other thread begins to run.
Finally, in lines 12 through to 15, you will see that the main thread goes to sleep for five seconds or so, and
when it wakes up, it calls hit() with the magic bullet name DONE. This will cause the alice and bob threads
to exit. The short sleep in lines 18 through 20 cover this case and allow our program to exit normally on all
systems.
So we have managed to get two threads to share the processor equally by synchronizing the use of a
common object instance.
Fairness, Starvation, and Deadlock
You can call a system fair if each thread gets enough access to limited resources to make reasonable
progress. You need to take precaution in order to ensure fairness if you write a program in which several
concurrent threads are competing for fairness. Deadlocks and starvations are not allowed in a fair system.
When does starvation take place? When one or more threads in the program are blocked from gaining
access to a resource and hence, cannot progress. The ultimate form a starvation is a deadlock. Deadlock
happens when two or more threads in the program are on a condition, which cannot be satisfied.
Suspend() and resume() and stop()
Thread suspend and resume are two more thread management features. When a thread executes a thread
suspend to suspend the execution of itself or another thread, the indicated thread will be suspended until
the execution of a thread resume that releases the indicated thread. For example, suppose we have three
threads A, B and C running concurrently. Then, thread A execute a thread suspend to suspend the
execution of thread B. After this, we have only two threads A and C running concurrently. Note that even
though both A and C are waiting for the completion of their own I/O activities and no thread is running,
the suspended thread B cannot run. To run thread B again, one of the other threads must execute a
204 | P a g e
360digrii
Java course material
corresponding thread resume. For example, thread C may execute a thread resume to resume thread B's
execution. After this, all three threads are running concurrently.
Note that Sun has removed Thread.stop(), Thread.suspend(), and Thread.resume(). These methods are
dangerous to use and you do not require them as it is inherently unsafe. Invoking stop() methods on a
thread causes it to unlock all the monitors that it had locked. (The monitors are unlocked as the
ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these
monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state.
Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can
result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other
unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program
may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even
hours or days in the future. In a similar fashion suspend() and resume() methods may lead to deadlock
situations.
Suspending, Resuming, and Stopping Threads - Java 1.1 and Earlier Versions
205 | P a g e
360digrii
Java course material
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
}
}
class SuspendResume {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
try {
Thread.sleep(1000);
ob1.t.suspend();
System.out.println("Suspending thread One");
Thread.sleep(1000);
ob1.t.resume();
System.out.println("Resuming thread One");
ob2.t.suspend();
System.out.println("Suspending thread Two");
Thread.sleep(1000);
ob2.t.resume();
System.out.println("Resuming thread Two");
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
206 | P a g e
360digrii
Java course material
ob2.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");}}
Output:
207 | P a g e
360digrii
Java course material
One: 9
One: 8
One: 7
One: 6
Resuming thread Two
Waiting for threads to finish.
Two: 5
One: 5
Two: 4
One: 4
Two: 3
One: 3
Two: 2
One: 2
Two: 1
One: 1
Two exiting.
One exiting.
Main thread exiting.
Using Java 2
209 | P a g e
360digrii
Java course material
}
class SuspendResume {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
try {
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspending thread One");
Thread.sleep(1000);
ob1.myresume();
System.out.println("Resuming thread One");
ob2.mysuspend();
System.out.println("Suspending thread Two");
Thread.sleep(1000);
ob2.myresume();
System.out.println("Resuming thread Two");
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
210 | P a g e
360digrii
Java course material
System.out.println("Main thread exiting.");
}
}
System.out.println("Resuming thread One");
ob2.mysuspend();
System.out.println("Suspending thread Two");
Thread.sleep(1000);
ob2.myresume();
System.out.println("Resuming thread Two");
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
Thread Deadlock
212 | P a g e
360digrii
Java course material
Chapter 11 – IO Package
I/O Basics
Any programmer should know the basic idea of how to read from files and write to files while dealing with
any new language. This is because he / she will always have the need of saving and loading data in most of
the software developed. Hence, Java I/O has come up with simple facilities that include standardized API
for reading and writing character and byte data from various data sources. This chapter will reflect the
inside out of java.io package, scrutinizing I/O classes, methods, and various techniques for handling I/O in
your Java code. But the java.io package, as the term suggests deals with input and output operations like
reading a plain comma, a XML data file and delimited text file or something very different like a network
stream.
Streams
Java I/O is based on the concept of streams. A stream is defined as a flowing sequence of characters. Most
of the programs work with external data stored either in local files or they come from other computers on
the network. Java’s concept allows it to work with the streams of data. When the physical data storage is
mapped to a logical stream of data, a Java program reads data serially from this stream. The term serially
here means byte after byte and character after character. Some of the types of streams are byte streams
(InputStream, OutputStream) and character streams (Reader and Writer). There are different types of
data, and hence different types of streams. You can see the flow of data in Fig. 1.
Open a stream pointing a specific data source: a file, a socket, URL, etc.
Then read or write data from/to this stream.
Close the stream.
213 | P a g e
360digrii
Java course material
There are lots of sources to provide input to Java program and output can reach a lot of places where it is
destined. Thus the main work of stream classes between the sources and destinations remains abstracted.
The image Fig.1 shows how we can read data from file with an InputStream and how we can write data to
a file with an OutputStream.
Input stream functions like a like a siphon that sucks up water and output stream functions like a hose that
discharges water. So, you can imagine a siphon-hose relationship where a siphon and a hose are connected
to flow water from one place to another. A Siphon gets limited water source if it draws water from a small
or finite vessel whereas if done from a river it gets unlimited water. Similarly, input stream may read from
a file that is a finite source and from user prompt that is an unlimited source.
When sending a stream of data it is said that we are writing a stream. When receiving a stream of data we
are said to be reading a stream. If an error occurs when reading or writing a stream, an exception (usually
IOException) is thrown. This kind of exception can be handled by surrounding your stream statements
with a try - catch block.
The first source of input most programmer’s encounter is System.in. You can find this with stdin in C. The
java.lang.System class give console output through the static output field, that is, System.out. This system
is similar to stdout in C language that may follow the similar way. Again, stderr runs as System.err. This is
meant for printing error messages and debugging inside the catch clauses. Standard error stream deals
with error related text messages that are revealed to the command-line application user. The standard
output is different which often may be redirected to a file or another application and is not seen by the
user.
The following example accepts a character from the user and prints it back in the prompt.
import java.io.*;
{
System.out.println((char)System.in.read());
}}
214 | P a g e
360digrii
Java course material
In the above example you can see that the data read by System.in.read is casted into char, because read()
method returns a byte. The input and output stream read and write bytes respectively. This means readers
can read and writers can write characters. Hence, to understand how i/o operations are carried on with
stream of bytes, you should know how Java deals with data types like bytes, integers, characters, and other
primitive data types. You will also learn when and why one of these data types is converted into another.
ASCII
ASCII stands for American Standard Code for Information Interchange. When computer understands
numbers, ASCII code serves the purpose, as it is the numerical representation of a character. It is a seven-
bit character set consisting of 27 or 128 different characters whose numeric values range from 0 to 127.
These characters are sufficient to handle American English and European languages to a great extent. If
you want to read a byte value between 0 and 127 from a stream, then convert it to a char, which is the
corresponding ASCII character.
ISO Latin-1
ISO 8859-1.was referred as ISO/IEC 8859-1. It is first part of ISO/IEC 8859, which is a standard character
encoding of the Latin alphabet. It is sometimes called as Latin-1. This character encoding is used in places
like America, Western Europe, Oceania, and much of Africa. It is also commonly used in most standard
romanizations of East-Asian languages. Every character is encoded as a single eight-bit code value. These
code values can be used in almost any data interchange system to communicate in the following European
languages. To communicate in the following European languages, these code values can be used in any
data interchange system.
Unicode
Unicode provides a unique number for every character, irrespective of platform, program and language.
The Unicode Standard has been adopted by industry leaders such as Apple, IBM, HP, Microsoft, Oracle,
JustSystem, Sun, SAP and Sybase etc.Each Unicode character is defined by 16 bits.
The first 256 characters of Unicode i.e., the characters whose high-order byte is zero are identical to the
characters of the ISO Latin-1 character set. Thus, 65 is ASCII A and Unicode A; 66 is ASCII B and Unicode B
and so on. Streams generally read a byte at a time, but each Unicode character occupies two bytes. Thus, to
read a Unicode character, you multiply the first byte read by 256, add it to the second byte read, and cast
the result to a char. For example:
int b1 = System.in.read();
int b2 = System.in.read();
215 | P a g e
360digrii
Java course material
char c = (char) (b1*256 + b2);
UTF-8
Unicode is a relatively inefficient encoding when most of your text consists of ASCII characters. Every
character requires the same number of bytes (two) even though some characters are used much more
frequently than others. A more efficient encoding would use fewer bits for the more common characters.
This is what UTF-8 does. In UTF-8 the ASCII alphabet is encoded using a single byte, just as in ASCII.
Character Streams
Streams, handling only character data are actually introduced by java.io Reader and Writer character
stream classes. While using these classes any programmer can think it only in terms of characters and
string data that allows the underlying implementation to handle the conversion of bytes to a specific
character encoding. The character stream’s main advantage is that they make it easy to write programs
that do not depend upon a specific character encoding. Hence, they are easy to internationalize. Unicode is
an international standard character encoding that has the capability to represent most of the world's
written languages. Java stores strings in this Unicode. The second main advantage of character streams is
their efficiency. They are much more efficient than byte streams. Many of Java's original byte streams
implementations are oriented around byte-at-a-time read and write operations. On the other hand, the
character-stream classes are inclined towards buffer-at-a-time read and write operations.
Streams
InputStream Class
The java.io.InputStream class fall under abstract superclass for all input streams. When there is need to
read bytes of data from a stream, it declares three basic methods. Moreover, it has methods to close and
flush streams, to check the number of bytes of data available to be read, to skip over input, to mark a
position in a stream and reset back to that position and also to determine whether marking and resetting
back are supported. The following list provides the details of some important methods in the InputStream
class.
217 | P a g e
360digrii
Java course material
public int read(byte[] data, int offset, int length) throws IOException
An array of bytes
A file
A pipe
data[i] = System.in.read();
218 | P a g e
360digrii
Java course material
The skip() method argument means the number of bytes to skip. As a return value, it gives the number of
bytes actually skipped, which may be less than bytesToSkip. Thus it returns -1 if the end of stream is
encountered. The argument as well as return value are long which means it allows skip() to handle
extremely long input streams.
InputStream marking
Some, but not all, InputStreams support marking. Marking allows you to go back to a marked place in the
stream like a bookmark for future reference. Remember, not all InputStreams support marking. To test if
the stream supports the mark() and reset() methods, use the boolean markSupported() method. The
mark() method, which takes an integer read_limit, marks the current position in the input stream so that
reset() can return to that position as long as no more than the specified number of bytes have been read
between the mark() and reset().
Output Streams
OutputStream Class
There are three basic methods declared by java.io.OutputStream class to write bytes of data onto a stream.
It also has methods for closing and flushing streams. OutputStream is an abstract class. Their subclass
provides the abstract write(int b) method implementations. It may be possible that four nonabstract
methods are overridden. The following example of the FileOutputStream class overrides all five methods
with original methods knowing how to write bytes into files on the host platform.
public void write(byte[] data, int offset, int length) throws IOException
219 | P a g e
360digrii
Java course material
An array of bytes
A file
A pipe
Example:
import java.io.*;
System.out.write(i);
if (i % 8 == 7) System.out.write('\n');
else System.out.write('\t');
System.out.write('\n');
}
The write() Method to work with byte array
Writing larger chunks of data can be faster than writing them byte by byte. There are two overloaded
variants of the write() method doing this operation and they are:
public void write(byte[] data, int offset, int length) throws IOException
220 | P a g e
360digrii
Java course material
The entire byte array data is written by the first variant. Only the sub-array of data that starts at offset and
continues for length bytes is written by second array.
The following example constructs a byte array filled with an ASCII chart, then sends it onto the console in
one call to write().
Example:
import java.io.*;
public class AsciiChart
int index = 0;
b[index++] = (byte) i;
try {
System.out.write(b);
221 | P a g e
360digrii
Java course material
The flush() and close() Method
There are many output streams buffer that writes to improve performance. It does this by the
accumulated bytes in a memory buffer with size ranging from several bytes to several thousands bytes
rather than sending each byte the way it is written to its destination. As soon as the buffer fills up, all the
data is sent at the same time. Whether the buffer is full or not, the flush() method prepares the data to be
written. If you use a stream for a short time, then there is no need to flush it explicitly but can be done once
the stream is closed.This is possible when the program exits or when you explicitly invoke the close()
method. System.out, System.err, and some (but not all) other print streams automatically flush after each
call to println() and after each time a new line character ('\n') appears in the string is being written. The
auto-flushing can be enabled in the PrintStream constructor.
Constructors
Test methods
Action methods
List methods
Constructors
There are several constructors in the File class ther allow Java code to specify the initial values of an
object. Constructors for the File class are:
File(String filename)
222 | P a g e
360digrii
Java course material
These methods are all of the boolean type and that is why they return a true or false.
Action methods
Public instance methods in the File class perform actions on the specified file. Let's take a look at them:
List methods
The names of all the entries that are not rejected by an optional FilenameFilter are returned in a directory
by the list() method. The list() method returns null if the File is a normal file, or returns the names in the
directory. The list() method can take a FilenameFilter filter and return names in a directory satisfying the
filter. More on FilenameFilter is discussed in the next section of the chapter. The listFiles() method works
the same way as list() except that it returns as File [] (File array) format where as list() returns in String
[](String array) format.
import java.io.*;
if(f.exists())
System.out.println("SqlStar.txt exists");
}else
223 | P a g e
360digrii
Java course material
{
f.createNewFile();
if(f.length()==0)
f.delete();
}}}
The following example demonstrates the use of listFiles() method along with recursion principle to extract
the list of files and directory names under the C:/WINDOWS directory.
import java.io.*;
File [] arr=ff.listFiles();
String name;
for(int x=0;x<arr.length;x++)
File f1=arr[x];
name=f1.getName();
if(f1.isFile())
System.out.println(name);
filecount++;
else
foldercount++;
}}}
225 | P a g e
360digrii
Java course material
The FilenameFilter interface helps in filtering filenames. You simply create a class that implements the
FilenameFilter. Java language does not implement any standard FilenameFilter classes. In the File class,
objects that implement this interface, are used by the FileDialog class and the list().The implemented
accept() method determines if the filename in a directory should be included in a file list. You can pass
with the directory and a file name. If the name is included in the list, the method returns true.
import java.io.*;
import java.util.*;
if (a_directory.isDirectory())
}}
if (a_directory.isDirectory())
}}}}
return true;
else
return false;
}}}
227 | P a g e
360digrii
Java course material
RandomAccessFile(File file, String mode)
The mode string should be either “r” or “rw”. You can take “r” to open the file, only for reading and take
rw” to open the file for both reading and writing. In addition to that, you can see that seek( ) is used to
move about in the file and change one of the values. Methods like getFilePointer( ) to find out where you
are in the file, mark( ) to mark a position (whose value is held in a single internal variable) and reset( ) to
reset that position, and length( ) to determine the maximum size of the file provides more flexibility in file
handling.
The following example prints its own source code on the prompt:
Example:
import java.io.*;
String str="";
while(str!=null)
try
System.out.println(str=f.readLine());
catch(Exception e)
System.exit(0);
228 | P a g e
360digrii
Java course material
}}}}
File Streams
Most of the examples in this chapter have used the streams System.in and System.out. These are
convenient for examples, but in real life, you will more commonly attach streams to data sources like files
and network connections. You will use the java.io.FileInputStream and java.io.FileOutputStream classes,
which are concrete subclasses of InputStream and OutputStream, to read and write files.
Reading Files:
FileInputStream is a pure subclass of InputStream that provides an input stream connected to a particular
file.
import java.io.*;
try {
int n;
System.out.print(s);
} // End while
} // End try
catch (IOException e)
System.err.println(e);
System.out.println();
}}
Writing Files :
The FileOutputStream class is a concrete subclass of OutputStream that provides output streams
connected to files.
This class has all the usual methods of output streams, such as write(), flush(), and close().They are used
exactly as they are for any other output stream. There are three main FileOutputStream() constructors:
The following program creates a file called “Sample.txt” and writes a string into the file.
import java.io.*;
try
230 | P a g e
360digrii
Java course material
{
byte []b=str.getBytes();
for(int n=0;n<b.length;n++)
fos.write(b[n]);
catch (IOException e)
System.err.println(e);
System.out.println();
Character Streams
Reader class
You know that Readers are character based input streams that can read Unicode characters.
The read() method reads a single character and also returns a character that can be read as an integer in
the range from 0 to 65535 or it can be -1 if the end of the stream is reached.
The abstract read() method reads characters into a portion of an array that starts at the offset up to
length number of characters. It returns the number of characters read or –1 only if the end of the
stream is reached.
231 | P a g e
360digrii
Java course material
Character input streams
Java.io package has different character input streams. They are:
If you look at the different character input streams in the java.io package, they are
Strings
Character arrays
Pipes
As InputStreamReader is a character input stream, it uses a byte input stream as its data source,
converting it into Unicode characters. LineNumberReader is a character input stream and a subclass of
BufferedReader that tracks the number of lines of text that have been read from it. PushbackReader, is a
character input stream and a subclass of FilterReader, that uses another input stream as its input source. It
also adds the ability to push characters back onto the stream.
The following example used the InputStreamReader to read its source file.
import java.io.*;
try{
int ch=0;
buf.append((char)ch);
System.out.print(buf.toString());
}
232 | P a g e
360digrii
Java course material
Writer class:
The writer class consists of character based output streams called writers that can write character bytes
and turn Unicode into bytes. The methods that includes these methods are as follows:
The void write() method – They take a character and writes single character in 16 low-order bits.
The abstract void write() method – They take a character array and writes a portion of an array of
characters
Character output streams
In the java.io package, you will find many character output streams. There you can view branches of this
inheritance tree. It has not only Readers, but also other important branches available.
Strings
CharArray
Pipes
The destination for the data in OutputStreamWriter is used with the help of byte output stream. Buffering
is employed by BufferedWriter to a character output stream. Therefore, it enhances the efficiency of the
output by combining many small write requests into a single large request. An abstract class FilterWriter
functions as a superclass for character output streams. The stream helps in filtering the data written to
them before writing it to some other character output stream.
PrintWriter is a character output stream having print() and println()methods. These methods give textual
representations of primitive values and objects as output.
Byte arrays
Pipes
Sequences
Char arrays
Byte arrays
The creation of ByteArrayInputStream object is passed as an array. The bytes from this array can be read
as an InputStream. ByteArrayOutputStream writes to a byte array. If bytes are written to the output
stream, they are added to an internal array. It is obvious that you will think of the way of getting to the
byte array. At any point in time The toByteArray() method returns you the byte array. The byte array in
233 | P a g e
360digrii
Java course material
the form of a String is returned by the available toString() method.Therefore, the byte array can be either a
source or a sink as in Fig. 3.
Sequences
SequenceInputStream aggregates input streams and this stream reads each input stream till its
completion. SequenceInputStream can be used to read two or three streams considering them as one
stream. There are various sources to concatenate streams. You can take two or more files. Enumeration,
which represents a set of input streams, can help in constructing a SequenceInputStream. You can also
specify two streams for the same work. A program in UNIX like the "cat" can be used to do something like
this. SequenceInputStream starts reading from the first underlying input stream that is given to it. After
the exhaustion of the first one, it opens the next input stream and reads the same. When the same gets
exhausted, it reads the next, and so on. But in between, the users are unaware of when the input is
transferred from one stream to the next stream. Another byte is simply read. After the reading of all the
input streams, the entire input stream receives an EOF.
Char arrays
To start with Readers and Writers classes, we have read and write methods to input and output a
character respectively. If you recollect the function of ByteArrayOutputStream, it is easy to remember
CharArrayWriter that can write characters to a char array in the same way. When a character is written to
a CharArrayWriter object, it is added to an array of characters that automatically increments its size. Any
time, you can get the character array filled up by you. The method called toCharArray() returns an array of
characters. The character array is used as a source by a CharArrayReader. With a CharArrayWriter object,
234 | P a g e
360digrii
Java course material
there is also an array that has been created. Take an alternate constructor, where you can specify the
array, the position of starting in the array (an offset) and the number of bytes to read (a length) before you
return an EOF character. See Fig.4:
InputStreamReader
InputStreamReader, which is discussed earlier, reads bytes from an InputStream and converts them to
characters. An InputStreamReader uses the default character encoding for the bytes, which is usually
ASCII. If the bytes that are being read are ASCII bytes, only a single byte at a time is used to form a
character. If the bytes are not ASCII, such as Chinese or another language, you want its conversion to
Unicode as well. Specific encoding of the byte stream is necessary, and the InputStreamReader converts it
to Unicode. With an alternate constructor, you can specify the encoding of the bytes on the InputStream.
OutputStreamReader
OutputStreamWriter is similar to InputStreamReader. The output characters, which are in Unicode, are
converted to the underlying format of the machine using an OutputStreamWriter. The converted
characters are written to an OutputStream. The underlying default format is typically ASCII. However, you
can state a specific encoding scheme with an alternate constructor.
Buffering
The InputStream class also defines methods for reading several bytes of data in one step into an array of
bytes. However, InputStream provides no convenient methods for reading other types of data, such as int
or double, from a stream. This is not a problem because you'll never use an object of type InputStream
itself. Instead, you'll use subclasses of InputStream that add more convenient input methods to
InputStream's rather primitive capabilities. Similarly, the OutputStream class defines a primitive output
method for writing one byte of data to an output stream, the method
The Reader and Writer classes provide very similar low-level read and write operations. But in these
character-oriented classes, the I/O operations read and write char values rather than bytes. In practice,
you will use sub-classes of Reader and Writer, as discussed below.
235 | P a g e
360digrii
Java course material
Reading and writing to a file, getting data one byte at a time is slow and painstaking. One way to speed up
the process is to put a wrapper around the file and put a buffer on it .A buffer can increase efficiency by
reducing the number of physical read or write operations that correspond to read( ) or write( ) method
calls. You create a buffered stream with an appropriate input or output stream and a buffer size.
A program can convert an unbuffered stream into a buffered stream using the wrapping, where the
unbuffered stream object is passed to the constructor for a buffered stream class, for example,
inputStream =
outputStream =
236 | P a g e
360digrii
Java course material
BufferedInputStream
Our BufferedInputStream is going to put a buffer onto an InputStream that is specified in the constructor.
The actual data source is what you pass it as an InputStream. The BufferedInputStream reads large chunks
of data from the InputStream. Then you read individual bytes or small chunks of bytes from the
BufferedInputStream. The default buffer size is 512 bytes, but there's a constructor that allows you to
specify the buffer size if you want something different.
To improve your efficiency, you read from the object of BufferedInputStream instead of reading directly
from the underlying InputStream. And you will not have to go back to the operating system to read
individual bytes. See Fig. 6:
Fig. 6: Buffering
Here is an example of using the BufferedInputStream, note how similar it is with the previous example
when InputStreamReader is replaced by BufferedInputStream:
import java.io.*;
try{
while((ch=bin.read())> -1){
237 | P a g e
360digrii
Java course material
buf.append((char)ch);
System.out.print(buf.toString());
}catch(IOException e){System.out.println(e.getMessage());};
}
BufferedOutputStream
BufferedOutputStream extends FilterOutputStream. When you apply it to an OutputStream, you have a
buffered output stream. Instead of going to the operating system for every byte you write, you have the
intermediary that provides a buffer and you write to that. When that buffer is full, it is written all at once
to the operating system. And it is written automatically if the buffer gets full, if the stream is full, or if the
flush() method is used. The flush() method forces any output buffered by the stream to be written to its
destination. So for creating a BufferedOutputStream, you have to specify:
Fig. 7: BufferedOutputStream
BufferedReader and BufferedWriter
A BufferedReader and a BufferedWriter act like BufferedOutputStream and BufferedInputStream, except
they deal with reading and writing characters. For a BufferedReader, you specify an underlying Reader
and optionally a buffer size. For a BufferedWriter, you specify an underlying Writer and optionally a buffer
size. BufferedReader has one additional method, called readLine(), which allows us to simply read an
entire line of characters from the underlying Reader.
238 | P a g e
360digrii
Java course material
Serialization
Serialization 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. There are a couple of other features of a
serializable class. First, it has to have a zero parameter constructor. When you read the object, it needs to
be able to construct and allocate memory for an object, and it is going to fill in that memory from what it
has read from the serial stream. The static fields, or class attributes, are not saved because they are not
part of an object. If you do not want a data attribute to be serialized, you can make it transient.
import java.io.*;
int roll;
String name;
An ObjectOutputStream writes primitive data types and graphs of Java objects to an OutputStream. Only
objects that support the java.io.Serializable interface can be written to streams. 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 graphs of objects can be restored to the same shape as when the original was written.
For example to write an object of the student class into a file that can be read by the example in
ObjectInputStream:
import java.io.*;
239 | P a g e
360digrii
Java course material
{
st.roll=12;
st.name="Amitav";
st.phone="23467549";
f.createNewFile();
oos.writeObject(st);
}
ObjectInputStream:
An ObjectInputStream deserializes primitive data and objects previously written using an
ObjectOutputStream. 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.
Sample code for reading the object stored in the previous example:
import java.io.*;
Student st=(Student)ob;
Externalizable
Externalizable interface 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. These methods supercede customized implementations of writeObject and
readObject methods.
StreamTokenizer
StreamTokenizer breaks the input stream into tokens using whitespace as a delimiter. By default, Unicode
characters \u0000 through \u0020 are considered whitespace. This encompasses things like space, tab,
newline, etc. If you want to change this list, you need to invoke the method whitespaceChars(int low, int
high); all characters having Unicode values between low and high will be considered whitespace, in
addition to the default set.
You can call whitespaceChars() any number of times - each invocation will add to the list of whitespace
characters. The only way to clear out the list is to set those characters to be something other than
whitespace - you might use ordinaryChar(int ch), ordinaryChars(int low, int high), wordChars(int low, int
high), or resetSyntax() to do this.
The following program is a very simple example of using StreamTokenizer to parse a text file into words,
number, and characters. The file to be parsed is taken from the first argument; the second argument is a
string containing all the characters to use as delimiters.
import java.io.*;
IOException {
241 | P a g e
360digrii
Java course material
FileReader file = new FileReader(args[0]);
char[] c = args[1].toCharArray();
st.whitespaceChars(c[i], c[i]);
int tokval;
switch (tokval) {
case StreamTokenizer.TT_WORD:
break;
case StreamTokenizer.TT_NUMBER:
break;
default:
break;
} } }
}
For example, if the input is delimited by commas and colons, you would run this using the command line:
java TokenizeIt ",:"
242 | P a g e
360digrii
Java course material
Chapter 12 – Collections Framework
Introduction
Data encapsulation is one of the important features of OOPs. But, this doesn’t mean the data organization
inside classes is not important. The way you structure your data depends on your requirement and the
problem you need to solve. Does your class need to search for items quickly? Does it require sorted
elements and rapid inserts and deletions of elements? Does it need an array-like structure with random-
access ability that can grow at run time? The way data is structured inside classes is very important to
improve the performance.
This chapter tells you how Java helps you structure your data needed for programming.
Prior to JDK1.2, only a few classes were provided for data structures by the standard library. Vector, Stack,
HashTable, BitSet and Enumeration interface are some of them. Enumeration interface provided an
abstract mechanism to access elements in an arbitrary container. It takes time and skill to come up with a
comprehensive collection class library.
With the advent of JDK 1.2 the Standard Library supplied a full-fledged set of data structures. The
designers had faced a number of conflicting design decisions. Hence they wanted the library to be small
and easy to learn. They wanted the benefit of “generic algorithms” that STL pioneered and not the
complexity of the “Standard Template Library” (or STL) of C++,. They wanted the new framework to
accommodate the legacy classes. They had to make some hard choices, and came up with a number of
distinctive design decisions. This chapter takes you through the basic design of the Java collections
framework, let you know how to make it work, and reasons behind some of its controversial features.
Just like other data structure libraries, the Java collection library also separates interfaces and
implementations.
Collections Overview
This chapter deals with one of the powerful subsystems: Collections. Collections provide a well-defined
set of interfaces and classes to store and manipulate groups of data as a single unit. This unit is called a
collection.
The framework provides a convenient API to many of the abstract datatypes like maps, sets, lists, trees,
arrays, hashtables and other collections. The Java classes in the Collections Framework encapsulate both
the data structures and the algorithms associated with these abstractions because of their object-oriented
design.
The framework provides a standard programming interface to many of the most common abstractions,
without complicating it with too many procedures and interfaces. The programmer can easily define
higher-level data abstractions like stacks and queues with the help of a variety of operations supported by
the collections framework.
243 | P a g e
360digrii
Java course material
The major goals of the Collections Framework are:
High-performance.
Implementations for the fundamental collections (dynamic arrays, linked lists, trees, and hash tables) are highly
efficient.
Should avoid coding of these “data engines” manually.
Should allow different types of collections to work in a similar manner.
Should have a high degree of interoperability.
Should be easy to extend and/or adapt a collection.
Towards this end, the entire collections framework is designed around a set of standard interfaces.
Several standard implementations (such as LinkedList, HashSet, and TreeSet) of these interfaces are
ready to use. You can also use your own collections. Various special-purpose implementations are created
for your convenience, and some partial implementations are provided to make it easier to have user-
defined Collection class. Mechanisms were added to integrate standard arrays into the collections
framework.
Algorithms are another major part of the collection mechanism, which operate on collections and are
defined as static methods within the Collections class. Thus, they are available for all collections. Each
collection class need not implement its own version. A standard means of manipulating collections is
provides by these algorithms.
Iterator interface is another item created by the collections framework. It provides a general-purpose,
standardized way of accessing the elements within a collection, one at a time. Thus, an iterator provides a
means of enumerating the contents of a collection. Because each collection implements Iterator, the
elements of any collection class can be accessed through the methods defined by Iterator. Thus, with only
small changes, the code that cycles through a set can also be used to cycle through a list, for example.
In addition to collections, several map interfaces and classes are defined within the framework. Maps store
key/value pairs. Though maps are not actually collections, they are completed integrated with collections.
In the language of the collections framework, you can obtain a collection-view of a map. Such a view
contains the elements from the map stored in a collection. Thus, you can process the contents of a map as a
collection.
The collection mechanism was retrofitted to some of the original classes defined by java.util so that they
too could be integrated into the new system. Although the addition of collections altered the architecture
of many of the original utility classes, it did not cause the deprecation of any. Collections simply provide a
better way to do many things.
One last thing: familiarity to C++ will help you to know that the Java collections technology is similar in
spirit to the Standard Template Library (STL) defined by C++. What C++ calls a container, Java calls it ,a
collection.
Collection Interfaces
The Collections Framework is made up of a set of interfaces for working with groups of objects. The
different interfaces describe the different types of groups. Once you are clear with the interfaces, you can
244 | P a g e
360digrii
Java course material
easily understand the framework. While you always need to create specific implementations of the
interfaces, access to the actual collection should be restricted to the use of the interface methods, thus
allowing you to change the underlying data structure, without altering the rest of your code. The following
diagrams show the framework interface hierarchy.
The root of the hierarchy of the collections interfaces is the Collection interface. It is also referred to as
the superinterface of the collections. There is another kind of collection called maps, which are
represented by the superinterface Map, which is not derived from the Collection interface. Both kinds of
collections interfaces are shown in Fig 1 above.
The List and Set interfaces extend from the Collection interface, and there is no direct implementation of
the Collection interface. Some of characteristics of the subinterfaces of Collection (that is, List and Set) and
of Map are as follows:
• List: An ordered collection of data items; i.e. The position of each data item is defined and known. A list
can have duplicate elements.
ArrayList, LinkedList, and Vector are the classes that implement the List interface.
• Map: An object that maps keys to values: each key can map to at most one value. Maps cannot have
duplicate keys.
HashMap and HashTable are some of the classes that implement the Map interface. Duplicate keys are not
allowed in maps but duplicate values are allowed.
• Set: A collection of unique items; i.e. there are no duplicates.
HashSet and LinkedHashSet are examples of classes that implement the Set interface.
Implementations of Collections Interfaces:
Classes, which implement the interfaces and represent reusable data structures to hold the data items, are
the Implementations of the collections interfaces. As you know, the purpose of a collection is to represent
a group of related objects, known as its elements. Depending upon the application requirements, these
related data items could be grouped together in various ways.
245 | P a g e
360digrii
Java course material
Following Fig 2 shows the hierarchy of collection and map implementations.
As per the application requirements, duplicate elements are allowed with some collections. Some are
ordered and others are unordered. There are certain restrictions on elements that an implementation can
contain, such as no null elements, and there can be restrictions on the types of their elements. Consider the
following features. The implementation you choose depends on which of them is important for your
application.
• Performance: It refers to the time taken by a specific operation on the data as a function of the number
of data items in the structure, such as accessing a given data item (search) and inserting or deleting an
item in the data structure. In some data structures, the search and insertion/deletion may have opposing
performance requirements. That means if a data structure offers fast search, the insertion/deletion may be
slow.
• Ordered/sorted: A data structure is said to be ordered if the data items are in a specific order. For
example, an array is an ordered data structure because the data items are ordered by index; that is, we can
refer to the data items with their index, such as the seventh element. A data structure is said to be sorted if
the data items are ordered either by ascending order or descending order of their values. So, by definition,
a sorted data structure is an ordered data structure, but not vice versa.
• Uniqueness of items: If you require each data item of the data structure to be uniquely identifiable, or
on the contrary, you want to allow duplicate items.
• Synchronized: Implementations are synchronized when they provide thread safety (i.e. they can be run
in a multithreaded environment). However, need not be considered while choosing an implementation,
246 | P a g e
360digrii
Java course material
because you can always use synchronization methods from the Collections class even if the
implementation is unsynchronized.
The characteristics of different implementations of the collections interfaces are summarized in the
following Table1:
The Collection interface is used to represent any group of objects, or elements. The interface is used when
you want to work with a group of elements in a very generalized manner.
class iteratordemo
{
public static void main(String args[])
{
ArrayList al=new ArrayList();
al.add("pehla");
248 | P a g e
360digrii
Java course material
al.add("dusra");
al.add("teesra");
al.add("chautha");
al.add("panchwa");
al.add("chhatha");
al.add("sathwa");
al.add("athwa");
al.add("nawa");
al.add("daswa");
//Use iterator to display contents of al.
System.out.println("Original contents of al :");
Iterator itr = al.iterator();
while(itr.hasNext())
{
Object element=itr.next();
System.out.print(element+" ");
}
System.out.println();
//Modify objects being created.
ListIterator litr = al.listIterator();
while(litr.hasNext())
{
Object element=litr.next();
litr.set(element+"+ ");
}
System.out.println("Modified contents of al :");
itr = al.iterator();
while(itr.hasNext())
{
Object element=itr.next();
System.out.print(element+" ");
}
System.out.println();
//Now display the list backwards.
System.out.println("Modified list backwards :");
249 | P a g e
360digrii
Java course material
while(litr.hasPrevious())
{
Object element=litr.previous();
System.out.print(element+" ");
}
System.out.println();
}
}
Group Operations
Group operations are tasks done on groups of elements or the entire collection at once:
boolean containsAll(Collection collection)
boolean addAll(Collection collection)
void clear()
void removeAll(Collection collection)
void retainAll(Collection collection)
The containsAll() method tells you whether the current collection contains all the elements of another
collection, a subset. The remaining methods are optional, in that a specific collection might not support the
altering of the collection.
The addAll() method ensures the addition of all elements from another collection to the current collection,
usually a union.
The clear() method removes all elements from the current collection.
The removeAll() method is like clear() but only removes a subset of elements.
The retainAll() method is similar to the removeAll() method, but does what might be perceived as the
opposite. It removes from the current collection those elements not in the other collection, an intersection.
The remaining two interface methods, which convert a Collection to an array, will be discussed later.
AbstractCollection Class
The AbstractCollection class provides the foundation for the concrete collection framework classes. While
you can implement all the methods of the Collection interface yourself, the AbstractCollection class
provides implementations for all the methods, except for the iterator() and size() methods, which are
implemented in the appropriate subclass. Optional methods like add() will throw an exception if the
subclass doesn't override the behavior.
Collection Framework Design Concerns
While creating the Collections Framework, the Sun development team had to provide flexible interfaces
that manipulated groups of elements. To keep the design simple, the interfaces define all the methods an
implementation class may provide. However, some of the interface methods are optional. Because an
250 | P a g e
360digrii
Java course material
interface implementation must provide implementations for all the interface methods, there needed to be
a way for a caller to know if an optional method is not supported. The manner the framework
development team chose to signal callers when an optional method is called was to throw an
UnsupportedOperationException exception. If while using a collection, an
UnsupportedOperationException is thrown while trying to add to a read-only collection, then it indicates
that the operation failed because it is not supported.Yhe UnsupportedOperationException class is an
extension of the RuntimeException class.
In addition to handling optional operations with a runtime exception, the iterators for the concrete
collection implementations are fail-fast. That means that if you are using an Iterator to traverse a
collection while underlying collection is being modified by another thread, then the Iterator fails
immediately by throwing a ConcurrentModificationException (another RuntimeException). That means
the next time an Iterator method is called, and the underlying collection has been modified, the
ConcurrentModificationException exception gets thrown.
Set Interface
The Set interface defines a set and extends the Collection interface. It forbids duplicates within the
collection. All the original methods are present and no new methods are introduced. The concrete Set
implementation classes rely on the equals() method of the object added to check for equality.
251 | P a g e
360digrii
Java course material
hashCode() implementation in Object. You have to override hashCode() when creating your own classes to
add to a HashSet. You will find the TreeSet implementation to be useful when you need to extract elements
from a collection in a sorted manner. In order to work properly, elements added to a TreeSet must be
sortable. The Collections Framework adds support for Comparable elements and will be covered in detail
later. As of now, assume a tree knows how to keep elements of the java.lang wrapper classes sorted. It is
generally faster to add elements to a HashSet and then convert the collection to a TreeSet for sorted
traversal.
Tuning the initial capacity and the load factor you will be able to make optimal usage of HashSet space. The
TreeSet has no tuning options, as the tree is always balanced, ensuring log(n) performance for insertions,
deletions, and queries.
Both HashSet and TreeSet implement the Cloneable interface.
HashSet Usage Example
import java.util.*;
class hashsetdemo
{
public static void main(String args[])
{
HashSet hs=new HashSet();
hs.add("TERA");
hs.add("JADOO");
hs.add("CHAL");
hs.add("GAYA");
System.out.println(hs);
}
}
TreeSet Usage example:
import java.util.*;
class treesetdemo
{
public static void main(String args[])
{
TreeSet t=new TreeSet();
t.add("t");
t.add("j");
t.add("c");
252 | P a g e
360digrii
Java course material
t.add("g");
System.out.println(t);
}
}
AbstractSet Class
To ensure two equal sets return the same hash code, the AbstractSet class overrides the equals() and
hashCode() methods. If both the sets are the same size and contain the same elements, then they are said
to be equal. By definition, the hash code for a set is the sum of the hash codes for the elements of the set.
Thus, irrespective of what the internal ordering of the sets is, same hash code is reported by the two equal
sets.
List Interface
The List interface extends the Collection interface to define an ordered collection and it permits
duplicates. The interface adds position-oriented operations, and also the ability to work with just a part of
the list. Below is a list of methods provided by the List Interface:
boolean add(Object element)
void add(int index, Object element)
boolean addAll(Collection collection)
boolean addAll(int index, Collection collection)
void clear()
boolean contains(Object element)
boolean containsAll(Collection collection)
boolean equals(Object object)
Object get(int index)
int hashCode()
Iterator iterator()
int lastIndexOf(Object element)
ListIterator listIterator()
ListIterator listiterator(int startIndex)
boolean remove(Object element)
Object remove(int index)
boolean removeAll (Collection collection)
boolean retainAll(Collection collection)
Object set(int index, Object element)
int size()
List sublist(int fromIndex, int toIndex)
Object[] toArray()
Object[] toArray(Object[] array )
253 | P a g e
360digrii
Java course material
The position-oriented operations include the ability to insert an element or Collection, get an element, as
well as remove or change an element. Searching for an element in a List can be started from the beginning
or end and will report the position of the element, if found. Some of the methods to implement position-
oriented operations are:
void add(int index, Object element)
boolean addAll(int index, Collection collection)
Object get(int index)
int indexOf(Object element)
int lastIndexOf(Object element)
Object remove(int index)
Object set(int index, Object element)
The List interface also helps working with a subset of the collection, and iterating through the entire list in
a position friendly manner:
ListIterator listIterator()
ListIterator listIterator(int startIndex)
List subList(int fromIndex, int toIndex)
It is important to mention that the element at fromIndex is in the sub list in working with subList(), but
the element at toIndex is not. This loosely maps to the following for-loop test cases:
for (int i=fromIndex; i<toIndex; i++) {
// process element at position i
}
In addition, it should be mentioned that changes to the sublist like add(), remove(), and set() calls have
an effect on the underlying List.
ListIterator Interface
To support bi-directional access, as well as adding or changing elements in the underlying collection,
Iterator interface is extended to ListIterator interface. listIterator() method returns an object of
listIterator class type.
void add(Object element)
boolean hasNext()
boolean hasPrevious()
Object next()
int nextIndex()
Obejct previous()
int previousIndex()
254 | P a g e
360digrii
Java course material
void remove()
void set(Obejct element)
The code below illustrates the looping backwards through a list. Notice that the ListIterator is originally
positioned beyond the end of the list [list.size()], as the index of the first element is 0.
List list = ...;
ListIterator iterator = list.listIterator(list.size());
while (iterator.hasPrevious()) {
Object element = iterator.previous();
// Process element
}
Generally, ListIterator is not used to alternate between going forward and backward in one iteration
through the elements of a collection. While technically possible, one needs to know that calling next()
immediately after previous() results in the same element being returned. The same thing happens when
you reverse the order of the calls to next() and previous().
In case of add() operation, adding an element results in the new element being added immediately prior to
the implicit cursor. Thus, calling previous() after adding an element would return the new element and
calling next() would have no effect, returning what would have been the next element prior to the add
operation.
ArrayList, LinkedList Classes
There are two general-purpose List implementations in the Collections Framework: ArrayList and
LinkedList. Based on your specific needs, you can choose between the two list implementations. Suppose,
random access is what you require, without inserting or removing elements from any place other than the
end, then ArrayList offers the optimal collection. However, if your requirement is frequent addition and
removal of elements from the middle of the list and only access the list elements sequentially, then,
LinkedList offers the better implementation.
Both the general-purpose implementations, ArrayList and LinkedList, implement the Cloneable interface.
Additionally, to work with the elements at the ends of the list, several methods are provided by LinkedList.
(Only the new methods are shown in the following list):
void addFirst(Object element)
void addLast(Object element)
Object getFirst()
Object getLast()
Obejct removeFirst()
Obejct removeLast()
255 | P a g e
360digrii
Java course material
Below is a program to demonstrate ArrayList usage:
import java.util.* ;
class ArrayListDemo
{
public static void main(String args[])
{
ArrayList a1 = new ArrayList();
System.out.println("Initital Size Ofa1 " +a1.size()) ;
//add elements
a1.add("360 digrii");
a1.add("niit");
a1.add("aptech");
a1.add("ssi");
a1.add("cmc");
a1.add("pannet");
a1.add("tulec");
a1.add("ignou");
a1.add("iddco");
System.out.println(" Size Of a1 After addition " +a1.size()) ;
// display array list
System.out.println("content of a1 " +a1) ;
a1.remove("tulec");
a1.remove(3);
System.out.println(" Size Of a1 After deletion " +a1.size()) ;
System.out.println(" content of a1 " +a1) ;
}
}
Below is the program to implement Linkedlist:
import java.util.*;
class linkedlistdemo
{
public static void main(String args[])
256 | P a g e
360digrii
Java course material
{
LinkedList ll=new LinkedList();
System.out.println("Initial size of ll :"+ll.size());
//add elements
ll.add("360 digrii");
ll.add("niit");
ll.add("nimt");
ll.add("aptech");
ll.add("first");
ll.add("ignou");
ll.add("idco");
ll.add("narimann");
ll.add("telco");
ll.add("officenet");
ll.add("hindalco");
ll.add("nalco");
ll.addLast("last mein rahe gaya");
ll.addFirst("pehle main aa gaya");
ll.add(2,"teen number pe ghus gaya");
System.out.println("Size of ll after addition :"+ll.size());
257 | P a g e
360digrii
Java course material
You can easily treat the LinkedList as a stack, queue, or other end-oriented data structure by using new
methods.
Running the program produces the following output. Notice that, unlike Set, List permits duplicates.
[Sunday, Monday, Tuesday, Monday, Wednesday]
2: Tuesday
0: Sunday
[Wednesday, Monday, Tuesday, Monday, Sunday]
[Wednesday, Monday, Tuesday]
AbstractList AbstractSequentialList
ListIterator listIterator(int
index)
- boolean hasNext()
- Object next()
Object get(int index)
unmodifiable - int nextIndex()
int size()
- boolean hasPrevious()
- Object previous()
- int previousIndex()
int size()
unmodifiable +
unmodifiable +
modifiable ListIterator
Object set(int index, Object element)
- set(Object element)
259 | P a g e
360digrii
Java course material
modifiable +
variable-size modifiable +
ListIterator
and add(int index, Object element)
- add(Object element)
modifiable Object remove(int index)
- remove()
Two constructors, a no-argument one and one that accepts another Collection, should also be provided.
Map Interface
The Map interface starts off its own interface hierarchy, for maintaining key-value associations. It is not an
extension to Collection interface. According to it’s definition, the interface describes a mapping from keys
to values, without duplicate keys.
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
Set entrySet()
Object get(Object key)
boolean isEmpty()
Set keySet()
Object put(Object key, Object value)
void putAll(Map mapping)
Object remove(Object key)
int size()
Collection values()
The interface methods can be broken down into three sets of operations: altering, querying, and providing
alternative views.
The alteration operations allow you to add and remove key-value pairs from the map even when the key
and value can be null. However, you should not add a Map to itself as a key or value.
Object put(Object key, Object value)
Object remove(Object key)
void putAll(Map mapping)
void clear()
The query operations allow you to check on the contents of the map:
Object get(Object key)
boolean containsKey(Object key)
260 | P a g e
360digrii
Java course material
boolean containsValue(Object value)
int size()
boolean isEmpty()
The last set of methods allows you to work with the group of keys or values as a collection.
public Set keySet()
public Collection values()
public Set entrySet()
Since the collection of keys in a map must be unique, you get a Set back. Since the collection of values in a
map may not be unique, you get a Collection back. The last method returns a Set of elements that
implement the Map.Entry interface, described next.
Map.Entry Interface
The entrySet() method of Map returns a collection of objects that implement Map.Entry interface. Each
object in the collection is a specific key-value pair in the underlying Map.
boolean equals(Object object)
Object getKey()
Object getValue()
int hashCode()
Object setValue(Object value)
Iterating through this collection, you can get the key or value, as well as change the value of each entry.
However, the set of entries becomes invalid, causing the iterator behavior to be undefined, if the
underlying Map is modified outside the setValue() method of the Map.Entry interface.
HashMap, TreeMap Classes
HashMap and TreeMap are the two general-purpose Map implementations provided by the Collections
Framework. As with all the concrete implementations, which implementation you use depends on your
specific needs. The HashMap offers the best alternative for inserting, deleting, and locating elements in a
Map. However, if you need to traverse the keys in a sorted order, then TreeMap is a better alternative.
Depending upon the size of your collection, it may be faster to add elements to a HashMap, and then
convert the map to a TreeMap for sorted key traversal. Using a HashMap requires that the class of key
added have a well-defined hashCode() implementation. With the TreeMap implementation, elements
added to the map must be sortable.
Tuning the initial capacity and load factor will help you make optimal use of HashMap space. The TreeMap
has no tuning options, as the tree is always balanced.
The Cloneable interface can be implemented with both HashMap and TreeMap.
The Hashtable and Properties classes are historical implementations of the Map interface.
261 | P a g e
360digrii
Java course material
Map Usage Example
The following program demonstrates the use of the concrete Map classes.
First let us see the usage of HashMap class:
HashMap Example:
import java.util.*;
class HashMapDemo
{
public static void main(String args[])
{
HashMap hm = new HashMap();
hm.put("amarendra mohanty",new Double(5000));
hm.put("sarada satpathy",new Double(4500));
hm.put("pravat pala",new Double(6000));
hm.put("mitrabhanu tripathy",new Double(7000));
262 | P a g e
360digrii
Java course material
public static void main(String args[])
{
TreeMap hm = new TreeMap();
hm.put("mitrabhanu tripathy ",new Double(5000));
hm.put("sarada satpathy",new Double(4500));
hm.put("amarendra mohanty",new Double(6000));
hm.put("pravat pala",new Double(7000));
263 | P a g e
360digrii
Java course material
Sorting
To add support for Sorting, many changes have been done to the core Java libraries with the addition of
Collection Framework in the Java 2 SDK version 1.2. Comparable interface can be implemented by classes
like String and Integer so that a natural sorting order is provided. You can implement the Comparator
interface to define your own order when you desire a different order than the natural order, or for the
classes without a natural order.
To take advantage of the sorting capabilities, SortedSet and SortedMap are the two interfaces provided by
Collections Framework.
Comparable Interface
The Comparable interface, in the java.lang package, is for those classes, which have a natural ordering. The
interface allows you to order the collection into that natural ordering when a collection of objects is of the
same type.
int compareTo(Object element)
compareTo(): Using this method, current instance can be compared with an element that is passed as an
argument. If the current instance comes before the argument in the ordering, it returns a negative value,
whereas if the current instance comes after, then a positive value is returned. Otherwise, it returns a zero.
It is does not mean that a zero return value signifies equality of elements but it just signifies that two
objects are ordered at the same position.
Several classes implement the Comparable interface. You will observe from the below table that some
classes share the same natural ordering. Only mutually comparable classes can be sorted. This goes for
the current release of the SDK. (that means the same class.)
The following table shows their natural ordering.
Class Ordering
BigDecimal
BigInteger
Byte
Double
Float Numerical
Integer
Long
Short
Date Chronological
264 | P a g e
360digrii
Java course material
specific pathname
The documentation for the compareTo() method of String defines the ordering lexicographically. This
implies the comparison is of the numerical values of the characters in the text, which is not necessarily
alphabetically in all languages. For locale-specific ordering, use Collator with CollationKey.
The following demonstrates the use of Collator with CollationKey to do a locale-specific sorting:
import java.text.*;
import java.util.*;
public class CollatorTest {
public static void main(String args[]) {
Collator collator =
Collator.getInstance();
CollationKey key1 =
collator.getCollationKey("Som");
CollationKey key2 =
collator.getCollationKey("som");
CollationKey key3 =
collator.getCollationKey("shon");
CollationKey key4 =
collator.getCollationKey("Shon");
CollationKey key5 =
collator.getCollationKey("Shonar");
Set set = new TreeSet();
set.add(key1);
set.add(key2);
set.add(key3);
set.add(key4);
set.add(key5);
printCollection(set);
}
static private void printCollection(
Collection collection) {
265 | P a g e
360digrii
Java course material
boolean first = true;
Iterator iterator = collection.iterator();
System.out.print("[");
while (iterator.hasNext()) {
if (first) {
first = false;
} else {
System.out.print(", ");
}
CollationKey key =
(CollationKey)iterator.next();
System.out.print(key.getSourceString());
}
System.out.println("]");
}
}
Running the program produces the following output:
[shon, Shon, Shonar, som, Som]
Making your own class Comparable is just a matter of implementing the compareTo() method. It usually
involves relying on the natural ordering of several data members. Your own classes should also override
equals() and hashCode() to ensure two equal objects return the same hash code.
Comparator Interface
When java.lang.Comparable cannot be implemented with a class or if you don’t like the default
Comparable behavior, you can provide your own java.util.Comparator.
int compare(Object element1, Object element2)
boolean equals(Object object)
The return values of both the methods, compare() method of Comparator and compareTo() method of
Comparable are similar. In this case, if the first element comes before the second element in the ordering,
it returns a negative value. If the first element comes after, then a positive value is returned. It returns a
zero value. As we have seen in the case of Comparable, even in comparator interface, zero return value
does not signify equality of elements. It just signifies that two objects are ordered at the same position.
It depends on the user of the Comparator to determine how to deal with it. If two unequal elements
compare to zero, you should first be sure what you want. When used with a TreeSet or TreeMap it can be
tedious to use a Comparator that is not compatible to equals(). With a Set, only the first will be added. With
a map, the value for the second will replace the value for the second (keeping the key of the first).
To demonstrate, you may find it easier to write a new Comparator that ignores case, instead of using
Collator to do a locale-specific, case-insensitive comparison. The following is one such implementation:
266 | P a g e
360digrii
Java course material
class CaseInsensitiveComparator implements
Comparator {
public int compare(Object element1,
Object element2) {
String lowerE1 = (
(String)element1).toLowerCase();
String lowerE2 = (
(String)element2).toLowerCase();
return lowerE1.compareTo(lowerE2);
}}
Since every class subclasses Object at some point, you need not implement the equals() method. In most
cases you do not implement it. The equals() method compares only the comparator implementations and
not the objects being compared.
With the Collections class, a predefined Comparator is available for reuse. Objects that implement the
Comparable interface are sorted in reverse order by a comparator which is returned as a result of calling
Collections.reverseOrder().
SortedSet Interface
For maintaining elements in a sorted order, a special Set interface, SortedSet is provided by the Collections
Framework.
Comparator comparator()
Object first()
SortedSet headSet(Object toElement)
Object last()
SortedSet subSet(Object fromElement , Object toElement)
SortedSet tailSet(Object fromElement)
Access methods are provided to the ends of the set as well as to subsets of the set by the interface. When
you work with these subsets of the list, you can see that the changes to the subset are reflected in the
source set and vice versa. This works because elements identify the subsets at the end points and not
indices. Moreover, if the fromElement is part of the source set then it is also a part of the subset. However,
if the toElement is part of the source set, it is not part of the subset. If you want a particular to-element to
be in the subset, you have to find out the next element. In the case of a String, the next element is the same
string with a null character appended (string+"\0").
The elements added to a SortedSet must either implement Comparable or you must provide a Comparator
to the constructor of its implementation class: TreeSet. (You can implement the interface yourself. But the
Collections Framework only provides one such concrete implementation class.)
To demonstrate, the following example uses the reverse order Comparator available from the Collections
class:
267 | P a g e
360digrii
Java course material
import java.text.*;
import java.util.*;
public class Comp {
public static void main(String args[]) {
Comparator comparator = Collections.reverseOrder();
Set reverseSet = new TreeSet(comparator);
reverseSet.add("January");
reverseSet.add("February");
reverseSet.add("March");
reverseSet.add("February");
reverseSet.add("April");
System.out.println(reverseSet);
}}
Running the program produces the following output:
[March, January, February, April]
Because sets must hold unique items, if comparing two elements when adding an element results in a zero
return value (from either the compareTo() method of Comparable or the compare() method of
Comparator), then the new element is not added. If the elements are equal, then that is okay. However, if
they are not, then you should modify the comparison method such that the comparison is compatible with
equals().
Using the following creates a set with three elements: thom, Thomas, and Tom, not five elements as might
be expected.
Comparator comparator =
new CaseInsensitiveComparator();
Set set = new TreeSet(comparator);
set.add("Tom");
set.add("tom");
set.add("thom");
set.add("Thom");
set.add("Thomas");
SortedMap Interface
SortedMap: It is a special Map interface provided by the Collections Framework for maintaining keys in a
sorted order.
Comparator comparator()
Object firstKey()
268 | P a g e
360digrii
Java course material
SortedMap headMap(Object toKey )
Object lastKey()
SortedMap subMap (Object fromKey, Object toKey)
SortedMap tailMap (Object fromKey)
Access methods are provided by the interface to the ends of the map as well as to subsets of the map. A
SortedMap workd just like a SortedSet, except that the sort is done on the map keys. TreeMap is the
implementation class provided by the Collections Framework.
Since the key value pairs are unique, (i.e. one maps can only have one value for every key), if a zero value is
returned while comparing two keys when adding a key-value pair (from either the compareTo() method
of Comparable or the compare() method of Comparator), then new value replaces the value for the
original key. If the result is zero then it is fine. But when they are not, then comparison method should be
modified such that the comparison is compatible with equals().
There can be situations when you need to use some of the original collections capabilities rather than the
new ones. The capabilities of working with some of these collections (arrays, vectors, hashtables,
enumerations, and other historical capabilities.) is shown below:
Arrays
You must have learnt about arrays while learning the basics of Java programming language. According to
their definition, Arrays are fixed-size collections of the same datatype. You must remember that only
Arrays can store primitive datatypes. All others including arrays, can store objects. While creating an
array, the number and type of object you wish to store has to be specified. The size of an array can neither
grow nor store a different type. (unless it extends the first type).
To find out the size of an array, you ask its single public instance variable, length, as in array.length.
To access a specific element, either for setting or getting, you place the integer argument within square
brackets ([int]), either before or after the array reference variable. The integer index is zero-based, and
accessing beyond either end of the array will throw an ArrayIndexOutOfBoundsException at runtime.
However, if a long variable is used to access an array index, you get a compiler-time error.
Arrays are full-fledged subclasses of java.lang.Object. They can be used with the various Java programming
language constructs excepting an object:
Consider the following example to implement Array class:
import java.util.*;
class ArrayDemo
{
public static void main ( String args[])
{
int array[] = new int [10];
for ( int i =1; i<10;i++)
269 | P a g e
360digrii
Java course material
array[i]= 3 * i ;
A Vector is a historical collection class whose size can grow, but it can store heterogeneous data elements.
With the Java 2 SDK, version 2, List interface can be implemented by the Vector class as it has been
retrofitted into the Collections Framework hierarchy. You should use ArrayList, if you are using the new
framework.
When transitioning from Vector to ArrayList, one key difference is the arguments have been reversed to
positionally change an element's value:
From original Vector class
void setElementAt(Object element, int index)
270 | P a g e
360digrii
Java course material
From List interface
void set(int index, Object element)
The Stack class extends Vector to implement a standard last-in-first-out (LIFO) stack, with push() and
pop() methods. Be careful though. Since the Stack class extends the Vector class, you can still access or
modify a Stack with the inherited Vector methods.
Let us see an example to understand the usage of Vector class:
//Vector Example
import java.util.*;
class vectordemo
{
public static void main(String args[])
{
Vector v = new Vector(3,2);
System.out.println("Initial size "+v.size());
System.out.println("Initial capacity "+v.capacity());
v.addElement(new Integer(1));
v.addElement(new Integer(2));
v.addElement(new Integer(3));
v.addElement(new Integer(4));
System.out.println("Capacity after addition "+v.capacity());
v.addElement(new Double(50.20));
v.addElement(new Double(22.56));
System.out.println("Capacity after addition "+v.capacity());
v.addElement(new Float(0.20));
v.addElement(new Float(2.56));
System.out.println("Capacity after addition "+v.capacity());
v.insertElementAt( new Double(10.29),2);
v.removeElementAt(2);
System.out.println("First Element "+(Integer)v.firstElement());
System.out.println("Last Element "+(Float)v.lastElement());
}
}
Let us see an example for the usage of Stack Class:
import java.util.* ;
class StackDemo
271 | P a g e
360digrii
Java course material
{
static void showpush( Stack st,int a)
{
st.push(new Integer(a));
System.out.println("push ( " + a + " ) " );
System.out.println("Stack : " + st);
}
static void showpop(Stack st)
{
System.out.println("POP ---- > ");
Integer a = (Integer) st.pop();
System.out.println(a);
System.out.println("Stack : " +st );
}
public static void main(String args[])
{
Stack st = new Stack();
System.out.println("Stack " + st );
showpush(st, 45);
showpush(st, 50 );
showpush(st, 65);
showpush(st,70 );
showpush(st,80);
showpop(st);
showpop(st);
showpop(st);
showpop(st);
showpop(st);
try
{
showpop(st);
}
catch (EmptyStackException e )
{
System.out.println("Empty Stack ");
272 | P a g e
360digrii
Java course material
}
}
}
Enumeration Interface
To iterate through all the elements of a collection, you can use Enumeration interface. This interface has
been superceded by the Iterator interface in the Collections Framework. You may use Enumeration from
time to time because all libraries do not support the newer interface.
boolean hasMoreElements()
Object nextElement()
Iterating through an Enumeration is similar to iterating through an Iterator, though method names are
more preferred with Iterator. However, there is no removal support with Enumeration.
Enumeration enum = ...;
while (enum.hasNextElement()) {
Object element = iterator.nextElement();
// process element
}
Dictionary, Hashtable, Properties Classes
The Dictionary class is full of abstract methods. Infact, it should have been an interface. It forms the basis
for key-value pair collections in the historical collection classes, with its replacement being Map, in the
new framework. Hashtable and Properties are the two specific implementations of Dictionary available.
Storage of any object (except null) as its key or value is permitted with the Hashtable implementation and
hence is called a generic dictionary. With the new version of Java SDK, to implement the Map interface, the
class has been reworked into the Collections Framework. So, you can go for the original Hashtable
methods or the newer Map methods. If you need a synchronized Map, using Hashtable is slightly faster
than using a synchronized HashMap.
To work with text strings, a specialized Hashtable called Properties implementation is used. Properties
class allows gets you text values without any casting whereas you have to cast values retrieved from a
Hashtable to your desired class. Loading and saving property settings from and input stream or to an
output stream is also supported by the class. System.getProperties() retrieves the system properties list
which is the most commonly used set of properties.
Here’s an example to understand the usage of HashTable Class:
import java.util.*;
class hashtabledemo
{
public static void main(String args[])
273 | P a g e
360digrii
Java course material
{
//Create a hash table
Hashtable balance=new Hashtable();
Enumeration names;
String str;
//Put elements into ‘balance’
balance.put("Benjamin gilani",new Double(3434.34));
balance.put("Nusrulla Khan",new Double(7834.33));
balance.put("Benjamin gilani",new Double(3439.80));
balance.put("Arijit bolbaka",new Double(1378.00));
balance.put("Anu Kalia",new Double(299.34));
balance.put("Ali Kuli Khan",new Double(399.34));
balance.put("Golmal Khan",new Double(-19.34));
//show all balances in hashtable
names=balance.keys();
while(names.hasMoreElements())
{
str=(String)names.nextElement();
System.out.println(str+":"+balance.get(str));
}
System.out.println();
274 | P a g e
360digrii
Java course material
System.out.println("Nusrulla Khan's new balance "+balance.get("Nusrulla Khan"));
}
}
BitSet Class
BitSet: It gives an alternate representation of a set. If a finite number of n objects are given, each object can
be associated with a unique integer. Then each possible subset of the objects corresponds to an n-bit
vector, with each bit "on" or "off" depending on whether the object is in the subset. For small values of n, a
bit vector might be an extremely compact representation. However, for large values of n an actual bit
vector might be inefficient, when most of the bits are off.
Collections framework has been enhanced with the help of three new language features:
Generics
Adds compile-time type safety to the collections framework
Eliminates the need to cast when reading elements from collections.
Enhanced for loop
When iterating over collections, it eliminates the need for explicit iterators
Autoboxing/unboxing
Automatically converts primitives (such as int) to wrapper classes (such as Integer) when inserting them
into collections
Converts wrapper class instances to primitives when reading from collections.
Understanding Generics
The most important feature added to Collections API is Generics. It plays and important role in enhanced
for loop and autoboxing. Generics are Java's answer to C++ templates, but in many ways they are much
more. A specific type can be associated with collections with the help of Generics, which was not possible
before J2SE 5.0, and if tried to associate, it created many problems.
import java.util.*;
public class BasicCollection {
public static void main(String args[]) {
ArrayList list = new ArrayList();
list.add( new String("One") );
list.add( new String("Two") );
list.add( new String("Three") );
Iterator itr = list.iterator();
275 | P a g e
360digrii
Java course material
while( itr.hasNext() ) {
String str = (String)itr.next();
System.out.println( str );
}
}
}
The preceding code shows how a typical collection class might look prior to J2SE 5.0. The class creates an
ArrayList and adds three strings to it. Note that there's no specific type associated with this ArrayList; you
can add any class that inherits from Object to the ArrayList.
Look at the while loop that retrieves the strings from the ArrayList.
while(itr.hasNext() ) {
String str = (String)itr.next();
System.out.println( str );
}
The loop iterates over every item in the ArrayList. But notice what you have to do for each element
retrieved—typecast each element. The typecast is required because the ArrayList does not know what
types it stores. This is the problem that generics solve in Java. Generics allow you to associate a specific
type with the ArrayList. So when you upgrade this BasicCollection class to use generics, the problem
disappears. The GenericCollection class shown below constitutes an upgraded version
import java.util.*;
public class GenericCollection {
public static void main(String args[]) {
ArrayList<String> list = new ArrayList<String>();
list.add( new String("One") );
list.add( new String("Two") );
list.add( new String("Three") );
//list.add( new StringBuffer() );
Iterator<String> itr = list.iterator();
while( itr.hasNext() ) {
String str = itr.next();
System.out.println( str );
}
}
}
276 | P a g e
360digrii
Java course material
As you can see, only a few lines change when you upgrade the class to J2SE 5.0. The first is the line of code
that declares the ArrayList; this version declares the ArrayList using a type of String.
ArrayList<String> list = new ArrayList<String>();
Notice how the code combines the type with the name of the collection. This is exactly how you specify all
generics, delimiting the name of the type with angle brackets (<>), placed immediately after the end of the
collection name.
Next, when declaring the Iterator, you declare it as an Iterator for the String type. You specify the generic
type for the iterator exactly as you did for the ArrayList, for example:
Iterator<String> itr = list.iterator();
That line specifies the Iterator's type as String. Now, when you call the next method for the iterator, you no
longer need the typecast. You can simply call the next method and get back a String type.
String str = itr.next();
Although that's a nice code-saving feature, generics does more than just save you from having to do a
typecast. It will also cause the compiler to generate a compile error when you try to add an "unsupported"
type to the ArrayList. What is an unsupported type? Because the ArrayList was declared to accept strings,
any class that is not a String or a String subclass is an unsupported type.
The class StringBuffer is good example of an unsupported type. Because this ArrayList accepts only
Strings, it will not accept a StringBuffer object. For example, it would be invalid to add the following line to
the program.
list.add( new StringBuffer() );
Here's the real beauty of generics. If someone attempts to add an unsupported type to the ArrayList you
won't get a runtime error; the error will be detected at compile time. You will get the following compile
error.
c:\collections\GenericCollection.java:12:
cannot find symbol
symbol : method add(java.lang.StringBuffer)
location: class java.util.ArrayList<java.lang.String>
list.add( new StringBuffer() );
Catching such errors at compile time is a huge advantage for developers trying to write bug-free code.
Prior to J2SE 5.0 this error would have likely shown up later as a ClassCastException at runtime. Catching
errors at compile time is always preferable to waiting for the right conditions at runtime to cause the bug,
because those "right conditions" may very well appear only after deployment, when your users are
running the program.
277 | P a g e
360digrii
Java course material
Using the Enhanced For Loop
Java did not support for each loop for some time. Using languages like Visual Basic and C#, looping through
the contents of a collection was very easy because they supported a for loop. With the introduction of for
each loop in collections, one can access the contents of a collection without the need for an iterator. Now
(finally) Java has a for each looping construct, in the form of the enhanced for loop.
The enhanced for loop was one of the most anticipated features of J2SE 5.0. It simplifies your code to a
greater extent since there is no need of an iterator. Here's a version, upgraded to use the enhanced for
loop.
import java.util.*;
public class EnhancedForCollection {
public static void main(String args[]) {
ArrayList<String> list = new ArrayList<String>();
list.add( new String("One") );
list.add( new String("Two") );
list.add( new String("Three") );
//list.add( new StringBuffer() );
for( String str : list ) {
System.out.println( str );
}
}
}
The preceding code eliminates the Iterator and while loop completely, leaving just these three lines of
code.
The first parameter, the collection item type, must be a Java type that corresponds to the generic type
specified when the collection was created. Because this collection is type ArrayList, the collection item
type is String.
The next parameter provided to the enhanced for loop is the name of the access variable, which holds the
value of each collection item as the loop iterates through the collection.
278 | P a g e
360digrii
Java course material
That variable must also be the same as that specified for the collection item type.
For the last parameter, specify the collection to be iterated over. This variable must be declared as a
collection type, and it must have a generic type that matches the collection item type. If these two
conditions are not met, a compile error will result.
Primitive Data Types and Autoboxing
Another feature added to J2SE 5.0 is the ability to automatically box and unbox primitive datatypes. Using
this feature, the complexity is reduced to a great extent when you have to add and access primitive data
types in the collections API.
To understand what boxing and unboxing are, have a look to how primitive data types in Java were
handled prior to J2SE 5.0. Here's a simple Java application that makes use of primitive data types with the
collections API, prior to J2SE 5.0.
import java.util.*;
279 | P a g e
360digrii
Java course material
list.add( new Integer(1) );
list.add( new Integer(2) );
list.add( new Integer(3) );
But the boxing requirement presents a problem when later code tries to access the primitive int variables
stored in the collection. Because the primitive data types were stored as Integer objects they will be
returned from the collection as Integer objects, not as int variables, forcing yet another conversion to
reverse the boxing process:
Iterator itr = list.iterator();
while( itr.hasNext() ) {
Integer iObj = (Integer)itr.next();
int iPrimitive = iObj.intValue();
System.out.println( iPrimitive );
}
In this case, the code first retrieves each item as an Integer object, named iObj. Next, it converts the Integer
object into an int primitive by calling its intValue method.
Using autoboxing, storing primitive types in collections and retrieving them becomes far simpler. Here's
an example.
import java.util.*;
With the addition of generics to J2SE 5.0, it is easy to specify what type of data a collection can store
exactly. Thus the collection accepts only the correct type of object, and eliminates the need to typecast
items stored to or retrieved from the collection. It is only the compiler that ensures these entire things.
In many programming languages you have found ‘for’ in each construct. Now the same functionality has
been used in Generics that allow you to use the enhanced for loop. So by using “enhanced for loop" the
need for iterators and the whole iterating process through a collection of items becomes simple and easy.
Finally, it is not an easy task to add primitive data types to collections. Developers have to handle the
feature called Autoboxing and Unboxing where they have to box primitive types such as int into Integer
objects and then unbox back into int primitive types. This results in much clearer source code while using
collections with primitive data types.
However due to these changes, whatever technique you use to access collection data in J2SE 5.0 is thus
been changed. But it has simplified Java code used to access the collections API to a great extent.
There are three new collection interfaces that are provided:
Queue – This represents a collection that is designed to hold elements before it goes for processing. Other
than basic Collection operations, queues also provide additional insertion, extraction, and
inspection operations.
lockingQueue – This is an extension of the Queue that waits for the queue to become non-empty while
retrieving an element and also the wait for space to become available in the queue when an
element is being stored. (This interface is included in package java.util.concurrent.)
ConcurrentMap – This extends Map with atomic putIfAbsent, remove, and replace methods. (This
interface is included in package java.util.concurrent.)
281 | P a g e
360digrii
Java course material
There are two new concrete Queue implementations that are provided, where one existing List
implementation has been retrofitted to implement Queue, and one abstract Queue implementation is
provided:
PriorityQueue – It is an unbounded priority queue backed by a heap.
ConcurrentLinkedQueue – It is an unbounded thread-safe FIFO (first-in first-out) queue backed by
linked nodes. (This class is part of java.util.concurrent.)
LinkedList – This is retrofitted to implement the Queue interface. LinkedList behaves as a FIFO queue,
when accessed via the Queue interface.
AbstractQueue – An implementation of skeletal Queue.
There are five new implementations of BlockingQueue implementations that are provided. (All of these are
included in java.util.concurrent):
LinkedBlockingQueue – It is a FIFO blocking queue, optionally bounded and backed by linked nodes.
ArrayBlockingQueue – It is a FIFO blocking queue, bounded and backed by an array.
PriorityBlockingQueue – It is an unbounded blocking priority queue backed by a heap.
DelayQueue – It is a time-based scheduling queue backed by a heap.
SynchronousQueue – It is a simple rendezvous mechanism utilizing the BlockingQueue interface.
There is one ConcurrentMap implementation:
ConcurrentHashMap – It is a ConcurrentMap implementation backed by a hash table highly concurrent
and with high-performance. When this implementation is used, it never blocks at the time of retrieval and
the client can select the concurrency level for updates. This is done so as to have a drop-in replacement for
Hashtable, which is in addition to implementing ConcurrentMap. It supports all of the "legacy" methods
peculiar to Hashtable.
There are some special-purpose List and Set implementations provided for situations where read
operations are more than write operations and also iteration cannot or should not be synchronized:
CopyOnWriteArrayList – It is a List implementation backed by an array. When you make a new copy of
the array, all mutative operations (such as add, set, and remove) are implemented. No synchronization is
required, even during iteration. Iterators promises never to throw ConcurrentModificationException. This
implementation is best for maintaining event-handler lists (where it has infrequent change, and traversal
is frequent and potentially time-consuming).
CopyOnWriteArraySet – It is a Set implementation backed by a copy-on-write array. This
implementation is same as CopyOnWriteArrayList. The add, remove, and contains methods require time
proportional to the size of the set which is unlike most Set implementations. This implementation is best
for maintaining event-handler lists that must prevent duplicates.
There are special-purpose Set and Map implementations that are provided for use with enums:
EnumSet – It is a Set implementation backed by a bit-vector with a high-performance. All elements must
be elements of a single enum type of each EnumSet instance.
282 | P a g e
360digrii
Java course material
EnumMap – It is a Map implementation backed by an array with a high-performance. All keys must be
elements of a single enum type in each EnumMap instance.
For the use with generic collections a new family of wrapper implementations is provided:
Collections.checkedInterface – It returns a dynamically typesafe view of the specified collection, which
throws a ClassCastException. It throws the same if a client wants to add an element of the wrong type. You
are provided with compile-time (static) type checking in this generics mechanism but it is possible to
defeat this mechanism in the language. This possibility is eliminated entirely by dynamically typesafe
views.
There are three new generic algorithms and one comparator converter added to the Collections utility
class:
frequency(Collection<?> c, Object o) - This counts the number of times the specified element occurs in
the specified collection.
disjoint(Collection<?> c1, Collection<?> c2) – This determines whether they contain no elements in
common or whether two collections are disjoint.
addAll(Collection<? super T> c, T... a) – This is convenient method where you can add all of the
elements in the specified array to the specified collection.
Comparator<T> reverseOrder(Comparator<T> cmp) – A comparator is returned that gives you the
reverse ordering of the specified comparator.
We have content-based hashCode and toString methods outfitted in the Arrays utility class for arrays of
all types. The existing equals() methods is complemented by these methods. The versions of all the three
methods are provided that operate on nested (or "multidimensional") arrays. They are deepEquals,
deepHashCode, and deepToString. It is not very necessary to print the contents of any array.
The idiom for printing a "flat" array is:
System.out.println(Arrays.toString(a));
The idiom for printing a nested (multidimensional) array is:
System.out.println(Arrays.deepToString(a));
Benefits of the Java Collections Framework
283 | P a g e
360digrii
Java course material
Reduces Effort to Learn and to Use New APIs
Many APIs naturally take collections on input and furnish them as output. Previously, each such API had a
small sub-API devoted to manipulating its collections. One had to learn each sub API just because of the
little consistency among them. There were lots of chances of making mistakes when using them. But, with
the advent of standard collection interfaces, the problem is solved.
Reduces Effort to Design New APIs
This is the flip side of the previous advantage. While creating an API that relies on collections, Designers
and implementers don't have to reinvent the wheel each time. Instead, they can use standard collection
interfaces.
Fosters Software Reuse
New data structures that conform to the standard collection interfaces are by nature reusable. The same
goes for new algorithms that operate on objects that implement these interfaces.
284 | P a g e
360digrii
Java course material
Chapter 13: JDBC
Introduction to JDBC
In simple language JDBC means the connectivity mechanism to connect a database through a java
program. The Java Database Connectivity (JDBC) API provides universal data access from the Java
applications to the backend database. You can use the JDBC API, to access any data source, from relational
databases to spreadsheets to flat files. The JDBC technology also provides a common base on which
alternate interfaces and tools can be built.
The JDBC is comprised of two packages:
The java.sql package
The javax.sql package, which adds server-side capabilities
Both the packages are available to you when you when you download J2SE
285 | P a g e
360digrii
Java course material
The same way let us understand related terms of database.
A database is essentially a smart container for tables.
A table is a container comprised of many rows.
A row is a container comprised of columns.
A column is a single data item having a name, type, and value.
In most computer languages, SQL is declarative rather than procedural. In other words, instead of writing
a class to perform some task in SQL, you issue a statement that updates a table or returns a group of
records. Different flavors of SQL have been created by different DBMS vendors and many of them support
additional features like procedural constructs, control-of-flow statements, user-defined data types, and
various other language extensions. It was in the year of 1992 when SQL was standardized. As a result
programs could communicate with most database systems without having to change much. However
before sending any SQL commands, you must connect to a database. Each database vendor provides a
different interface to do so, as well as different extensions of SQL. Many such extensions were formally
adopted as part of the SQL language, with the release of the SQL:1999.
Database Drivers
Database drivers are software programs that establish a connection between a client application and a
database. The drivers convert the query made by the application into the database specific calls and
thereby establishing communication. Drivers send SQL statements generated by the client application to a
database server and receive result and other responses from the server. There are several types of drivers
available. Some of them are discussed below.
Many database servers use vendor specific protocols. In other words, the programmer has to learn a new
language each time, to talk to a different database. Microsoft solved the problem by providing a common
standard for communicating with databases, called Open Database Connectivity (ODBC).
(See Fig. 1 a database client connected to many databases)
Java applications and applets use JDBC drivers to communicate with database servers.
286 | P a g e
360digrii
Java course material
Java application
JDBC/ODBC Vendor-
Bridge supplied JDBC
ODBC driver driver
Database Database
JDBC DRIVERS
JDBC provides a common database – programming API for Java programs. JDBC drivers do not
communicate with the databases directly, instead many JDBC drivers communicate with databases using
ODBC.
However, JDBC is a better solution. Java applications and applets use JDBC due to the following reasons:
ODBC is a C language API, not a Java language API. Java is object-oriented and C is not. C uses pointers that Java does
not support.
ODBC drivers must be installed on each client machines, and means that an applet’s access to a database would be
constrained by the requirement to download and install a JDBC driver.
As ODBC is developed in C, it is not portable across different hardware platform.
287 | P a g e
360digrii
Java course material
Ever since the release of JDBC API, a number of JDBC drivers have been developed. These drivers provide
varying levels of capability. JDBC drivers into the following types:
Type1. JDBC-ODBC Bridge plus ODBC Driver
This is a combination of the JDBC-ODBC bridge and an ODBC driver. This driver translates JDBC calls to
ODBC calls and relies on an ODBC driver to communicate with the database. This driver is included with
the JDK. However this driver requires deployment and proper configuration of an ODBC driver. The bridge
is handy for testing, but it is not recommended for production use. It is a cumbersome solution for both
Internet and Intranet because it needs both the drivers to be installed on the user’s machine. A block
diagram of JDBC-ODBC bridge is shown in Fig. 3.
288 | P a g e
360digrii
Java course material
Database
Server (A)
Java
Database JDBC_
Database
Client ODBC
Server (B)
bridge
This type of drivers is partly written in Java and partly in the native code. This driver category consists of
drivers that communicate with databases servers in the server’s native protocol. For example, as shown in
Fig. 4, an Oracle driver would use the SQL*Net protocol. Similarly a DB2 driver would use an IBM database
protocol. These drivers are implemented in a combination of binary code and Java, and they must be
installed on each client machines. The only benefit is that its installation is easier than installing both the
JDBC-ODBC bridge and an ODBC driver.
289 | P a g e
360digrii
Java course material
Database
Server (A)
Database
Server (C)
Java Type4
Database JDBC Database
Driver Server
Client Vender Specific
(Pure-
protocol
Java)
Fig. 6: Access to a database by JDBC-Net pure Java driver
Now a days, you will find most database vendors supply either JDBC-Net pure Java driver or Native
protocol pure Java driver with their databases. In addition, a number of third party companies specialize
in producing drivers with better conformance to standards, and support for more platforms.
No installation is required for the third and fourth type of driver. As these drivers are written entirely in
Java, they are downloaded from the web server along with the applet.
Note: In order to support zero installation, the driver is usually placed on the web server in the same
directory as the applet.
290 | P a g e
360digrii
Java course material
ODBC
Open DataBase Connectivity, is a standard database access method developed by the SQL Access group in
1992.
Introduction of ODBC made it possible to access any database from any application. ODBC manages to do
this by inserting a middle layer, called a database driver, between the application and the DBMS.
This layer translates the application's data queries into commands that the DBMS can understand.
Both the application and the DBMS must be ODBC-compliant to achieve this. On other words the
application must be capable of issuing ODBC commands and the DBMS must be capable of
responding to them.
ODBC is written in C language to allow the programmer to communicate with a database and also access
the metadata. Each vendor gives a specific driver to his or her database management system.
With ODBC together with sql you can connect to database and even manipulate the data in a standardized
way. This being the reason ODBC, although started as a PC standard, became almost an industry
standard.
SQL language is designed to work with a database, meaning the use of SQL is very much specific. It is not
possible to make a general-purpose application using SQL. Communication with the database could be
done using SQL but what about the GUI we want to create, which will give user the facility to interact with
the interface and sends the request to backend i.e. database. You require to take help of another language
to develop the gui and connect from that gui based interface to the database. To do this we require one
middle tier, which will be accepting the request entered from the interface and converting that to the
database understandable code. It then gives the converted code to the database. The processed result from
the database will be again picked up by this middle tier and converted to application understandable code.
This will be done by the middle tier ODBC.
One very important thing that you should remember is that a program written for one platform will not
run on another platform even though the database connectivity standardization issue has been resolved to
a large extent. For e.g. a database client written in C++ for Windows platform need to be entirely rewritten
when the client platform changes from Windows to Macintosh. Reasons behind this is C++ is not portable
as it does not give complete specification like how many bits will be used by an int datatype and secondly
libraries for supporting network access or GUI are different for every platform.
By now you know that Java programs are platform independent and a program created on one platform
can be easily run on any other platform without the requirement of recompilation. The Java API
includes the java.sql package as a core library, which makes it possible to work with JDBC. JDBC can
be thought of as a portable solution of ODBC. Writing the GUI as well as JDBC in java makes the
program truly portable.
As you know everything in Java is presented in a way of class. Similarly JDBC driver is also a class that
implements JDBC Driver interface. JDBC driver knows how to convert the program (which includes SQL in
291 | P a g e
360digrii
Java course material
it) request targeted towards a particular database. Drivers are the one, which makes the program work.
There are four types of drivers available. In this chapter we are going to use the 4th type of driver, as using
this driver will be very simple with no separate installation as well as the dynamic nature of this driver.
JDBC 1.0
The JDBC 1.0 API provided the basic framework for data access, which mainly consists of the following
interfaces and classes:
Driver
DriverManager
Connection
Statement
PreparedStatement
CallableStatement
ResultSet
DatabaseMetaData
ResultSetMetaData
Types
Steps to establish a connection and manipulate the data:
1. Pass a Driver to DriverManager to get connection to the database.
2. Out of the three interfaces Statement, preparedStatement and CallableStatement you have to create
reference of one of it.
3. After creating reference you can query the database or update the database depending on the
requirement.
4. Query will return the data in the form of reference to the ResultSet where the requested data is stored.
5. If further the program requires to know details about the database or a resultset you can use
ResultSetMetaData interface.
JDBC 2.0
The JDBC 2.0 API is broken into two parts: the core API, and the JDBC 2.0 Optional Package. The main
development done into JDBC 2.0 is addition of some extra classes. Main aim of JDBC 2.0 specification was
to have performance improvement and the new SQL3 (also known as SQL-99) datatypes. The functionality
includes
scrollable result sets
programmatic DML( insert, update and deletes, batch upates etc )
292 | P a g e
360digrii
Java course material
full precision for java.math.BigDecimal values
support for time zones in Date, Time, and Timestamp values.
JDBC 3.0
The JDBC API consists of the packages, interfaces and the classes that support Java database connectivity.
Some of them are discussed below. The java.sql package contains the classes and interfaces for Java
database connectivity.
The DriverManager class of java.sql package is responsible for selecting the database drivers and creating
a new database connection. However, before the driver manager can activate a driver, the driver must be
registered.
You can register a driver manually by loading its class using the “Class” class. For example, to load the
JDBC-ODBC Bridge driver, the command is as follows:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//force registration of driver
Note: In this chapter we will be using Type 4. Native-Protocol Pure Java Driver
After registering the drivers, you can open a database connection as shown in the following manner:
String url = ”jdbc:oracle:thin:@localhost:1521:orcl”;
String username = “scott”;
String password = “tiger”;
Connection con = DriverManager.getConnection( url, username, password);
The driver manager will try to locate a driver that can use the protocol specified in the database URL by
iterating through the available drivers
The getConnection() method
It is used to establish a connection to a database. The getConnection() method returns a Connection object.
You can use the Connection object to execute queries or action statements, and commit or rollback
transactions (transactions are explained later in the chapter).
The DriverManager class does not provide any constructor. All methods in this class are static. The
getConnection() method has the following forms:
getConnection(String url)
getConnection(String url, String userID, String password)
getConnection(String url, Properties arguments)
The getDrivers() and getConnection() methods are the most important methods of the DriverManager
class. The Other methods of DriverManager class are listed in Table 1.
293 | P a g e
360digrii
Java course material
Methods Description
getDriver() Returns a driver that can support a connection via the specified URL.
getDrivers() Returns an Enumeration with all of the currently loaded JDBC drivers.
getLoginTimeout() Gets the maximum time in seconds that a driver can wait when attempting to log in to a
database.
setLoginTimeout() Sets the maximum time in seconds that a driver will wait while attempting to connect to a
database.
setLogWriter(PrintWriter out) JDBC 2.0 Sets the logging/tracing Writer that is used by the DriverManager and all
drivers.
All JDBC drivers implement the Driver interface. The Driver interface provides methods that enable you
to write drivers. These methods are listed in Table 2.
Methods Description
connect() Attempts to make a database connection to the given URL.
acceptsURL(String URL) Returns true if the driver thinks that it can open a connection to
the given URL.
getPropertyInfo(String URL , Gets information about the possible properties for this driver.
Properties info)
294 | P a g e
360digrii
Java course material
The DriverPropertyInfo Class
The DriverPropertyInfo class has one constructor and does not provide a method. An array of objects of
the DriverPropertyInfo class is returned by the getPropertyInfo() method of the Driver class to provide
information about a driver. You can use this information to establish a database connection. To describe a
property of the driver the DriverPropertyInfo class provides the following five fields:
name : The properties name
description : A description of the property.
value : The current value of the property.
choices : A list of possible values.
required : A variable that indicates whether the property is required.
In the last section we went through getConnection() methods of the DriverManager class. The Connection
itself is responsible for several things , such as-
Creating Statement, PreparedStatement and CallableStatement instances.
Obtaining DatabaseMetadata objects.
Controlling transactions via the commit () and rollback() methods.
Setting the isolation level involved in transactions.
You can use the nativeSQL() method to obtain any SQL statement in a given database's native dialect. Some
of these areas are discussed in later sections of the chapter.
Before pushing forward the new ‘DataSource’ class introduced in the JDBC 2.0 Optional Package should be
mentioned. The specification recommends DataSource as the means for obtaining a Connection.Infact
actually talks about deprecating the current DriverManager class’s getConnection() method. While the
JDBC programmer should be aware of this movement, and may even use it -- most commonly in a J2EE
environment.
The getConnection() method of DriverManager class returns an object that implements the Connection
interface. This interface defines methods for interacting with the database via the established connection.
It also defines several constants that describe the manner in which the database supports the database
transactions.
The methods of the Connection interface are used to manage a database connection, obtain information
about a connection, rollback or commit database transactions and, prepare SQL statements for execution.
The following methods are defined by the Connection interface are listed in Table 3.
295 | P a g e
360digrii
Java course material
Methods Description
close() Releases a Connection to the database and JDBC resources
immediately.
Note: A number of methods are defined by the Connection interface. Refer the API documentation of the
Connection interface for a complete description.
With JDBC you will be able to get information about the structure of a database and its tables. For example,
in a particular database, information will be available to you about the list of tables or the column names
and types of any table. When implementing a database you will not find this information to be of any use.
After all, if you design the tables, you know the tables and their structure. Structural information is,
however, extremely useful for programmers who write tools that work with any database. The
DatabaseMetaData interface provides the information about the database to which a connection is
established. It defines several constants for describing database attributes and over 100 methods.
The key methods defined by the DatabaseMetaData interface are listed in Table 4.
296 | P a g e
360digrii
Java course material
Methods Description
getImportedKeys(String catalog, String Gets a description of the primary key columns that
schema, String table) are referenced by a table's foreign key columns
(the primary keys imported by a table).
Statement Interface
A Statement object is a container or transport mechanism to send/execute (normally) SQL statements and
retrieves any results via its associated Connection. As mentioned in Areas Controlled by the Connection
Interface, there are three types of Statements, including Prepared Statements and Callable Statements,
both of which are subinterfaces of Statement. As noted earlier, you do not create a new instance of
Statement, but instead, request the associated Connection to create one:
Statement stmt = con.createStatement();
The execute series are the most often used of Statement's methods:
executeQuery() is used to execute SQL statements that return a single ResultSet.
executeUpdate() is used to execute SQL statements that modify a table or values of columns in a
table and return the number of rows affected (which is zero in the case of DDL statements).
execute() can be used to execute any type of SQL statement, but is intended for those that can
return multiple results or values. execute() is not discussed further in the course.
To allow the maximum flexibility to work with various databases and data sources, JDBC places no
restriction on the kinds of SQL statements that a Statement can send. In fact, if the data source can
understand it (and this is a programmer responsibility), the statements do not even have to be SQL, which
raises some interesting possibilities. However, a driver that claims to be JDBC Compliant must support at
least ANSI SQL-92 entry level capabilities.
A Statement should automatically be closed when the connection is garbage collected, but you should close
it yourself as soon as it is no longer needed. The JDBC recommendation is to always close the Statement
explicitly.
297 | P a g e
360digrii
Java course material
The ResultSet Interface
When a database query is executed, the results of the query are returned as a table of data organized
according to rows and columns. The ResultSet interface is used to provide access to this tabular data.
ResulSet provides the access of one row at a time.
The most useful improvements in JDBC 2.0 are in the ResultSet interface. A ResultSet provides access to a
table of data. Executing a SQL statement usually generates a ResultSet object. A ResultSet object
maintains a pointer to a row within tabular results. The pointer is referred to a cursor. Initially the cursor
is positioned before the first row of the table. The next() method of the ResultSet interface is used to
move the cursor to the next row of the table. The next() method returns a boolean value that is true if the
next row is returned and false if the end of the table is reached. The next method is used to successively
step through the rows of the tabular results. You usually want the user to be able to move both forward
and backward in the result set. But in JDBC 1.0, there was no previous () method. If a programmer wanted
to implement backwards iteration, he had to manually cache the result set data. In JDBC 2.0 you can move
forward and backward through a result set and may jump to any position in the result set.
Key methods of interest defined by the ResultSet interface are listed in Table 5.
Methods Description
deleteRow() JDBC 2.0 Deletes the current row from the result set and the
underlying database.
findColumn(String Maps the given Resultset column name to its ResultSet column
columnName) index.
findColumn(String Maps the given Resultset column name to its ResultSet column
columnName) index.
next ( ) Moves the cursor down one row from its current position.
getInt(int columnIndex) Gets the value of a column in the current row as a Java int.
298 | P a g e
360digrii
Java course material
Methods Description
import java.sql.*;
import java.util.*;
class ResultSet1 {
public static void main(String args[]) {
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con=DriverManager.getConnection
(“jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM emp");
while(rs.next()){
String s=rs.getString("ENAME");
int n=rs.getInt("EMPNO");
System.out.println("Employee Name = " + s);
System.out.println("Employee Id = " + n);
299 | P a g e
360digrii
Java course material
}
con.close();
}catch(Exception ex){
System.out.println(ex);
System.exit(0);
}}}
Note: According to the URL we are connecting the local machine where the database is present. In case
you want to connect to any other database server then in place of “localhost” you have to mention
the machine name.
Structured Query Language is used to interact with database servers. SQL statements can be used to
populate the database, update or delete the existing database informations. The purpose of java.sql
package is to enable you to execute SQL statements from Java programs. This section describes the
JDBC API that is used to execute SQL statements.
The Statement Interface
The createStatement() method of the Connection interface returns the object of Statement interface.
Using this object you invoke the executeQuery() method of the Statement interface, the executeQuery()
method takes the SQL statement as an argument. This results in the query being processed by the database
and a ResultSet object being returned.
The Statement interface defines methods that are used to interact with databases via the execution of SQL
statements.
The key methods of the Statement interface are as follows (See Table 7)
Methods Description
The PreparedStatement interface extends the Statement interface. An SQL statement is pre-compiled
and stored in a PreparedStatement object. This object can be used to efficiently execute the SQL
statement multiple times. The Statement object enables you to manipulate a single record in a database.
When you work with multiple entries, make use of the PreparedStatement object. This object enables
you to retrieve, edit, or delete multiple records at a time.
For example:
Before executing the prepared statement we should supply values for the parameters using one of the
set() methods defined in the PreparedStatement interface.
First parameter
Value of the first parameter
ps.setString(1,”Tom”);
ps.setInt(2,101);
Here the first parameter of the setString() method refers to the query number of SQL statement and
second parameter is the requested value of the query.
Methods Description
getMetaData() Gets the number, types and properties of a
ResultSet's columns.
setInt(int parameterIndex, int x) Sets the designated parameter to a Java int value
301 | P a g e
360digrii
Java course material
setArray(int I, Array x ) Sets an array parameter
setObject(int parameterIndex, Sets the value of a parameter using an object; use the
object x) java.lang equivalent objects for integral values.
import java.sql.*;
import java.util.*;
class Prepare {
public static void main(String args[]) {
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection
con=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger");
Statement stmt = con.createStatement();
302 | P a g e
360digrii
Java course material
The CallableStatement Interface
A stored procedure call may take IN parameters, OUT Parameters, INOUT parameters.
The following code snippet creats a CallableStatement object.
CallableStatement cstmt=cn.prepareCall(“{call getTestData(?,?)}”);
Where the ? place holders are IN, OUT or INOUT, parameters depend on the stored procedure IN and OUT
parameters.
Passing IN parameters is done using set() methods. Each OUT parameter must be registered in a log file.
registerOutParameter() is used to register the out parameter values. A parameter that supplies input
as well as accepts output (an output parameter) requires a call to the set method and a call to
registerOutParameter().
303 | P a g e
360digrii
Java course material
Transaction Processing
Consider an example where the salaries of employees are processed. For salary processing, several tables
in a database need to be updated. The database supports online updating. In case of system crash or power
failure, the updation process stops. In such a condition you may loose the data.
Transaction processing was invented as a solution to this database updation problem. A transaction
consists of a group of related database operations. The SQL statements that make up a transaction update
the database at the same time, even though the statements are executed in sequence. The database does
not permanently update until they are committed. If an error occurs during the transaction, the SQL
statement that makes up the transaction can be rolled back. (See Fig 7)
Updated
SQL Query On Commit D/B
Database
to update the
table
Unchanged
On Rollback D/B
304 | P a g e
360digrii
Java course material
Parallel Transaction
Parallel transaction occurs when two separate transactions occur simultaneously. An SQL statement of
first transaction updates a row, and a second transaction performs a query that reads the changed row. If
first transaction is not yet been committed, what row value should be reported in the query? Transaction
isolation is used to resolve the conflicts between transactions.
Transaction Isolation
Higher levels of transaction isolation prevent conflicts occurring between concurrent transactions.
However this isolation results in reduced database performance.
The Connection interface defines constants that can be used to access transactions. At high level of
transaction isolation, transaction must occur in a serial fashion, eliminating concurrent database
transactions completely.
The following constants and methods are defined in the Connection interface to specify the transaction
isolation:
Methods Description
305 | P a g e
360digrii
Java course material
Java Database Connectivity Programs
Now you will see the Java programs performing database connectivity. Following are the programs that
connect a Java program to a database, insert values into a database, select values from a database, update a
database, and delete values from a database.
A JDBC Program
The JDBC code is relatively simple to understand. The following steps are used to connect a Java program
to a database:
Load the driver.
Open a connection to the database.
Execute SQL statement.
Close the connection.
1. Loading the Driver
The Class.forName() method is used for loading the Driver class, instantiating it and registering it with
the driver manager. The static method forName() of the class Class is used to load a driver. The method
forName() takes the driver name as its parameter.
Class.forName(“oracle.jdbc.driver.OracleDriver”);
2. Making the connection
A connection to the database is made by the static method getConnection() of the DriverManager class.
This method takes the database URL and optionally a user name and password as its parameters.
306 | P a g e
360digrii
Java course material
Selecting Values
You can select values from a table using the following lines of code:
ResultSet rs=stmt.executeQuery(“SELECT” + “ename, empno FROM emp”);
while(rs.next())
{
String s= rs.getString(“ename”);
int n = rs.getInt(“empno”);
System.out.println(s+ “-” + n);
}
Note: The next( ) method moves the cursor to the next row.
Similarly you can update and delete values from a table using the respective SQL statement.
4. Closing the Connection
It is important to close the connection to the database to protect the database from accidental changes
being made. Use the following code:
cn.close();
First you will create a database table named AccountHolder using JDBC. It contains the details of an
account holder in a bank.
import java.sql.*;
// The constructor
public BankAccCreate() {
}
void createDB() {
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con =
DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger");
Statement stmt = con.createStatement();
import java.sql.*;
// The constructor
public BankAccInsert() {
}
void insertDB() {
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con =
DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger");
Statement stmt = con.createStatement();
308 | P a g e
360digrii
Java course material
Example Selecting Values from a Table
Here is a program to select values from a table using JDBC. In this program you will store the result of the
select statement in a ResultSet object. Using this object you will traverse through the selected result and
display every item selected.
import java.sql.*;
// The Constructor
public BankAccSelect() {
}
void selectDB() {
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con =
DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger");
Statement stmt = con.createStatement();
309 | P a g e
360digrii
Java course material
Java-SQL Type Equivalence
JDBC provides generic SQL types by defining Types for conversion to standard Java types. In other words,
determining the types and methods needed is quite straightforward. The following two tables show the
normal ResultSet methods used to get each data type. Typically the setXXX() methods follow the same
patterns.
SQL Type Java Method
BIGINT getLong()
BINARY getBytes()
BIT getBoolean()
CHAR getString()
DATE getDate()
DECIMAL getBigDecimal()
DOUBLE getDouble()
FLOAT getDouble()
INTEGER getInt()
LONGVARBINARY getBytes()
LONGVARCHAR getString()
NUMERIC getBigDecimal()
OTHER getObject()
REAL getFloat()
SMALLINT getShort()
TIME getTime()
TIMESTAMP getTimestamp()
TINYINT getByte()
VARBINARY getBytes()
VARCHAR getString()
310 | P a g e
360digrii
Java course material
You can also use the ResultSet.getString() on the types mentioned above for display purposes. The only
possible exception is OTHER.
Handling exceptions or errors is a tedious and boring task for developers. A certain level of exception
handling is possible through JDBC. Now you will learn about exception handling through introduction to
three types of SQLExceptions.
SQL Exceptions
An SQLException is thrown by a number of methods in the java.sql package. Like any other exception, this
requires a try/catch block. What is the reason for this? Databases or driver errors like SQL syntax is
described by this. Note that the SQLException has additional methods providing further information, as
well as the standard getMessage() inherited from Throwable. Other additional methods are a method to
get (or chain) additional exceptions as well as a method to set an additional exception.
An SQLState identifier based on the X/Open SQL specification is returned by the getSQLState()
For retrieving the vendor-specific error code, you need to use the getErrorCode().
The next SQLException or null is returned by the getNextException() if there is not anything else.
Note here that there might be a number of things that can go wrong between your program and the
database. In this method all the problems that occur, can be tracked.
The programmer is allowed to add an SQLException to the chain if s/he wishes to use the
setNextException().
Note that these methods are not necessarily straightforward. For instance, a typical catch code might look
like:
try
{
// some DB work
} // end try
catch ( SQLException SQLe)
{
while( SQLe != null)
{
// do handling
SQLe = SQLe.getNextException();
}
} // end catch
What is a batch update? You have a batch update when a set of multiple update statements, submitted to
the database for processing as a batch. Why is it necessary? Because in some instances, it is more efficient
to send multiple update statements to the database together as a unit can that sending each of the update
311 | P a g e
360digrii
Java course material
statements separately. The JDBC 2.0 API provides this batch update facility –i.e. the ability to send updates
as a unit.
Using Statement Objects for Batch Updates
Updates with the method executeUpdate are submitted to the database individually by the Statement
objects in the JDBC 1.0 API. You can send multiple executeUpdate statements in the same transaction.
These statements are processed individually even if they are committed or rolled back as a unit. Note that
the interfaces that are derived from -Statement, PreparedStatement and CallableStatement- all have the
same capabilities and use their individual version of the executeUpdate.
Now the JDBC 2.0 API empowers Statement, PreparedStatement, and CallableStatement objects to
maintain a list of commands that can be submitted together as a batch. These are created with an initially
empty associated list. How do these methods work?
Examine the following example to understand batch updates. Suppose the coffee house owner wants to
start carrying flavored coffees and has determined that the best source for him is one of his current
supplies is Superior Coffee and he wants to add four new flavors to the table COFFEES. What is he doing?
He is inserting four new rows. (Note that since are only four new rows, updates might not significantly
improve the performance.) Note that the table COFFEES has five columns which are column COF_NAME of
type VARCHAR (32), column SUP_ID of type INTEGER, column PRICE of type FLOAT, column SALES of
type INTEGER, and column TOTAL of type INTEGER. Each new row that is inserted will have the values of
five columns in order. Look at the codes that are used for inserting the new rows as a batch:
con.setAutoCommit(false);
Scrollable ResultSets
So far you have seen that all ResultSets have been used in a sequential manner. This has been done by
obtaining rows from beginning to end using ResultSet.next(). ResultSets, like Statements, ResultSets, and
Interacting with a Database, are obtained via Statements. Here you normally use the method
312 | P a g e
360digrii
Java course material
executeQuery. So far you have created statements with the following method, i.e. the only one available in
JDBC 1.0:
stmt = con.createStatement();
which was the only method available in JDBC 1.0.
You, however, have a new method in JDBC. The advantage of this is that you are allowed to create
scrollable and/or ResultSets that can be updated:
createStatement(
int resultSetType,
int resultSetConcurrency )
ResultSetType
ResultSet.TYPE_FORWARD_ONLY: Same as in JDBC 1.0, this is the default. It allows only forward
movement and columns can be generally read only once. The ResultSet data is no longer available if
ResultSet.next() returns false, generally causing automatic closure.
ResultSet.TYPE_SCROLL_INSENSITIVE: This allows the creation of a ResultSet. The difference is
that in this ResultSet, the cursor is allowed to move backwards, forwards, and at random. Note that
this is static data. Changes made to the rows selected in the current ResultSet and in the database
are invisible. This indicates that the to data modification, the ResultSet is insensitive.
ResultSet.TYPE_SCROLL_SENSITIVE: With this you can create a ResultSet where also the can move
backwards, forwards, and at random. So what is the difference between
ResultSet.TYPE_SCROLL_SENSITIVE and
Reult.TYPE_SCROLL_INSENSITIVE? The difference is that the later allows a dynamic view of data
and changes made to the rows selected in the current ResultSet and in the database are visible
which also means that the data modification, the ResultSet is sensitive.
ResultSetConcurrency
ResultSet.CONCUR_READ_ONLY: This is default. This is also the same as it was in JDBC 1.0.
ResultSet.CONCUR_UPDATABLE: Programmatic data changes via new ResultSet methods and
positioning capabilities are allowed by this.
The requested ResultSet can supported by the driver. But even in those cases the requested ResultSet
might not be returned. If this happens, an SQLWarning on the connections needs to be issued by the
driver. You can acquire a scrollable ResultSet (like any other), normally via the Statement.executeQuery().
Note that, the following methods are available along with a scrollable ResultSet:
absolute()
afterLast()
beforeFirst()
first()
getRow()
isAfterLast()
313 | P a g e
360digrii
Java course material
isBeforeFirst()
isFirst()
isLast()
last()
moveToCurrentRow()--effectively valid only with an updatable ResultSet.
moveToInsertRow()--valid only with an updatable ResultSet.
previous()
relative()
Usage Notes
For scrollable ResultSets, driver capabilities and implementation levels vary and sometimes quite
significantly. (Refer to the Java documentation.) Meanwhile, consider a few other factors regarding the
usage of scrollable ResultSets:
Upon retrieval, a scrollable ResultSet is positioned just before the first row. Note that a
nonscrollable ResultSet is positioned similarly.
After all rows are retrieved, a statement is considered as complete. This takes place the last row is
reprieved by the ResultSet.next(). This is interpreted by some drivers as committing the Statement
at a time when autocommit is on. What is the outcome? The ResultSet is closed. Also an
SQLException is thrown on the next attempted access. Hence, set autocommit for portability.
Zero might by returned by ResultSet.getRow() at certain positions, or at all positions. This might
mean a lot of things. For instance, it is not reliable to use the ResultSet.last(), ResultSet.getRow()
sequence in order to obtain the number of rows across databases, or even drivers for the same
database.
If zero is passed, the ResultSet.absolute() throws an SQLException.
If zero is passed, the cursor position should not be changed by ResultSet.relative(). However, note
that the ResultSet.absolute() is called from the ResultSet.relative() by at least one vendor without
checking for a zero value. Can you imagine the outcome?
314 | P a g e
360digrii
Java course material
Chapter 14: Servlets
What are Servlets?
Java Servlets are programs that run on a Web or Application server and act as a middle layer between a
request coming from a Web browser or other HTTP client and databases or applications on the HTTP
server.
Using Servlets, you can collect input from users through web page forms, present records from a database
or another source, and create web pages dynamically.
Java Servlets often serve the same purpose as programs implemented using the Common Gateway
Interface (CGI). But Servlets offer several advantages in comparison with the CGI.
Servlets Architecture:
315 | P a g e
360digrii
Java course material
Servlets Tasks:
Read the explicit data sent by the clients (browsers). This includes an HTML form on a Web page or
it could also come from an applet or a custom HTTP client program.
Read the implicit HTTP request data sent by the clients (browsers). This includes cookies, media
types and compression schemes the browser understands, and so forth.
Process the data and generate the results. This process may require talking to a database, executing
an RMI or CORBA call, invoking a Web service, or computing the response directly.
Send the explicit data (i.e., the document) to the clients (browsers). This document can be sent in a
variety of formats, including text (HTML or XML), binary (GIF images), Excel, etc.
Send the implicit HTTP response to the clients (browsers). This includes telling the browsers or
other clients what type of document is being returned (e.g., HTML), setting cookies and caching
parameters, and other such tasks.
Servlets Packages:
Java Servlets are Java classes run by a web server that has an interpreter that supports the Java Servlet
specification.
Servlets can be created using the javax.servlet and javax.servlet.http packages, which are a standard
part of the Java's enterprise edition, an expanded version of the Java class library that supports large-scale
development projects.
Java servlets have been created and compiled just like any other Java class. After you install the servlet
packages and add them to your computer's Classpath, you can compile servlets with the JDK's Java
compiler or any other current compiler.
Servlet LifeCycle
The init method is designed to be called only once. It is called when the servlet is first created, and not
called again for each user request. So, it is used for one-time initializations, just as with the init method of
applets.
The servlet is normally created when a user first invokes a URL corresponding to the servlet, but you can
also specify that the servlet be loaded when the server is first started.
316 | P a g e
360digrii
Java course material
When a user invokes a servlet, a single instance of each servlet gets created, with each user request
resulting in a new thread that is handed off to doGet or doPost as appropriate. The init() method simply
creates or loads some data that will be used throughout the life of the servlet.
The service() method is the main method to perform the actual task. The servlet container (i.e. web
server) calls the service() method to handle requests coming from the client( browsers) and to write the
formatted response back to the client.
Each time the server receives a request for a servlet, the server spawns a new thread and calls service. The
service() method checks the HTTP request type (GET, POST, PUT, DELETE, etc.) and calls doGet, doPost,
doPut, doDelete, etc. methods as appropriate.
The service () method is called by the container and service method invokes doGe, doPost, doPut,
doDelete, etc. methods as appropriate. So you have nothing to do with service() method but you override
either doGet() or doPost() depending on what type of request you receive from the client.
The doGet() and doPost() are most frequently used methods with in each service request. Here are the
signature of these two methods.
A GET request results from a normal request for a URL or from an HTML form that has no METHOD
specified and it should be handled by doGet() method.
317 | P a g e
360digrii
Java course material
The doPost() Method
A POST request results from an HTML form that specifically lists POST as the METHOD and it should be
handled by doPost() method.
The destroy() method is called only once at the end of the life cycle of a servlet. This method gives your
servlet a chance to close database connections, halt background threads, write cookie lists or hit counts to
disk, and perform other such cleanup activities.
After the destroy() method is called, the servlet object is marked for garbage collection. The destroy
method definition looks like this:
Architecture Digram:
First the HTTP requests coming to the server are delegated to the servlet container.
The servlet container loads the servlet before invoking the service() method.
Then the servlet container handles multiple requests by spawning multiple threads, each thread
executing the service() method of a single instance of the servlet.
318 | P a g e
360digrii
Java course material
Servlets are Java classes which service HTTP requests and implement the javax.servlet.Servlet interface.
Web application developers typically write servlets that extend javax.servlet.http.HttpServlet, an abstract
class that implements the Servlet interface and is specially designed to handle HTTP requests.
Following is the sample source code structure of a servlet example to write Welcome:
319 | P a g e
360digrii
Java course material
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h3>" + message + "</h3>");
}
}
}
Servlet Deployment:
web.xml
<servlet>
<servlet-name>Welcome</servlet-name>
<servlet-class>WelcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Welcome</servlet-name>
<url-pattern>/Welcome</url-pattern>
</servlet-mapping>
You must have come across many situations when you need to pass some information from your browser
to web server and ultimately to your backend program. The browser uses two methods to pass this
information to web server. These methods are GET Method and POST Method.
GET method:
The GET method sends the encoded user information appended to the page request. The page and the
encoded information are separated by the ? character as follows:
320 | P a g e
360digrii
Java course material
http://www.test.com/hello?key1=value1&key2=value2
The GET method is the defualt method to pass information from browser to web server and it produces a
long string that appears in your browser's Location:box. Never use the GET method if you have password
or other sensitive information to pass to the server. The GET method has size limtation: only 1024
characters can be in a request string.
This information is passed using QUERY_STRING header and will be accessible through QUERY_STRING
environment variable and Servlet handles this type of requests using doGet() method.
POST method:
A generally more reliable method of passing information to a backend program is the POST method. This
packages the information in exactly the same way as GET methods, but instead of sending it as a text string
after a ? in the URL it sends it as a separate message. This message comes to the backend program in the
form of the standard input which you can parse and use for your processing. Servlet handles this type of
requests using doPost() method.
Servlets handles form data parsing automatically using the following methods depending on the situation:
getParameter(): You call request.getParameter() method to get the value of a form parameter.
getParameterValues(): Call this method if the parameter appears more than once and returns
multiple values, for example checkbox.
getParameterNames(): Call this method if you want a complete list of all parameters in the
current request.
Here is a simple URL which will pass two values to HelloForm program using GET method.
http://localhost:8080/HelloForm?first_name=ZARA&last_name=ALI
Below is HelloForm.java servlet program to handle input given by web browser. We are going to use
getParameter() method which makes it very easy to access passed information:
321 | P a g e
360digrii
Java course material
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// Set response content type
response.setContentType("text/html");
Here is a simple example which passes two values using HTML FORM and submit button. We are going to
use same Servlet HelloForm to handle this imput.
<html>
<body>
<form action="HelloForm" method="GET">
First Name: <input type="text" name="first_name">
<br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
322 | P a g e
360digrii
Java course material
Keep this HTML in a file Hello.htm and put it in <Tomcat-installation-directory>/webapps/ROOT
directory. When you would access http://localhost:8080/Hello.htm, here is the actual output of the above
form.
First Name:
Last Name:
Try to enter First Name and Last Name and then click submit button to see the result on your local
machine where tomcat is running. Based on the input provided, it will generate similar result as
mentioned in the above example.
Let us do little modification in the above servlet, so that it can handle GET as well as POST methods. Below
is HelloForm.java servlet program to handle input given by web browser using GET or POST methods.
323 | P a g e
360digrii
Java course material
" <li><b>First Name</b>: "
+ request.getParameter("first_name") + "\n" +
" <li><b>Last Name</b>: "
+ request.getParameter("last_name") + "\n" +
"</ul>\n" +
"</body></html>");
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Now compile, deploy the above Servlet and test it using Hello.htm with the POST method as follows:
<html>
<body>
<form action="HelloForm" method="POST">
First Name: <input type="text" name="first_name">
<br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
Here is the actual output of the above form, Try to enter First and Last Name and then click submit button
to see the result on your local machine where tomcat is running.
First Name:
Last Name:
Based on the input provided, it would generate similar result as mentioned in the above examples.
Checkboxes are used when more than one option is required to be selected.
Here is example HTML code, CheckBox.htm, for a form with two checkboxes
324 | P a g e
360digrii
Java course material
<html>
<body>
<form action="CheckBox" method="POST" target="_blank">
<input type="checkbox" name="maths" checked="checked" /> Maths
<input type="checkbox" name="physics" /> Physics
<input type="checkbox" name="chemistry" checked="checked" />
Chemistry
<input type="submit" value="Select Subject" />
</form>
</body>
</html>
Below is CheckBox.java servlet program to handle input given by web browser for checkbox button.
Maths Flag : : on
Physics Flag: : null
Chemistry Flag: : on
Once we have an Enumeration, we can loop down the Enumeration in the standard manner, using
hasMoreElements() method to determine when to stop and using nextElement() method to get each
parameter name.
326 | P a g e
360digrii
Java course material
// Extend HttpServlet class
public class ReadParams extends HttpServlet {
while(paramNames.hasMoreElements()) {
String paramName = (String)paramNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n<td>");
String[] paramValues =
request.getParameterValues(paramName);
// Read single valued data
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() == 0)
out.println("<i>No Value</i>");
else
out.println(paramValue);
} else {
// Read multiple valued data
out.println("<ul>");
for(int i=0; i < paramValues.length; i++) {
out.println("<li>" + paramValues[i]);
327 | P a g e
360digrii
Java course material
}
out.println("</ul>");
}
}
out.println("</tr>\n</table>\n</body></html>");
}
// Method to handle POST method request.
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<html>
<body>
<form action="ReadParams" method="POST" target="_blank">
<input type="checkbox" name="maths" checked="checked" /> Maths
<input type="checkbox" name="physics" /> Physics
<input type="checkbox" name="chemistry" checked="checked" /> Chem
<input type="submit" value="Select Subject" />
</form>
</body>
</html>
Now calling servlet using above form would generate following result:
maths on
chemistry on
You can try above servlet to read any other form's data which is having other objects like text box, radio
button or drop down box etc.
328 | P a g e
360digrii
Java course material
Servlet Filters
Servlet Filters are Java classes that can be used in Servlet Programming for the following purposes:
To intercept requests from a client before they access a resource at back end.
To manipulate responses from server before they are sent back to the client.
Authentication Filters.
Data compression Filters.
Encryption Filters.
Filters that trigger resource access events.
Image Conversion Filters.
Logging and Auditing Filters.
MIME-TYPE Chain Filters.
Tokenizing Filters .
XSL/T Filters That Transform XML Content.
Filters are deployed in the deployment descriptor file web.xml and then map to either servlet names or
URL patterns in your application's deployment descriptor.
When the web container starts up your web application, it creates an instance of each filter that you have
declared in the deployment descriptor. The filters execute in the order that they are declared in the
deployment descriptor.
A filter is simply a Java class that implements the javax.servlet.Filter interface. The javax.servlet.Filter
interface defines three methods:
329 | P a g e
360digrii
Java course material
Servlet Filter Example:
Following is the Servlet Filter Example that would print the clients IP address and current date time. This
example would give you basic understanding of Servlet Filter, but you can write more sophisticated filter
applications using the same concept:
Compile LogFilter.java in usual way and put your class file in <Tomcat-installation-
directory>/webapps/ROOT/WEB-INF/classes.
330 | P a g e
360digrii
Java course material
Servlet Filter Mapping in Web.xml:
Filters are defined and then mapped to a URL or Servlet, in much the same way as Servlet is defined and
then mapped to a URL pattern. Create the following entry for filter tag in the deployment descriptor file
web.xml
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>LogFilter</filter-class>
<init-param>
<param-name>test-param</param-name>
<param-value>Initialization Paramter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The above filter would apply to all the servlets because we specified /* in our configuration. You can
specicy a particular servlet path if you want to apply filter on few servlets only.
Now try to call any servlet in usual way and you would see generated log in your web server log. You can
use Log4J logger to log above log in a separate file.
Your web application may define several different filters with a specific purpose. Consider, you define two
filters AuthenFilter and LogFilter. Rest of the process would remain as explained above except you need to
create a different mapping as mentioned below:
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>LogFilter</filter-class>
<init-param>
<param-name>test-param</param-name>
<param-value>Initialization Paramter</param-value>
</init-param>
</filter>
<filter>
<filter-name>AuthenFilter</filter-name>
<filter-class>AuthenFilter</filter-class>
<init-param>
<param-name>test-param</param-name>
331 | P a g e
360digrii
Java course material
<param-value>Initialization Paramter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AuthenFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The order of filter-mapping elements in web.xml determines the order in which the web container applies
the filter to the servlet. To reverse the order of the filter, you just need to reverse the filter-mapping
elements in the web.xml file.
For example, above example would apply LogFilter first and then it would apply AuthenFilter to any
servlet but the following example would reverse the order:
<filter-mapping>
<filter-name>AuthenFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Cookies
Cookies are text files stored on the client computer and they are kept for various information tracking
purpose. Java Servlets transparently supports HTTP cookies.
Server script sends a set of cookies to the browser. For example name, age, or identification number
etc.
Browser stores this information on local machine for future use.
When next time browser sends any request to web server then it sends those cookies information
to the server and server uses that information to identify the user.
332 | P a g e
360digrii
Java course material
This chapter will teach you how to set or reset cookies, how to access them and how to delete them.
Cookies are usually set in an HTTP header (although JavaScript can also set a cookie directly on a
browser). A servlet that sets a cookie might send headers that look something like this:
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT;
path=/; domain=tutorialspoint.com
Connection: close
Content-Type: text/html
As you can see, the Set-Cookie header contains a name value pair, a GMT date, a path and a domain. The
name and value will be URL encoded. The expires field is an instruction to the browser to "forget" the
cookie after the given time and date.
If the browser is configured to store cookies, it will then keep this information until the expiry date. If the
user points the browser at any page that matches the path and domain of the cookie, it will resend the
cookie to the server. The browser's headers might look something like this:
GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz
A servlet will then have access to the cookie through the request method request.getCookies() which
returns an array of Cookie objects.
Following is the list of useful methods which you can use while manipulating cookies in servlet.
333 | P a g e
360digrii
Java course material
S.N. Method & Description
public void setDomain(String pattern)
1
This method sets the domain to which cookie applies, for example tutorialspoint.com.
public String getDomain()
2
This method gets the domain to which cookie applies, for example tutorialspoint.com.
public void setMaxAge(int expiry)
3 This method sets how much time (in seconds) should elapse before the cookie expires. If you don't
set this, the cookie will last only for the current session.
public int getMaxAge()
4 This method returns the maximum age of the cookie, specified in seconds, By default, -1 indicating
the cookie will persist until browser shutdown.
public String getName()
5
This method returns the name of the cookie. The name cannot be changed after creation.
public void setValue(String newValue)
6
This method sets the value associated with the cookie.
public String getValue()
7
This method gets the value associated with the cookie.
public void setPath(String uri)
8 This method sets the path to which this cookie applies. If you don't specify a path, the cookie is
returned for all URLs in the same directory as the current page as well as all subdirectories.
public String getPath()
9
This method gets the path to which this cookie applies.
public void setSecure(boolean flag)
10 This method sets the boolean value indicating whether the cookie should only be sent over
encrypted (i.e. SSL) connections.
public void setComment(String purpose)
11 This method specifies a comment that describes a cookie's purpose. The comment is useful if the
browser presents the cookie to the user.
public String getComment()
12 This method returns the comment describing the purpose of this cookie, or null if the cookie has no
comment.
(1) Creating a Cookie object: You call the Cookie constructor with a cookie name and a cookie value, both
of which are strings.
334 | P a g e
360digrii
Java course material
Keep in mind, neither the name nor the value should contain white space or any of the following
characters:
[]()=,"/?@:;
(2) Setting the maximum age: You use setMaxAge to specify how long (in seconds) the cookie should be
valid. Following would set up a cookie for 24 hours.
cookie.setMaxAge(60*60*24);
(3) Sending the Cookie into the HTTP response headers: You use response.addCookie to add cookies
in the HTTP response header as follows:
response.addCookie(cookie);
Example:
Let us modify our Form Example to set the cookies for first and last name.
335 | P a g e
360digrii
Java course material
// Set response content type
response.setContentType("text/html");
Compile above servlet HelloForm and create appropriate entry in web.xml file and finally try following
HTML page to call servlet.
<html>
<body>
<form action="HelloForm" method="GET">
First Name: <input type="text" name="first_name">
<br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
First Name:
Last Name:
336 | P a g e
360digrii
Java course material
Try to enter First Name and Last Name and then click submit button. This would display first name and
last name on your screen and same time it would set two cookies firstName and lastName which would be
passed back to the server when next time you would press Submit button.
Next section would explain you how you would access these cookies back in your web application.
To read cookies, you need to create an array of javax.servlet.http.Cookie objects by calling the getCookies(
) method of HttpServletRequest. Then cycle through the array, and use getName() and getValue() methods
to access each cookie and associated value.
Example:
Compile above servlet ReadCookies and create appropriate entry in web.xml file. If you would have set
first_name cookie as "Rakesh" and last_name cookie as "Kumar" then running
http://localhost:8080/ReadCookies would display the following result:
To delete cookies is very simple. If you want to delete a cookie then you simply need to follow up following
three steps:
Example:
Following example would delete and existing cookie named "first_name" and when you would run
ReadCookies servlet next time it would return null value for first_name.
338 | P a g e
360digrii
Java course material
// Extend HttpServlet class
public class DeleteCookies extends HttpServlet {
Now try to run http://localhost:8080/ReadCookies and it would display only one cookie as follows:
You can delete your cookies in Internet Explorer manually. Start at the Tools menu and select Internet
Options. To delete all cookies, press Delete Cookies.
HTTP is a "stateless" protocol which means each time a client retrieves a Web page, the client opens a
separate connection to the Web server and the server automatically does not keep any record of previous
client request.
Still there are following three ways to maintain session between web client and web server:
Cookies:
A webserver can assign a unique session ID as a cookie to each web client and for subsequent requests
from the client they can be recognized using the recieved cookie.
This may not be an effective way because many time browser does not support a cookie, so I would not
recommend to use this procedure to maintain the sessions.
A web server can send a hidden HTML form field along with a unique session ID as follows:
This entry means that, when the form is submitted, the specified name and value are automatically
included in the GET or POST data. Each time when web browser sends request back, then session_id value
can be used to keep the track of different web browsers.
340 | P a g e
360digrii
Java course material
This could be an effective way of keeping track of the session but clicking on a regular (<A HREF...>)
hypertext link does not result in a form submission, so hidden form fields also cannot support general
session tracking.
URL Rewriting:
You can append some extra data on the end of each URL that identifies the session, and the server can
associate that session identifier with data it has stored about that session.
URL rewriting is a better way to maintain sessions and works for the browsers when they don't support
cookies but here drawback is that you would have generate every URL dynamically to assign a session ID
though page is simple static HTML page.
Apart from the above mentioned three ways, servlet provides HttpSession Interface which provides a way
to identify a user across more than one page request or visit to a Web site and to store information about
that user.
The servlet container uses this interface to create a session between an HTTP client and an HTTP server.
The session persists for a specified time period, across more than one connection or page request from the
user.
You would get HttpSession object by calling the public method getSession() of HttpServletRequest, as
below:
You need to call request.getSession() before you send any document content to the client. Here is a
summary of the important methods available through HttpSession object:
341 | P a g e
360digrii
Java course material
public long getCreationTime()
3 This method returns the time when this session was created, measured in milliseconds since
midnight January 1, 1970 GMT.
This example describes how to use the HttpSession object to find out the creation time and the last-
accessed time for a session. We would associate a new session with the request if one does not already
exist.
String docType =
"<!doctype html public \"-//w3c//dtd html 4.0 " +
"transitional//en\">\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
343 | P a g e
360digrii
Java course material
"<h1 align=\"center\">" + title + "</h1>\n" +
"<h2 align=\"center\">Session Infomation</h2>\n" +
"<table border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +
" <th>Session info</th><th>value</th></tr>\n" +
"<tr>\n" +
" <td>id</td>\n" +
" <td>" + session.getId() + "</td></tr>\n" +
"<tr>\n" +
" <td>Creation Time</td>\n" +
" <td>" + createTime +
" </td></tr>\n" +
"<tr>\n" +
" <td>Time of Last Access</td>\n" +
" <td>" + lastAccessTime +
" </td></tr>\n" +
"<tr>\n" +
" <td>User ID</td>\n" +
" <td>" + userID +
" </td></tr>\n" +
"<tr>\n" +
" <td>Number of visits</td>\n" +
" <td>" + visitCount + "</td></tr>\n" +
"</table>\n" +
"</body></html>");
}
}
Compile above servlet SessionTrack and create appropriate entry in web.xml file. Now running
http://localhost:8080/SessionTrack would display the following result when you would run for the first
time:
Welcome to my website
Session Infomation
Session info value
id 0AE3EC93FF44E3C525B4351B77ABB2D5
344 | P a g e
360digrii
Java course material
User ID ABCD
Number of visits 0
Now try to run the same servlet for second time, it would display following result.
id 0AE3EC93FF44E3C525B4351B77ABB2D5
User ID ABCD
Number of visits 1
When you are done with a user's session data, you have several options:
Remove a particular attribute: You can call public void removeAttribute(String name) method to
delete the value associated with a particular key.
Delete the whole session: You can call public void invalidate() method to discard an entire session.
Setting Session timeout: You can call public void setMaxInactiveInterval(int interval) method to set
the timeout for a session individually.
Log the user out: The servers that support servlets 2.4, you can call logout to log the client out of
the Web server and invalidate all sessions belonging to all the users.
web.xml Configuration: If you are using Tomcat, apart from the above mentioned methods, you
can configure session time out in web.xml file as follows.
<session-config>
<session-timeout>15</session-timeout>
</session-config>
The timeout is expressed as minutes, and overrides the default timeout which is 30 minutes in Tomcat.
345 | P a g e
360digrii
Java course material
The getMaxInactiveInterval( ) method in a servlet returns the timeout period for that session in seconds.
So if your session is configured in web.xml for 15 minutes, getMaxInactiveInterval( ) returns 900.
The following HTML code below creates an uploader form. Following are the important points to be noted
down:
The form method attribute should be set to POST method and GET method can not be used.
The form enctype attribute should be set to multipart/form-data.
The form action attribute should be set to a servlet file which would handle file uploading at
backend server. Following example is using UploadServlet servlet to upload file.
To upload a single file you should use a single <input .../> tag with attribute type="file". To allow
multiple files uploading, include more than one input tags with different values for the name
attribute. The browser associates a Browse button with each of them.
<html>
<head>
<title>File Uploading Form</title>
</head>
<body>
<h3>File Upload:</h3>
Select a file to upload: <br />
<form action="UploadServlet" method="post"
enctype="multipart/form-data">
<input type="file" name="file" size="50" />
<br />
<input type="submit" value="Upload File" />
</form>
</body>
</html>
This will display following result which would allow to select a file from local PC and when user would
click at "Upload File", form would be submitted along with the selected file:
File Upload:
Select a file to upload:
346 | P a g e
360digrii
Java course material
NOTE: This is just dummy form and would not work.
Writing Backend Servlet:
Following is the servlet UploadServlet which would take care of accepting uploaded file and to store it in
directory <Tomcat-installation-directory>/webapps/data. This directory name could also be added using
an external configuration such as a context-param element in web.xml as follows:
<web-app>
....
<context-param>
<description>Location to store uploaded file</description>
<param-name>file-upload</param-name>
<param-value>
c:\apache-tomcat-5.5.29\webapps\data\
</param-value>
</context-param>
....
</web-app>
Following is the source code for UploadServlet which can handle multiple file uploading at a time. Before
procedding you have make sure the followings:
Following example depends on FileUpload, so make sure you have the latest version of commons-
fileupload.x.x.jar file in your classpath. You can download it from
http://commons.apache.org/fileupload/.
FileUpload depends on Commons IO, so make sure you have the latest version of commons-io-
x.x.jar file in your classpath. You can download it from http://commons.apache.org/io/.
While testing following example, you should upload a file which has less size than maxFileSize
otherwise file would not be uploaded.
Make sure you have created directories c:\temp and c:\apache-tomcat-5.5.29\webapps\data well
in advance.
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
347 | P a g e
360digrii
Java course material
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.output.*;
348 | P a g e
360digrii
Java course material
try{
// Parse the request to get file items.
List fileItems = upload.parseRequest(request);
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet upload</title>");
out.println("</head>");
out.println("<body>");
while ( i.hasNext () )
{
FileItem fi = (FileItem)i.next();
if ( !fi.isFormField () )
{
// Get the uploaded file parameters
String fieldName = fi.getFieldName();
String fileName = fi.getName();
String contentType = fi.getContentType();
boolean isInMemory = fi.isInMemory();
long sizeInBytes = fi.getSize();
// Write the file
if( fileName.lastIndexOf("\\") >= 0 ){
file = new File( filePath +
fileName.substring( fileName.lastIndexOf("\\"))) ;
}else{
file = new File( filePath +
fileName.substring(fileName.lastIndexOf("\\")+1)) ;
}
fi.write( file ) ;
out.println("Uploaded Filename: " + fileName + "<br>");
}
}
out.println("</body>");
out.println("</html>");
}catch(Exception ex) {
System.out.println(ex);
}
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, java.io.IOException {
349 | P a g e
360digrii
Java course material
throw new ServletException("GET method used with " +
getClass( ).getName( )+": POST method required.");
}
}
Compile and Running Servlet:
Compile above servlet UploadServlet and create required entry in web.xml file as follows.
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/UploadServlet</url-pattern>
</servlet-mapping>
Now try to upload files using the HTML form which you created above. When you would try
http://localhost:8080/UploadFile.htm, it would display following result which would help you uploading
any file from your local machine.
File Upload:
Select a file to upload:
Page Redirection
Page redirection is generally used when a document moves to a new location and we need to send the
client to this new location or may be because of load balancing, or for simple randomization.
The simplest way of redirecting a request to another page is using method sendRedirect() of response
object. Following is the signature of this method:
This method sends back the response to the browser along with the status code and new page location.
You can also use setStatus() and setHeader() methods together to achieve the same:
....
String site = "http://www.newpage.com" ;
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
....
350 | P a g e
360digrii
Java course material
Example:
This example shows how a servlet performs page redirection to an another location:
import java.io.*;
import java.sql.Date;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
}
}
Now let us compile above servlet and create following entries in web.xml
....
<servlet>
<servlet-name>PageRedirect</servlet-name>
<servlet-class>PageRedirect</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PageRedirect</servlet-name>
<url-pattern>/PageRedirect</url-pattern>
</servlet-mapping>
....
Now call this servlet using URL http://localhost:8080/PageRedirect. This would take you given URL
http://www.photofuntoos.com.
351 | P a g e
360digrii
Java course material
Hit Counter for a Web Page:
Many times you would be interested in knowing total number of hits on a particular page of your website.
It is very simple to count these hits using a servlet because the life cycle of a servlet is controlled by the
container in which it runs.
Following are the steps to be taken to implement a simple page hit counter which is based on Servlet Life
Cycle:
Here I'm assuming that the web container will not be restarted. If it is restarted or servlet destroyed, the
hit counter will be reset.
Example:
import java.io.*;
import java.sql.Date;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
}
public void destroy()
{
// This is optional step but if you like you
// can write hitCount value in your database.
}
}
Now let us compile above servlet and create following entries in web.xml
....
<servlet>
<servlet-name>PageHitCounter</servlet-name>
<servlet-class>PageHitCounter</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PageHitCounter</servlet-name>
<url-pattern>/PageHitCounter</url-pattern>
</servlet-mapping>
....
Now call this servlet using URL http://localhost:8080/PageHitCounter. This would increase counter by
one every time this page gets refreshed and it would display following result:
353 | P a g e
360digrii
Java course material
Total Number of Hits
6
Hit Counter for a Website:
Many times you would be interested in knowing total number of hits on your whole website. This is also
very simple in Servlet and we can achieve this using filters.
Following are the steps to be taken to implement a simple website hit counter which is based on Filter Life
Cycle:
Here I'm assuming that the web container will not be restarted. If it is restarted or servlet destroyed, the
hit counter will be reset.
Example:
354 | P a g e
360digrii
Java course material
// increase counter by one
hitCount++;
Now let us compile above servlet and create following entries in web.xml
....
<filter>
<filter-name>SiteHitCounter</filter-name>
<filter-class>SiteHitCounter</filter-class>
</filter>
<filter-mapping>
<filter-name>SiteHitCounter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
....
Now call any URL like URL http://localhost:8080/. This would increase counter by one every time any
page gets a hit and it would display following message in the log:
355 | P a g e
360digrii
Java course material
Consider a webpage which is displaying live game score or stock market status or currency exchange
ration. For all such type of pages, you would need to refresh your web page regularly using referesh or
reload button with your browser.
Java Servlet makes this job easy by providing you a mechanism where you can make a webpage in such a
way that it would refresh automatically after a given interval.
The simplest way of refreshing a web page is using method setIntHeader() of response object. Following
is the signature of this method:
This method sends back header "Refresh" to the browser along with an integer value which indicates time
interval in seconds.
This example shows how a servlet performs auto page refresh using setIntHeader() method to set
Refresh header.
Now let us compile above servlet and create following entries in web.xml
....
<servlet>
<servlet-name>Refresh</servlet-name>
<servlet-class>Refresh</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Refresh</servlet-name>
<url-pattern>/Refresh</url-pattern>
</servlet-mapping>
....
Now call this servlet using URL http://localhost:8080/Refresh which would display current system time
after every 5 seconds as follows. Just run the servlet and wait to see the result:
357 | P a g e
360digrii
Java course material
Chapter 15: Java Server Pages
JSP Overview
JavaServer Pages (JSP) is a server-side programming technology that enables the creation of dynamic,
platform-independent method for building Web-based applications.
JavaServer Pages (JSP) is a technology for developing web pages that support dynamic content which
helps developers insert java code in HTML pages by making use of special JSP tags, most of which start
with <% and end with %>.
A JavaServer Pages component is a type of Java servlet that is designed to fulfill the role of a user interface
for a Java web application. Web developers write JSPs as text files that combine HTML or XHTML code,
XML elements, and embedded JSP actions and commands.
Using JSP, you can collect input from users through web page forms, present records from a database or
another source, and create web pages dynamically.
JSP tags can be used for a variety of purposes, such as retrieving information from a database or
registering user preferences, accessing JavaBeans components, passing control between pages and sharing
information between requests, pages etc.
Performance is significantly better because JSP allows embedding Dynamic Elements in HTML
Pages itself.
JSP allows to separate the presentation logic and business logic
JSP are always compiled before it's processed by the server
JavaServer Pages are built on top of the Java Servlets API, so like Servlets, JSP also has access to all
the powerful Enterprise Java APIs, including JDBC, JNDI, EJB, JAXP etc.
JSP pages can be used in combination with servlets that handle the business logic, the model
supported by Java servlet template engines.
JSP Architeture:
The web server needs a JSP engine ie. container to process JSP pages. The JSP container is responsible for
intercepting requests for JSP pages. This tutorial makes use of Apache which has built-in JSP container to
support JSP pages development.
A JSP container works with the Web server to provide the runtime environment and other services a JSP
needs. It knows how to understand the special elements that are part of JSPs.
Following diagram shows the position of JSP container and JSP files in a Web Application.
358 | P a g e
360digrii
Java course material
JSP Processing:
The following steps explain how the web server creates the web page using JSP:
As with a normal page, your browser sends an HTTP request to the web server.
The web server recognizes that the HTTP request is for a JSP page and forwards it to a JSP engine.
This is done by using the URL or JSP page which ends with .jsp instead of .html.
The JSP engine loads the JSP page from disk and converts it into a servlet content. This conversion
is very simple in which all template text is converted to println( ) statements and all JSP elements
are converted to Java code that implements the corresponding dynamic behavior of the page.
The JSP engine compiles the servlet into an executable class and forwards the original request to a
servlet engine.
A part of the web server called the servlet engine loads the Servlet class and executes it. During
execution, the servlet produces an output in HTML format, which the servlet engine passes to the
web server inside an HTTP response.
The web server forwards the HTTP response to your browser in terms of static HTML content.
Finally web browser handles the dynamically generated HTML page inside the HTTP response
exactly as if it were a static page.
All the above mentioned steps can be shown below in the following diagram:
359 | P a g e
360digrii
Java course material
Typically, the JSP engine checks to see whether a servlet for a JSP file already exists and whether the
modification date on the JSP is older than the servlet. If the JSP is older than its generated servlet, the JSP
container assumes that the JSP hasn't changed and that the generated servlet still matches the JSP's
contents. This makes the process more efficient than with other scripting languages (such as PHP) and
therefore faster.
So in a way, a JSP page is really just another way to write a servlet without having to be a Java
programming wiz. Except for the translation phase, a JSP page is handled exactly like a regular servlet
A JSP life cycle can be defined as the entire process from its creation till the destruction which is similar to
a servlet life cycle with an additional step which is required to compile a JSP into servlet.
Compilation
Initialization
Execution
Cleanup
The three major phases of JSP life cycle are very similar to Servlet Life Cycle and they are as follows:
360 | P a g e
360digrii
Java course material
When a browser asks for a JSP, the JSP engine first checks to see whether it needs to compile the page. If
the page has never been compiled, or if the JSP has been modified since it was last compiled, the JSP engine
compiles the page.
When a container loads a JSP it invokes the jspInit() method before servicing any requests. If you need to
perform JSP-specific initialization, override the jspInit() method:
Typically initialization is performed only once and as with the servlet init method, you generally initialize
database connections, open files, and create lookup tables in the jspInit method.
361 | P a g e
360digrii
Java course material
(3) JSP Execution:
This phase of the JSP life cycle represents all interactions with requests until the JSP is destroyed.
Whenever a browser requests a JSP and the page has been loaded and initialized, the JSP engine invokes
the _jspService() method in the JSP.
The _jspService() method of a JSP is invoked once per a request and is responsible for generating the
response for that request and this method is also responsible for generating responses to all seven of the
HTTP methods ie. GET, POST, DELETE etc.
The destruction phase of the JSP life cycle represents when a JSP is being removed from use by a container.
The jspDestroy() method is the JSP equivalent of the destroy method for servlets. Override jspDestroy
when you need to perform any cleanup, such as releasing database connections or closing open files.
362 | P a g e
360digrii
Java course material
JSP Syntax
The Scriptlet:
A scriptlet can contain any number of JAVA language statements, variable or method declarations, or
expressions that are valid in the page scripting language.
Any text, HTML tags, or JSP elements you write must be outside the scriptlet. Following is the simple and
first example for JSP:
<html>
<head><title>Hello World</title></head>
<body>
Hello World!<br/>
<%
out.println("Welcome to JSP”);
%>
</body>
</html>
JSP Declarations:
A declaration declares one or more variables or methods that you can use in Java code later in the JSP file.
You must declare the variable or method before you use it in the JSP file.
363 | P a g e
360digrii
Java course material
}%
JSP Expression:
A JSP expression element contains a scripting language expression that is evaluated, converted to a String,
and inserted where the expression appears in the JSP file.
Because the value of an expression is converted to a String, you can use an expression within a line of text,
whether or not it is tagged with HTML, in a JSP file.
The expression element can contain any expression that is valid according to the Java Language
Specification but you cannot use a semicolon to end an expression.
Example:
<body>
</body>
JSP Directives:
A JSP directive affects the overall structure of the servlet class. It usually has the following form:
364 | P a g e
360digrii
Java course material
Directive Description
<%@ page ... %> Defines page-dependent attributes, such as scripting language, error page,
and buffering requirements.
<%@ include ... %> Includes a file during the translation phase.
<%@ taglib ... %> Declares a tag library, containing custom actions, used in the page
The page directive is used to provide instructions to the container that pertain to the current JSP page.
You may code page directives anywhere in your JSP page. By convention, page directives are coded at the
top of the JSP page.
Attribute Purpose
errorPage Defines the URL of another JSP that reports on Java unchecked runtime
exceptions.
isErrorPage Indicates if this JSP page is a URL specified by another JSP page's
errorPage attribute.
365 | P a g e
360digrii
Java course material
extends Specifies a superclass that the generated servlet must extend
import Specifies a list of packages or classes for use in the JSP as the Java import
statement does for Java classes.
info Defines a string that can be accessed with the servlet's getServletInfo()
method.
session Specifies whether or not the JSP page participates in HTTP sessions
isELIgnored Specifies whether or not EL expression within the JSP page will be
ignored.
The buffer attribute specifies buffering characteristics for the server output response object.
You may code a value of "none" to specify no buffering so that all servlet output is immediately directed to
the response object or you may code a maximum buffer size in kilobytes, which directs the servlet to write
to the buffer before writing to the response object.
To direct the servlet to write output directly to the response output object, use the following:
Use the following to direct the servlet to write output to a buffer of size not less than 8 kilobytes:
366 | P a g e
360digrii
Java course material
The autoFlush attribute specifies whether buffered output should be flushed automatically when the
buffer is filled, or whether an exception should be raised to indicate buffer overflow.
A value of true (default) indicates automatic buffer flushing and a value of false throws an exception.
The following directive causes the servlet to throw an exception when the servlet's output buffer is full:
This directive causes the servlet to flush the output buffer when full:
Usually, the buffer and autoFlush attributes are coded on a single page directive as follows:
The contentType attribute sets the character encoding for the JSP page and for the generated response
page. The default content type is text/html, which is the standard content type for HTML pages.
If you want to write out XML from your JSP, use the following page directive:
The following statement directs the browser to render the generated page as HTML:
The following directive sets the content type as a Microsoft Word document:
You can also specify the character encoding for the response. For example, if you wanted to specify that
the resulting page that is returned to the browser uses ISO Latin 1, you would use the following page
directive:
367 | P a g e
360digrii
Java course material
The errorPage Attribute:
The errorPage attribute tells the JSP engine which page to display if there is an error while the current
page runs. The value of the errorPage attribute is a relative URL.
The following directive displays MyErrorPage.jsp when all uncaught exceptions are thrown:
The isErrorPage attribute indicates that the current JSP can be used as the error page for another JSP.
The value of isErrorPage is either true or false. The default value of the isErrorPage attribute is false.
For example, the handleError.jsp sets the isErrorPage option to true because it is supposed to handle
errors:
The extends attribute specifies a superclass that the generated servlet must extend.
For example, the following directive directs the JSP translator to generate the servlet such that the servlet
extends somePackage.SomeClass:
The import attribute serves the same function as, and behaves like, the Java import statement. The value
for the import option is the name of the package you want to import.
To import multiple packages you can specify them separated by comma as follows:
368 | P a g e
360digrii
Java course material
By default, a container automatically imports java.lang.*, javax.servlet.*, javax.servlet.jsp.*, and
javax.servlet.http.*.
The info attribute lets you provide a description of the JSP. The following is a coding example:
The isThreadSafe option marks a page as being thread-safe. By default, all JSPs are considered thread-safe.
If you set the isThreadSafe option to false, the JSP engine makes sure that only one thread at a time is
executing your JSP.
The language attribute indicates the programming language used in scripting the JSP page.
For example, because you usually use Java as the scripting language, your language option looks like this:
The session attribute indicates whether or not the JSP page uses HTTP sessions. A value of true means that
the JSP page has access to a builtin session object and a value of false means that the JSP page cannot
access the builtin session object.
Following directive allows the JSP page to use any of the builtin object session methods such as
session.getCreationTime() or session.getLastAccessTime():
369 | P a g e
360digrii
Java course material
The isELIgnored option gives you the ability to disable the evaluation of Expression Language (EL)
expressions which has been introduced in JSP 2.0
The default value of the attribute is true, meaning that expressions, ${...}, are evaluated as dictated by the
JSP specification. If the attribute is set to false, then expressions are not evaluated but rather treated as
static text.
The isScriptingEnabled attribute determines if scripting elements are allowed for use.
The default value (true) enables scriptlets, expressions, and declarations. If the attribute's value is set to
false, a translation-time error will be raised if the JSP uses any scriptlets, expressions (non-EL), or
declarations.
You can set this value to false if you want to restrict usage of scriptlets, expressions (non-EL), or
declarations:
The include directive is used to includes a file during the translation phase. This directive tells the
container to merge the content of other external files with the current JSP during the translation phase.
You may code include directives anywhere in your JSP page.
Example:
A good example of include directive is including a common header and footer with multiple pages of
content.
Let us define following three files (a) header.jps (b)footer.jsp and (c)main.jsp as follows:
370 | P a g e
360digrii
Java course material
<%!
int pageCount = 0;
void addCount() {
pageCount++;
}
%>
<% addCount(); %>
<html>
<head>
<title>The include Directive Example</title>
</head>
<body>
<center>
<h2>The include Directive Example</h2>
<p>This site has been visited <%= pageCount %> times.</p>
</center>
<br/><br/>
<br/><br/>
<center>
<p>Copyright © 2010</p>
</center>
</body>
</html>
Now let us keep all these files in root directory and try to access main.jsp. This would display follow result:
371 | P a g e
360digrii
Java course material
The include Directive Example
Copyright © 2010
The JavaServer Pages API allows you to define custom JSP tags that look like HTML or XML tags and a tag
library is a set of user-defined tags that implement custom behavior.
The taglib directive declares that your JSP page uses a set of custom tags, identifies the location of the
library, and provides a means for identifying the custom tags in your JSP page.
Where the uri attribute value resolves to a location the container understands and the prefix attribute
informs a container what bits of markup are custom actions.
JSP Implicit Objects are the Java objects that the JSP Container makes available to developers in each page
and developer can call them directly without being explicitly declared. JSP Implicit Objects are also called
pre-defined variables.
Object Description
request This is the HttpServletRequest object associated with the request.
response This is the HttpServletResponse object associated with the response to
the client.
out This is the PrintWriter object used to send output to the client.
session This is the HttpSession object associated with the request.
application This is the ServletContext object associated with application context.
372 | P a g e
360digrii
Java course material
config This is the ServletConfig object associated with the page.
pageContext This encapsulates use of server-specific features like higher performance
JspWriters.
page This is simply a synonym for this, and is used to call the methods defined
by the translated servlet class.
Exception The Exception object allows the exception data to be accessed by
designated JSP.
The request object provides methods to get HTTP header information including form data, cookies, HTTP
methods etc.
The response object also defines the interfaces that deal with creating new HTTP headers. Through this
object the JSP programmer can add new cookies or date stamps, HTTP status codes etc.
The out implicit object is an instance of a javax.servlet.jsp.JspWriter object and is used to send content in a
response.
The initial JspWriter object is instantiated differently depending on whether the page is buffered or not.
Buffering can be easily turned off by using the buffered='false' attribute of the page directive.
The JspWriter object contains most of the same methods as the java.io.PrintWriter class. However,
JspWriter has some additional methods designed to deal with buffering. Unlike the PrintWriter object,
JspWriter throws IOExceptions.
Following are the important methods which we would use to write boolean char, int, double, object, String
etc.
373 | P a g e
360digrii
Java course material
Method Description
out.print(dataType dt) Print a data type value
out.println(dataType dt) Print a data type value then terminate the line with new line
character.
out.flush() Flush the stream.
The session object is an instance of javax.servlet.http.HttpSession and behaves exactly the same way that
session objects behave under Java Servlets.
The session object is used to track client session between client requests.
The application object is direct wrapper around the ServletContext object for the generated Servlet and in
reality an instance of a javax.servlet.ServletContext object.
This object is a representation of the JSP page through its entire lifecycle. This object is created when the
JSP page is initialized and will be removed when the JSP page is removed by the jspDestroy() method.
By adding an attribute to application, you can ensure that all JSP files that make up your web application
have access to it.
The config object is an instantiation of javax.servlet.ServletConfig and is a direct wrapper around the
ServletConfig object for the generated servlet.
This object allows the JSP programmer access to the Servlet or JSP engine initialization parameters such as
the paths or file locations etc.
The following config method is the only one you might ever use, and its usage is trivial:
config.getServletName();
This returns the servlet name, which is the string contained in the <servlet-name> element defined in the
WEB-INF\web.xml file
374 | P a g e
360digrii
Java course material
The pageContext Object:
This object is intended as a means to access information about the page while avoiding most of the
implementation details.
This object stores references to the request and response objects for each request. The application, config,
session, and out objects are derived by accessing attributes of this object.
The pageContext object also contains information about the directives issued to the JSP page, including the
buffering information, the errorPageURL, and page scope.
The PageContext class defines several fields, including PAGE_SCOPE, REQUEST_SCOPE, SESSION_SCOPE,
and APPLICATION_SCOPE, which identify the four scopes. It also supports more than 40 methods, about
half of which are inherited from the javax.servlet.jsp. JspContext class.
One of the important methods is removeAttribute, which accepts either one or two arguments. For
example, pageContext.removeAttribute ("attrName") removes the attribute from all scopes, while the
following code only removes it from the page scope:
pageContext.removeAttribute("attrName", PAGE_SCOPE);
This object is an actual reference to the instance of the page. It can be thought of as an object that
represents the entire JSP page.
The page object is really a direct synonym for the this object.
The exception object is a wrapper containing the exception thrown from the previous page. It is typically
used to generate an appropriate response to the error condition.
The exception object is an instance of a subclass of Throwable (e.g., java.lang. NullPointerException) and is
only available in error pages. Following is the list of important medthods available in the Throwable class.
375 | P a g e
360digrii
Java course material
SN Methods with Description
1 public String getMessage()
Returns a detailed message about the exception that has occurred. This message is initialized in the
Throwable constructor.
2 public Throwable getCause()
Returns the cause of the exception as represented by a Throwable object.
3 public String toString()
Returns the name of the class concatenated with the result of getMessage()
4 public void printStackTrace()
Prints the result of toString() along with the stack trace to System.err, the error output stream.
5 public StackTraceElement [] getStackTrace()
Returns an array containing each element on the stack trace. The element at index 0 represents the
top of the call stack, and the last element in the array represents the method at the bottom of the call
stack.
6 public Throwable fillInStackTrace()
Fills the stack trace of this Throwable object with the current stack trace, adding to any previous
information in the stack trace.
JSP gives you an option to specify Error Page for each JSP. Whenever the page throws an exception, the JSP
container automatically invokes the error page.
Following is an example to specifiy an error page for a main.jsp. To set up an error page, use the <%@
page errorPage="xxx" %> directive.
<html>
<head>
<title>Error Handling Example</title>
</head>
<body>
<%
// Throw an exception to invoke the error page
int x = 1;
if (x == 1)
{
throw new RuntimeException("Error condition!!!");
}
%>
</body>
</html>
376 | P a g e
360digrii
Java course material
Now you would have to write one Error Handling JSP ShowError.jsp, which is given below. Notice that the
error-handling page includes the directive <%@ page isErrorPage="true" %>. This directive causes the JSP
compiler to generate the exception instance variable.
Opps...
Sorry, an error occurred.
JSP Actions
JSP actions use constructs in XML syntax to control the behavior of the servlet engine. You can dynamically
insert a file, reuse JavaBeans components, forward the user to another page, or generate HTML for the Java
plugin.
There is only one syntax for the Action element, as it conforms to the XML standard:
Action elements are basically predefined functions and there are following JSP actions available:
377 | P a g e
360digrii
Java course material
Syntax Purpose
jsp:plugin Generates browser-specific code that makes an OBJECT or EMBED tag for
the Java plugin
Common Attributes:
There are two attributes that are common to all Action elements: the id attribute and the scope attribute.
Id attribute: The id attribute uniquely identifies the Action element, and allows the action to be
referenced inside the JSP page. If the Action creates an instance of an object the id value can be used
to reference it through the implicit object PageContext
Scope attribute: This attribute identifies the lifecycle of the Action element. The id attribute and
the scope attribute are directly related, as the scope attribute determines the lifespan of the object
associated with the id. The scope attribute has four possible values: (a) page, (b)request, (c)session,
and (d) application.
378 | P a g e
360digrii
Java course material
The <jsp:include> Action
This action lets you insert files into the page being generated. The syntax looks like this:
Unlike the include directive, which inserts the file at the time the JSP page is translated into a servlet, this
action inserts the file at the time the page is requested.
Attribute Description
flush The boolean attribute determines whether the included resource has its
buffer flushed before it is included.
Example:
Let us define following two files (a)date.jps and (b) main.jsp as follows:
<p>
Today's date: <%= (new java.util.Date()).toLocaleString()%>
</p>
<html>
<head>
<title>The include Action Example</title>
</head>
<body>
<center>
<h2>The include action Example</h2>
<jsp:include page="date.jsp" flush="true" />
</center>
</body>
</html>
379 | P a g e
360digrii
Java course material
Now let us keep all these files in root directory and try to access main.jsp. This would display result
something like this:
The useBean action is quite versatile. It first searches for an existing object utilizing the id and scope
variables. If an object is not found, it then tries to create the specified object.
Once a bean class is loaded, you can use jsp:setProperty and jsp:getProperty actions to modify and
retrieve bean properties.
Attribute Description
type Specifies the type of the variable that will refer to the object.
beanName Gives the name of the bean as specified by the instantiate () method of the
java.beans.Beans class.
Let us discuss about jsp:setProperty and jsp:getProperty actions before giving a valid example related to
these actions.
The setProperty action sets the properties of a Bean. The Bean must have been previously defined before
this action. There are two basic ways to use the setProperty action:
You can use jsp:setProperty after, but outside of, a jsp:useBean element, as below:
380 | P a g e
360digrii
Java course material
<jsp:useBean id="myName" ... />
...
<jsp:setProperty name="myName" property="someProperty" .../>
In this case, the jsp:setProperty is executed regardless of whether a new bean was instantiated or an
existing bean was found.
A second context in which jsp:setProperty can appear is inside the body of a jsp:useBean element, as
below:
Here, the jsp:setProperty is executed only if a new object was instantiated, not if an existing one was
found.
Attribute Description
name Designates the bean whose property will be set. The Bean must have been
previously defined.
property Indicates the property you want to set. A value of "*" means that all
request parameters whose names match bean property names will be
passed to the appropriate setter methods.
value The value that is to be assigned to the given property. The the parameter's
value is null, or the parameter does not exist, the setProperty action is
ignored.
param The param attribute is the name of the request parameter whose value
the property is to receive. You can't use both value and param, but it is
permissible to use neither.
381 | P a g e
360digrii
Java course material
The <jsp:getProperty> Action
The getProperty action is used to retrieve the value of a given property and converts it to a string, and
finally inserts it into the output.
The getProperty action has only two attributes, both of which are required ans simple syntax is as follows:
Attribute Description
name The name of the Bean that has a property to be retrieved. The Bean must
have been previously defined.
property The property attribute is the name of the Bean property to be retrieved.
Example:
/* File: TestBean.java */
package action;
382 | P a g e
360digrii
Java course material
Compile above code to generated TestBean.class file and make sure that you copied TestBean.class in
C:\apache-tomcat-7.0.2\webapps\WEB-INF\classes\action folder and CLASSPATH variable should also be
set to this folder:
Now use the following code in main.jsp file which loads the bean and sets/gets a simple String parameter:
<html>
<head>
<title>Using JavaBeans in JSP</title>
</head>
<body>
<center>
<h2>Using JavaBeans in JSP</h2>
<jsp:setProperty name="test"
property="message"
value="Hello JSP..." />
<p>Got message....</p>
</center>
</body>
</html>
The forward action terminates the action of the current page and forwards the request to another
resource such as a static page, another JSP page, or a Java Servlet.
383 | P a g e
360digrii
Java course material
Following is the list of required attributes associated with forward action:
Attribute Description
page Should consist of a relative URL of another resource such as a static page,
another JSP page, or a Java Servlet.
Example:
Let us reuse following two files (a) date.jps and (b) main.jsp as follows:
<p>
Today's date: <%= (new java.util.Date()).toLocaleString()%>
</p>
<html>
<head>
<title>The include Action Example</title>
</head>
<body>
<center>
<h2>The include action Example</h2>
<jsp:forward page="date.jsp" />
</center>
</body>
</html>
Now let us keep all these files in root directory and try to access main.jsp. This would display result
something like as below. Here it discarded content from main page and displayed content from forwarded
page only.
384 | P a g e
360digrii
Java course material
The <jsp:plugin> Action
The plugin action is used to insert Java components into a JSP page. It determines the type of browser and
inserts the <object> or <embed> tags as needed.
If the needed plugin is not present, it downloads the plugin and then executes the Java component. The
Java component can be either an Applet or a JavaBean.
The plugin action has several attributes that correspond to common HTML tags used to format Java
components. The <param> element can also be used to send parameters to the Applet or Bean.
<jsp:fallback>
Unable to initialize Java Plugin
</jsp:fallback>
</jsp:plugin>
You can try this action using some applet if you are interested. A new element, the <fallback> element, can
be used to specify an error string to be sent to the user in case the component fails.
The <jsp:element>, lt;jsp:attribute> and <jsp:body> actions are used to define XML elements dynamically.
The word dynamically is important, because it means that the XML elements can be generated at request
time rather than statically at compile time.
385 | P a g e
360digrii
Java course material
<jsp:element name="xmlElement">
<jsp:attribute name="xmlElementAttr">
Value for the attribute
</jsp:attribute>
<jsp:body>
Body for XML element
</jsp:body>
</jsp:element>
</body>
</html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:jsp="http://java.sun.com/JSP/Page">
The <jsp:text> action can be used to write template text in JSP pages and documents. Following is the
simple syntax for this action:
<jsp:text>Template data</jsp:text>
The body fo the template cannot contain other elements; it can only contain text and EL expressions (
Note: EL expressions are explained in subsequent chapter). Note that in XML files, you cannot use
expressions such as ${whatever > 0}, because the greater than signs are illegal. Instead, use the gt form,
such as ${whatever gt 0} or an alternative is to embed the value in a CDATA section.
<jsp:text><![CDATA[<br>]]></jsp:text>
If you need to include a DOCTYPE declaration, for instance for XHTML, you must also use the <jsp:text>
element as follows:
<jsp:text><![CDATA[<!DOCTYPE html
386 | P a g e
360digrii
Java course material
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">]]>
</jsp:text>
<head><title>jsp:text action</title></head>
<body>
<books><book><jsp:text>
Welcome to JSP Programming
</jsp:text></book></books>
</body>
</html>
387 | P a g e