Sei sulla pagina 1di 412

Index

Chapter 1 : Java Technology 7


1.1 History of Java 7
1.2 What is Java? 8
1.3 Versions of Java 8
1.4 Code Compatibility 11
1.5 Java 5.0 Improvements 11
1.6 Features of Java 12
1.7 Java Applets and Applications 14
1.8 Why Java is important to Internet? 14
1.9 The Java Platform 15
1.10 What Can Java Technology Do? 16
1.11 Writing a Program 17
1.12 Compiling the Program 17
1.13 Interpreting and Running the Program 17
1.14 Comments in Java 17
1.15 Application Structure and Elements 19
Summary 19

Chapter 2 : Data types, variables and Arrays 20


2.1 Data Types 20
2.2 Literals 21
2.3 Java Character Encoding: UTF and Unicode 21
2.4 EscapeSequences 22
2.5 Rules for naming an identifier 22
2.6 Java Language Keywords 23
2.7 Variables 23
2.8 Declaring constants – Final variables 24
2.9 Arrays 24
2.10 Multidimensional Arrays 26
2.11 Copying Arrays 27
Summary 28
Questions 29

Chapter 3 : Operators 31
3.1 Operands 31
3.2 Operator 31
3.2.1 Arithmetic Operators 32
3.2.2 Increment and Decrement Operators 34
3.2.3 Relational Operators 34
3.2.4 Bitwise Operators 36
3.2.5 Logical Operators 38
3.2.6 Assignment Operators 41

1
3.2.7 Ternary or Conditional operator 42
3.2.8 The [ ] Operator 43
3.2.9 The . Operator 44
3.2.10 The () Operator 44
3.2.11 The (type) Operator 44
3.2.12 The new Operator 44
3.2.13 The instanceof Operator 44
3.3 Expressions 44
3.4 Statements 45
3.5 Operator Precedence 45
3.6 Type Conversion and Casting 47
3.7 Automatic Type Promotions 50
Summary 51
Questions 51

Chapter 4 : Control flow statements 54


4.1 The while and do-while Statements 54
4.2 The for Statement 55
4.3 The if/else Statements 57
4.4 The switch Statement 60
4.5 Branching Statements 62
4.5.1 The break Statement 62
4.5.2 The continue Statement 64
4.5.3 The return Statement 65
4.6 Exception Handling Statements 65
Summary 66
Questions 67

Chapter 5 : Class Fundamentals and OOP 69


5.1 What Is an Object? 69
5.2 What Is a Class? 70
5.3 What Is a Message? 70
5.4 Features of Object Oriented Programming 71
5.4.1 Encapsulation 71
5.4.2 Inheritance 72
5.4.3 Polymorphism 73
5.4.4 Abstraction 74
5.5 Defining Classes 74
5.6 Creating Objects 74
5.7 Defining Methods in a class 75
5.8 Declaring Variables in a Class 80
5.9 Instance and Class Members 83
5.10 Static Initializer 88
5.11 Variable Shadowing 90
5.12 Pass by value and Pass by reference 90
5.13 Access Control 94

2
5.14 Constructors 98
5.15 The this keyword 100
5.16 Overloading 100
5.17 Recursion 103
5.18 Native Methods 104
5.19 Arrays of Objects 104
5.20 Nested and Inner Classes 105
5.21 Command-Line Arguments 110
5.22 Enumerated types 112
5.23 Garbage Collection 115
Summary 116
Questions 117

Chapter 6 : Inheritance 122


6.1 Inheritance Basics 122
6.2 Understanding how Constructors are called 125
6.3 Overriding Methods 129
6.4 Dynamic Method Dispatch 133
6.5 Annotations 134
6.6 Hiding Member Variables 136
6.7 Abstract Classes 137
6.8 Abstract Methods 138
6.9 Final Classes 140
6.10 Final Methods 142
6.11 Access control and Inheritance 143
6.12 Anonymous Inner Class 143
6.13 The Object class 145
Summary 149
Questions 150

Chapter 7 : Packages and Interfaces 152


7.1 Packages 152
7.2 Using package members 155
7.3 Interfaces 158
7.4 Static Import 163
7.5 strictfp 165
Summary 167
Questions 167

Chapter 8 : Assertions and Exception handling 169


8.1 What is an Exception? 169
8.2 Types of Exceptions 174
8.3 Catching and Handling Exceptions 176
8.4 The throw Statement 181
8.5 The throws Clause 184
8.6 Overriding methods that throw exceptions 185

3
8.7 Java’s built in exceptions 185
8.8 Chained Exceptions 189
8.9 Creating Your Own Exception Classes 192
8.10 Assertions 194
Summary 197
Questions 197

Chapter 9 : Multithreaded programming 200


9.1 Multitasking 200
9.2 What Is a Thread? 201
9.3 The Thread class 203
9.4 Using the main thread 204
9.5 Creating a thread 205
9.6 The Java Thread Model 208
9.7 Thread priority 210
9.8 Using the Thread yield method. 212
9.9 Stopping a Thread 213
9.10 Determining When a Thread Has Finished 214
9.11 Thread Scheduling 215
9.12 Thread Synchronization 217
9.13 Interthread Communication 224
9.14 Starvation and Deadlock 227
9.15 Suspending, Resuming & Stopping Threads 228
9.16 ThreadGroup 230
Summary 231

Chapter 10 : String Handling 232


10.1 The String class 232
10.2 The StringBuffer Class 243
10.3 The StringBuilder class 252
Questions 253

Chapter 11 : I/O 254


11.1 I/O Streams 254
11.2 Reading console input 260
11.3 Writing console output 262
11.4 System.out.printf() 263
11.5 File class 265
11.6 Using File Streams 269
11.7 Scanning text with java.util.Scanner 273
11.8 Redirecting Standard I/O 276
11.9 Working with Random Access Files 277
11.10 Filter Streams 279
11.11 Object Serialization 283
Summary 287

4
Chapter 12 : API classes in java.lang package 288
12.1 Wrapper classes 288
12.2 Autoboxing/Unboxing of Wrappers 293
12.3 Math class 295
12.4 System class 302
12.5 Runtime class 304
12.6 Class class 306
Summary 307
Questions 307

Chapter 13 : Utility & Legacy classes 310


13.1 Enumeration interface 310
13.2 Vector class 310
13.3 Stack class 312
13.4 Dictionary class 314
13.5 Hashtable class 314
13.6 Properties class 316
13.7 Formatter class 317
13.8 Date class 319
13.9 Calendar class 320
13.10 GregorianCalendar class 322
13.11 TimeZone and SimpleTimeZone classes 323
13.12 Locale class 324
13.13 StringTokenizer class 326
13.14 StreamTokenizer class 329
13.15 Random class 330
13.16 BitSet class 331
13.17 Timer and TimerTask classes 332
13.18 Observable class 334
13.19 Currency class 336

Chapter 14 : Regular Expression Processing 337


14.1 What is a Regular Expression? 337
14.2 Pattern class 339
14.3 Matcher class 339
14.4 String Class RegEx Methods 342

Chapter 15 : API classes in java.text 343


15.1 DateFormat class 343
15.2 SimpleDateFormat class 345
15.3 DateFormatSymbols class 347
15.4 NumberFormat class 348
15.5 DecimalFormat class 350
15.6 Format class 353
Summary 354

5
Chapter 16 : Collections Framework and Generics 355
16.1 What is a Collection? 355
16.2 Generics 355
16.3 What Is a Collections Framework? 357
16.4 Collection Interfaces 358
16.5 The Collection Interface 360
16.6 The Set Interface 364
16.7 The List Interface 369
16.8 The Queue Interface 379
16.9 The Map Interface 381
16.10 Object Ordering 386
16.11 The SortedSet Interface 393
16.12 The SortedMap Interface 396
16.13 Relationships Among Generics 397
16.14 Wildcard Types 398
16.15 Defining and Using Generic Methods 399

Answers 400
Chapter 2 400
Chapter 3 401
Chapter 4 402
Chapter 5 403
Chapter 6 406
Chapter 7 408
Chapter 8 408
Chapter 10 409
Chapter 12 409

6
Chapter 1 : Java Technology
1.1 History of Java

Around 1990 James Gosling , Bill Joy and others at Sun Microsystems began developing a
language called Oak. They wanted it primarily to control microprocessors embedded in
consumer items such as cable set-top boxes,VCR's, toasters, and also for personal data assistants
(PDA).

To serve these goals, Oak needed to be:

o Platform independent (since multiple manufacturers involved)


o Extremely reliable
o Compact.

However, as of 1993, interactive TV and PDA markets had failed to take off. Then the Internet
and Web explosion began, so Sun shifted the target market to Internet applications and changed
the name of the project to Java.

By 1994 Sun's HotJava browser appeared. Written in Java in only a few months, it illustrated the
power of applets, programs that run within a browser, and also the capabilities of Java for
speeding program development.

Riding along with the explosion of interest and publicity in the Internet, Java quickly received
widespread recognition and expectations grew for it to become the dominant software for
browser and consumer applications.

However, the early versions of Java did not possess the breadth and depth of capabilities needed
for client (i.e. consumer) applications. For example, the graphics in Java 1.0 seemed crude and
clumsy compared to mature software developed with C and other languages.

Applets became popular and remain common but don't dominate interactive or multimedia
displays on web pages. Many other "plug-in" types of programs also run within the browser
environment.

So Java has not succeeded at development of consumer applications. However, Java's


capabilities grew with the release of new and expanded versions and it became a very popular
language for development of enterprise, or middleware, applications such as on line web stores,
transactions processing, database interfaces, and so forth.

Java has also become quite common on small platforms such as cell phones and PDAs. Java is
now used in several hundred cell phone models. Over 600 million JavaCards, smart cards with
additional features provided by Java, have been sold as of the summer of 2004.

7
1.2 What is Java?

The term Java actual refers to more than just a particular language like C or Pascal. Java
encompasses several parts, including :

 A high level language – the Java language is a high level one that at a glance looks very
similar to C and C++ but offers many unique features of its own.

 Java bytecode - a compiler, Sun's javac, transforms the Java language source code to
bytecode that runs in the JVM.
 Java Virtual Machine (JVM) – a program, such as Sun's java, that runs on a given
platform and takes the bytecode programs as input and interprets them just as if it were a
physical processor executing machine code.

Sun provides a set of programming tools such as javac, java and others in a bundle that it calls a
Java Software Development Kit for each version of the language and for different platforms such
as Windows, Linux, etc.. Sun also provides a runtime bundle with just the JVM when the
programming tools are not needed.

Note that because of the open nature of Java any or all of these parts can be replaced by non-Sun
components. For example, just as many different languages can create machine code for a given
processor, compilers of other languages have been created that output bytecode to run in the
JVM. Similarly, many JVMs have been written by groups outside of Sun.

Java, Open or Closed?

Java is not quite an open language but not quite a proprietary one either. All the core language
products - compiler, virtual machines (VM), class packages, and other components - are free.
Detailed specifications and source code are made openly available.

The Java Community Process (JCP) leads the development of new standards for the language.
Other companies and organizations can legally create a clean sheet compiler and/or a Virtual
Machine as long as it follows the publicly available specifications. Microsoft did this with the
Version 1.1 JVM that it used in its Internet Explorer browser.

Sun, however, does still assert final say on the specifications and controls the copyrights to
logos, and trademarks.

1.3 Versions of Java

Since its introduction, Sun has released a new version of the Java language every two years or
so. These new versions brought enhancements, new capabilities and fixes to bugs. Until
recently, the versions were numbered 1.x, where x reached up till 4. (Intermediate revisions
were labeled with a third number - 1.x.y - as in 1.4.2.) The newest version, however, is called
Java 5.0 rather than Java 1.5.

8
Below is a timeline of the different versions of the basic, or Standard Edition (SE), of Java along
with some of the new features that each one introduced. This edition contains the core language
packages (the name for code libraries in Java) and is aimed for desktop programming.

 1995: Version 1.0 of the Java Development Kit (JDK) was released for free by Sun.
o 8 packages with 212 classes
o Netscape 2.0-4.0 included Java 1.0.
o Microsoft and other companies licensed Java.
 1997: Version 1.1:
o 23 packages - 504 classes
o Improvements include better event handling, inner classes, improved JVM.
o Microsoft developed its own 1.1. compatible Java Virtual Machine for the
Internet Explorer.
o Many browsers in use are still compatible only with 1.1.
o Swing packages of greatly improved graphics became available during this time
but not included with the core language.
 1999: Version 1.2, also called the Java 2 Platform
o 59 packages - 1520 classes
o Code and tools distributed as The Software Development Kit (SDK)
o Java Foundation Classes (JFC), based on Swing, for improved graphics and user
interfaces, now included with the core language.
o Collections API included support for various lists, sets, and hash maps.
 2000: Version 1.3:
o 76 packages - 1842 classes
o Performance enhancements including the Hotspot virtual machine.
 2002: Version 1.4:
o 135 packages - 2991 classes
o Improved IO, XML support, etc.
 2004: Version 5.0 (previously numbered 1.5):
o 165 packages, over 3000 classes
o Faster startup and smaller memory footprint
o Metadata
o Formatted output
o Generics
o Improved multithreading features

Other Editions of Java

In the late 1990s, Sun split off two other more specialized branches, or editions, of Java. One is
aimed at small, embedded applications and the other for large scale middleware applications:

Micro Java

Embedded systems such as cell phones and device controllers typically offer reduced resources
as compared to desktop PCs. This means substantially less disk space or no disk at all, and less

9
of other types of nonvolatile memory. It also usually means a smaller display or perhaps no
display at all.

For such systems Sun offers slimmed down versions of Java.

 JavaCard - extremely limited Java for systems with only 16kb nonvolatile memory and
512 bytes volatile

 EmbeddedJava - based on Java 1.1 for 32 bit system with about 512kb each for ROM
and RAM. Individual packages, classes and even methods in the core language can be
thrown out to make room.
 PersonalJava - based on Java 1.1.8 for larger systems with 2MB ROM and more than
1MB RAM.
 Java 2 Platform, Micro Edition (J2ME) - based on the Java 2 Platform, J2ME replaces
the Java 1.1 based systems (EmbeddedJava and PersonalJava but not JavaCard). The
developer will choose from different configurations to suit the capacity of a given system.

J2EE - Java 2 Platform, Enterprise Edition

With the Java 2 Platform came a separate version with enhanced resources targeted at enterprise
applications. The Java 2 Enterprise Edition now provides a wide array of tools for building
middleware software such as for database access applications, online storefronts, and other
services.

Naming Conventions

All of these editions and version numbers can be a bit confusing for newcomers. Also, terms
change such as Java Development Kit becoming Software Development Kit. For this course,
however, you can just use the latest version - Java 5.0 - and not worry about all these historical
issues.

1.4 Code Compatibility

Sun has maintained good compatibility among codes written with the different versions.
Generally, the newer versions maintain compatibilty with older code. The approach has been to
add new features without subtracting any older features. (In some cases, such as the event
handling system introduced in Java 1.1, code using newer classes and techniques should not be
mixed in the same program with older version code.)

Thus far, Java maintains backwards compatibility. A program written according to Java 1.0
will compile with a Java 5 compiler. (Though some obsolete methods will generate
"deprecation" warning messages from the compiler.) The bytecode from a Java 1.0 compiler will
still run in a Java 5 virtual machine.

10
1.5 Java 5.0 Improvements

Java 2 Platform, Standard Edition 5.0 (J2SE 5.0) was launched as the official Java version by
Sun on September 30, 2004.

Most of the changes fall into the ease of development (EoD) category. With a few important
exceptions, the changes do not add new functionality but rather provide an easier way of doing
the same things you could do before but with less code and better compiler-time error detection.
The most important changes to the platform include the following:

Quality, Stability, and Compatibility

The designers of J2SE considered quality, stability, and compatibility to be the most important
aspect of the new release. Release 5.0 is the most tested release ever. Great efforts were made to
ensure compatibility with previous versions of Java. The Sun engineers made a public plea for
users worldwide to test their code with the 5.0 Beta releases and to report any problems that
appeared, especially any code that worked with earlier versions of Java but failed under 5.0.

Performance and Scalability

Faster JVM startup time and smaller memory footprint were important goals. These have been
achieved through careful tuning of the software and use of class data sharing.

Ease of Development

It is in the EoD area that the most significant changes appear. In most cases, no new
functionality was added in the sense that almost anything you can do with 5.0 you could do with
1.4, it just sometimes took a lot more boilerplate code (i.e. code that is repeated frequently) to do
it. The exception to this general statement has to do with the new multithreading and
concurrency features that provide capabilities previously unavailable.

In many cases, the new EoD features are all about syntax shortcuts that greatly reduce the
amount of code that must be entered, making coding faster and more error free. Some features
enable improved compile-time type checking, thus producing fewer runtime errors.

Monitoring and Manageability

The 5.0 release includes the ability to remotely monitor and even manage a running Java
application. For example, it is now much easier to watch memory usage and detect and respond
to a low-memory condition. Many of these features are built right in to the system, and you can
add additional monitoring and managing features to your own code.

Improved Desktop Client

The last great theme of the 5.0 release was an improved experience on the desktop client. In
addition to better performance because of a faster startup time and smaller memory footprint,

11
there is a new, improved Swing look and feel called Ocean, and a new easy-to-customize
skinnable look and feel called Synth in which you can use XML configuration files to specify the
appearance of every visual component in the system. In addition, the GTK and XP look and
feels introduced in J2SE 1.4.2 have received further improvements. There is support for
OpenGL and better performance on Unix X11 platforms. The Java Web Start and Java Plug-In
technologies (both used to run Java applications downloaded over the Web) have been improved.

Other new features in J2SE 5.0 include core XML support, improvements to Unicode,
improvements to Java's database connectivity package known as JDBC, and an improved, high-
compression format for JAR files that can greatly reduce download times for applets and other
networked applications.

1.6 Features of Java

The Java programming language is a high-level language that can be characterized by all of the
following buzzwords:

 Architecture
 Simple
neutral
 Object
 Portable
oriented
 Distributed  High performance
 Interpreted  Multithreaded
 Robust  Dynamic
 Secure

With most programming languages, you either compile or interpret a program so that you can
run it on your computer. The Java programming language is unusual in that a program is both
compiled and interpreted. With the compiler, first you translate a program into an intermediate
language called Java bytecodes —the platform-independent codes interpreted by the interpreter
on the Java platform. The interpreter parses and runs each Java bytecode instruction on the
computer. Compilation happens just once; interpretation occurs each time the program is
executed. The following figure illustrates how this works.

You can think of Java bytecodes as the machine code instructions for the Java Virtual Machine
(Java VM). Every Java interpreter, whether it's a development tool or a Web browser that can
run applets, is an implementation of the Java VM.

12
Java bytecodes help make "write once, run anywhere" possible. You can compile your program
into bytecodes on any platform that has a Java compiler. The bytecodes can then be run on any
implementation of the Java VM. That means that as long as a computer has a Java VM, the same
program written in the Java programming language can run on Windows 2000, a Solaris
workstation, or on an iMac.

Java was designed to be easy for the professional programmer to learn and use effectively.

Java frees you from having to worry about many of the most common causes of programming
errors.

Because Java is a strictly typed language, it checks your code at compile-time. It also checks the
code at run-time.

Java virtually eliminates the memory access by managing memory allocation and deallocation.
In fact, deallocation is completely automatic, because Java provide Garbage Collection for
unused objects.

Java supports multithreaded programming which allows you to write programs that do many
things simultaneously. The Java runtime system comes with an elegant yet sophisticated
solution for multiprocess synchronization that enables you to construct smoothly running
interactive systems.

Operating system upgrades, processor upgrades and changes in core system resources can all
combine to make a program malfunction. The Java designers made several hard decisions in the
Java language and Java Virtual Machine in an attempt to alter this situation, thus making Java
architecture neutral.

Java is designed for the distributed environment of the Internet, because it handles TCP/IP
protocols. Accessing a resource using a URL is not much different from accessing a file.

13
Java supports dynamic programming where small fragments of bytecode may be dynamically
updated on a running system.

1.7 Java Applets and Applications

The most common types of programs written in the Java programming language are applets and
applications. An applet is a program that adheres to certain conventions that allow it to run
within a Java-enabled browser. An applet is an application designed to be transmitted over the
Internet and executed by a Java-compatible Web browser.

An application is a standalone program that runs directly on the Java platform. A special kind of
application known as a server serves and supports clients on a network. Examples of servers are
Web servers, proxy servers, mail servers, and print servers. Another specialized program is a
servlet. A servlet can almost be thought of as an applet that runs on the server side. Java
Servlets are a popular choice for building interactive web applications, replacing the use of CGI
scripts. Servlets are similar to applets in that they are runtime extensions of applications.
Instead of working in browsers, though, servlets run within Java Web servers, configuring or
tailoring the server.

1.8 Why Java is important to Internet?

Java provides a firewall between a networked application and your computer. When you use a
Java-compatible web browser, you can safely download Java applets without fear of viral
infection or malicious intent. Java achieves this protection by confining a Java program to the
Java execution environment and not allowing it access to other parts of the computer. Another
reason why Java is important to Internet is due to its portability i. e. Write once run anywhere
feature.

With Java technology, the Internet and private networks become your computing environment.
Coupled with the power of networking, the Java platform is helping computer users to do things
that were previously unimaginable. For example, users can securely access their personal
information and applications when they're far away from the office by using any computer that's
connected to the Internet; soon they'll be able to access tailored applications from a mobile phone
based on the Java platform, or even use smart cards as a pass key to everything from the cash
machine to ski lifts.

Why Java technology? Networks require software that is portable, modular, and secure -- all
areas where Java technology shines, because it was designed for use on networks from the
beginning.

Businesses are using Java technology because it connects easily to existing computing systems,
lowers computing costs, and speeds software development. It also lets businesses use the
Internet to securely connect to their customers, suppliers and partners.

14
And consumers benefit from Java technology because it brings personal, business, and
entertainment services to them -- easily and securely -- in many locations and on many different
kinds of appliances and devices at home, at work and on the road.

1.9 The Java Platform

A Java platform is the software environment in which a program runs.

The Java platform has two components:


 The Java Virtual Machine (Java VM)
 The Java Application Programming Interface (Java API)

The compiler, javac, takes your source file and translates its text into instructions that the Java
Virtual Machine (Java VM) can understand. The compiler converts these instructions into a
bytecode file.

The Java interpreter installed on your computer implements the Java VM. This interpreter takes
your bytecode file and carries out the instructions by translating them into instructions that your
computer can understand.

The Java compiler and interpreter are case-sensitive.

The Java API is a large collection of ready-made software components that provide many useful
capabilities, such as graphical user interface (GUI) widgets. The Java API is grouped into
libraries of related classes and interfaces; these libraries are known as packages.

The following figure depicts a program that's running on the Java platform. As the figure shows,
the Java API and the virtual machine insulate the program from the hardware.

Native code is code that after you compile it, the compiled code runs on a specific hardware
platform. As a platform-independent environment, the Java platform can be a bit slower than
native code. However, smart compilers, well-tuned interpreters, and just-in-time bytecode
compilers can bring performance close to that of native code without threatening portability.

1.10 What Can Java Technology Do?

Every full implementation of the Java platform gives you the following features:
 The essentials: Objects, strings, threads, numbers, input and output, data structures,
system properties, date and time, and so on.

15
 Applets: The set of conventions used by applets.
 Networking: URLs, TCP (Transmission Control Protocol), UDP (User Datagram
Protocol) sockets, and IP (Internet Protocol) addresses.
 Internationalization: Help for writing programs that can be localized for users
worldwide. Programs can automatically adapt to specific locales and be displayed in the
appropriate language.
 Security: Both low level and high level, including electronic signatures, public and
private key management, access control, and certificates.
 Software components: Known as JavaBeansTM, can plug into existing component
architectures.
 Object serialization: Allows lightweight persistence and communication via Remote
Method Invocation (RMI).
 Java Database Connectivity (JDBCTM): Provides uniform access to a wide range of
relational databases.

The Java platform also has APIs for 2D and 3D graphics, accessibility, servers, collaboration,
telephony, speech, animation, and more.

Java 2 Runtime Environment (JRE) consists of the virtual machine, the Java platform core
classes, and supporting files. The Java 2 SDK includes the JRE and development tools such as
compilers and debuggers.

Applications are standalone programs.

1.11 Writing a Program

The easiest way to write a simple program is with a text editor. So, using the text editor of your
choice, create a text file with the following text, and be sure to name the text file
ExampleProgram.java. Java programs are case sensitive, so if you type the code in yourself, pay
particular attention to the capitalization.

//A Very Simple Example


class ExampleProgram {
public static void main(String[] args){
System.out.println("I'm a Simple Program");
}
}

1.12 Compiling the Program

A program has to be converted to a form the Java VM can understand so any computer with a
Java VM can interpret and run the program

The Java compiler is invoked at the command line on Unix and DOS shell operating systems as
follows:

javac ExampleProgram.java

16
1.13 Interpreting and Running the Program

Once your program successfully compiles into Java bytecodes, you can interpret and run
applications on any Java VM, or interpret and run applets in any Web browser with a Java VM
built in such as Netscape or Internet Explorer. Interpreting and running a Java program means
invoking the Java VM byte code interpreter, which converts the Java byte codes to platform-
dependent machine codes so your computer can understand and run the program.

The Java interpreter is invoked at the command line on Unix and DOS shell operating systems as
follows:

java ExampleProgram

At the command line, you should see:

I'm a Simple Program

1.14 Comments in Java

Code comments are placed in source files to describe what is happening in the code to someone
who might be reading the file, to comment-out lines of code to isolate the source of a problem
for debugging purposes, or to generate API documentation. To these ends, the Java language
supports three kinds of comments: double slashes, C-style, and doc comments.

Double Slashes

Double slashes (//) are used in the C/C++ programming language, and tell the compiler to treat
everything from the slashes to the end of the line as text.

//A Very Simple Example


class ExampleProgram {
public static void main(String[] args){
System.out.println("I'm a Simple Program");
}
}

C-Style Comments

Instead of double slashes, you can use C-style comments (/* */) to enclose one or more lines of
code to be treated as text.

/* These are
C-style comments
*/

class ExampleProgram {
public static void main(String[] args){
System.out.println("I'm a Simple Program");
}

17
}

Doc Comments

To generate documentation for your program, use the doc comments (/** */) to enclose lines of
text for the javadoc tool to find. The javadoc tool locates the doc comments embedded in source
files and uses those comments to generate API documentation.

/** This class displays a text string at


* the console.
*/

class ExampleProgram {
public static void main(String[] args){
System.out.println("I'm a Simple Program");
}
}

With one simple class, there is no reason to generate API documentation. API documentation
makes sense when you have an application made up of a number of complex classes that need
documentation. The tool generates HTML files (Web pages) that describe the class structures
and contain the text enclosed by doc comments.

1.15 Application Structure and Elements

An application is created from classes. A class is similar to a RECORD in the Pascal language
or a struct in the C language in that it stores related data in fields, where the fields can be
different types. So you could, for example, store a text string in one field, an integer in another
field, and a floating point in a third field. The difference between a class and a RECORD or
struct is that a class also defines the methods to work on the data.

For example, a very simple class might store a string of text and define one method to set the
string and another method to get the string and print it to the console. Methods that work on the
data are called accessor methods.

Every application needs one class with a main method. This class is the entry point for the
program, and is the class name passed to the java interpreter command to run the application.

The code in the main method executes first when the program starts, and is the control point
from which the controller class accessor methods are called to work on the data.

It has no fields or accessor methods, but because it is the only class in the program, it has a main
method.

The public static void keywords mean the Java virtual machine (JVM) interpreter can call the
program's main method to start the program (public) without creating an instance of the class
(static), and the program does not return data to the Java VM interpreter (void) when it ends.

18
Summary
In this chapter you learnt the history of Java and how the Java language has evolved. Java is not
only a programming language it’s a platform. Java is important because of its cross-platform
functionality. Also Java is a secure language. Java can be used for simple as well as complex
applications. It can be used for embedded as well as mobile applications.

19
Chapter 2 : Data types, variables and Arrays
2.1 Data Types

The Java programming language has two categories of data types: primitive and reference. A
variable of primitive type contains a single value of the appropriate size and format for its type: a
number, a character, or a boolean value.

Arrays, classes, and interfaces are reference types. The value of a reference type variable, in
contrast to that of a primitive type, is a reference to (an address of) the value or set of values
represented by the variable.

A reference is called a pointer, or a memory address in other languages. The Java programming
language does not support the explicit use of addresses like other languages do. You use the
variable's name instead.

Primitive Data Types

Keyword Description Size/Format


(integers)
byte Byte-length integer 8-bit two's complement
short Short integer 16-bit two's complement
int Integer 32-bit two's complement
long Long integer 64-bit two's complement
(real numbers)
float Single-precision floating point 32-bit IEEE 754
double Double-precision floating point 64-bit IEEE 754
(other types)
char A single character 16-bit Unicode character
boolean A boolean value (true or false) true or false

You can put a literal primitive value directly in your code.

int anInt = 4;

Range of primitive data types


Primitive Type Size Range of Values
byte 8 bit -27 to 27-1
short 16 bit -215 to 215-1
int 32 bit -231 to 231-1
long 64 bit -263 to 263-1
char 16 bit '\u0000' to '\uffff'(0 to 216-1 )
float 32 bit Max. positive value: (2-2-23)*2127. Min. positive value: 2-149
double 64 bit Max. positive value: (2-2-52)*21023. Min. positive value: 2-1074

20
2.2 Literals

A specific primitive value in a line of code is called a literal. These will be translated into values
by the compiler and inserted into the byte code.

Examples of Literal Values and Their Data Types

Literal Data Type


178 int
8864L long
37.266 double
37.266D double
87.363F float
26.77e3 double
'c' char
true boolean
false boolean

A series of digits with no decimal point is typed as an integer. You can specify a long integer by
putting an 'L' or 'l' after the number. 'L' is preferred as it cannot be confused with the digit '1'. A
series of digits with a decimal point is of type double. You can specify a float by putting an 'f' or
'F' after the number. A literal character value is any single Unicode character between single
quote marks. The two boolean literals are simply true and false.

Constructing literal numeric values using octal and hexadecimal formats.

Octal literals begin with zero e.g. 013042 (and obviously only digits 0-7 are allowed).
Hexadecimal literals begin with zero and an 'x' e.g. 0x23e4A (digits allowed are 0-9 and a to f,
the 'x' and the letters can be upper or lower case).

Construct a literal value of char type using Java's unicode escape format for a specified
character code.

Use \u followed by four hexadecimal digits representing the 16 bit unicode character e.g.
char x='\u1234'

Java also supports certain escape codes for special characters such as '\n' for newline.

2.3 Java Character Encoding: UTF and Unicode

Java uses two closely related encoding systems UTF and Unicode. Java was designed from the
ground up to deal with multibyte character sets and can deal with the vast numbers of characters
that can be stored using the Unicode character set. Unicode characters are stored in two bytes
which allows for up to 65K worth of characters. This means it can deal with Japanese Chinese,
and just about any other character set known.

21
Although Unicode can represent almost any character you would ever likely to use it is not an
efficient coding method for programming. Most of the text data within a program uses standard
ASCII, most of which can easily be stored within one byte. For reasons of compactness Java uses
a system called UTF-8 for string literals, identifiers and other text within programs. This can
result in a considerable saving by comparison with using Unicode where every character requires
2 bytes.

2.4 EscapeSequences

\b /* \u0008: backspace BS */
\t /* \u0009: horizontal tab HT */
\n /* \u000a: linefeed LF */
\f /* \u000c: form feed FF */
\r /* \u000d: carriage return CR */
\" /* \u0022: double quote " */
\' /* \u0027: single quote ' */
\\ /* \u005c: backslash \ */
OctalEscape /* \u0000 to \u00ff: from octal value */

2.5 Rules for naming an identifier

When we learn to program we have to give names or identifiers to things we create such as files,
classes, objects, variables and attributes (attributes could be numbers, words or even objects).
There are rules which govern what is allowable.

Identifiers must be chosen according to certain rules:

 they can contain letters, numbers, the underscore character ( _ ) or dollar character ($)
 they cannot start with a number
 they must not include spaces, other special characters or punctuation marks
 a Java keyword must not be used.

A convention that is sometimes adopted to make identifiers more readable is to use a capital
letter to indicate the beginning of a new word, for example: cubeRoot, firstNumber, this is
sometimes called camel hump notation.

Note that Java is case sensitive so A1 and a1 are different identifiers.

Naming Conventions

Class identifiers begin with a capital letter.

The filename for the class code is the same as the name of the class, e.g. the code for the class
JTRectangle is stored in the file JTRectangle.java.

Object identifiers start with a lowercase letter.

Attributes identifiers start with a lowercase letter.

22
2.6 Java Language Keywords

true, false, and null are not keywords but they are reserved words, so you cannot use them as
names in your programs either.

abstract double int strictfp **


boolean Else interface super
break extends long switch
byte Final native synchronized
case finally new this
catch Float package throw
char For private throws
class goto * protected transient
const * If public try
continue implements return void
default import short volatile
do instanceof static while
enum**** assert***

* indicates a keyword that is not currently used


** indicates a keyword that was added for Java 2
*** new in J2SE 1.4
**** new in J2SE 5.0

2.7 Variables

A variable is an item of data named by an identifier. You must explicitly provide a name and a
type for each variable you want to use in your program. The variable's name must be a legal
identifier --an unlimited series of Unicode characters that begins with a letter. You use the
variable name to refer to the data that the variable contains. The variable's type determines what
values it can hold and what operations can be performed on it. To give a variable a type and a
name, you write a variable declaration, which generally looks like this:
type name

In addition to the name and type that you explicitly give a variable, a variable has scope.

Every variable must have a data type. A variable's data type determines the values that the
variable can contain and the operations that can be performed on it. Integers can contain only
integral values (both positive and negative). You can perform arithmetic operations, such as
addition, on integer variables.

Variable names begin with a lowercase letter, and class names begin with an uppercase letter. If
a variable name consists of more than one word, the words are joined together, and each word
after the first begins with an uppercase letter, like this: isVisible. The underscore character (_)
is acceptable anywhere in a name, but by convention is used only to separate words in constants
(because constants are all caps by convention and thus cannot be case-delimited).

23
2.8 Declaring constants – Final variables

You can declare a variable in any scope to be final. The value of a final variable cannot change
after it has been initialized. Such variables are similar to constants in other programming
languages.

To declare a final variable, use the final keyword in the variable declaration before the type:
final int aFinalVar = 0;

The previous statement declares a final variable and initializes it, all at once. Subsequent
attempts to assign a value to aFinalVar result in a compiler error. You may, if necessary, defer
initialization of a final local variable. Simply declare the local variable and initialize it later, like
this:
final int blankfinal;
. . .
blankfinal = 0;

A final local variable that has been declared but not yet initialized is called a blank final. Again,
once a final local variable has been initialized, it cannot be set, and any later attempts to assign a
value to blankfinal result in a compile-time error.

The following variable declaration defines a constant named PI, whose value is pi, the ratio of
the circumference of a circle to its diameter (3.141592653589793) and cannot be changed:

final double PI = 3.141592653589793;

By convention, the name of constant values are spelled in uppercase letters.

2.9 Arrays

An array is a structure that holds multiple values of the same type. The length of an array is
established when the array is created (at runtime). After creation, an array is a fixed-length
structure.

An array element is one of the values within an array and is accessed by its position within the
array.

24
Declaring an Array

This line of code from the sample program declares an array variable:
int[] anArray; // declare an array of integers

Like declarations for variables of other types, an array declaration has two components: the
array's type and the array's name. An array's type is written type[], where type is the data type
of the elements contained within the array, and [] indicates that this is an array. Remember that
all of the elements within an array are of the same type. The sample program uses int[], so the
array called anArray will be used to hold integer data. Here are declarations for arrays that hold
other types of data:
float[] anArrayOfFloats;
boolean[] anArrayOfBooleans;
Object[] anArrayOfObjects;
String[] anArrayOfStrings;

As with declarations for variables of other types, the declaration for an array variable does not
allocate any memory to contain the array elements. The sample program must assign a value to
anArray before the name refers to an array.

Creating an Array

You create an array explicitly using Java's new operator. The next statement in the sample
program allocates an array with enough memory for ten integer elements and assigns the array to
the variable anArray declared earlier.
anArray = new int[10]; // create an array of integers

In general, when creating an array, you use the new operator, plus the data type of the array
elements, plus the number of elements desired enclosed within square brackets ('[' and ']').
new elementType[arraySize]

If the new statement were omitted from the sample program, the compiler would print an error
like the following one and compilation would fail.
ArrayDemo.java:4: Variable anArray may not have been initialized.

Accessing an Array Element

Now that some memory has been allocated for the array, the program assigns values to the array
elements:
anArray[2] = 10;
System.out.print(anArray[2] + " ");

25
This part of the code shows that to reference an array element, either to assign a value to it, or to
access the value, you append square brackets to the array name. The value between the square
brackets indicates (either with a variable or some other expression) the index of the element to
access. Note that in Java, array indices begin at 0 and end at the array length minus 1.

Getting the Size of an Array

To get the size of an array, you write


arrayname.length

Be careful: Programmers new to the Java programming language are tempted to follow length
with an empty set of parenthesis. This doesn't work because length is not a method. length is
a property provided by the Java platform for all arrays.

Array Initializers

The Java programming language provides a shortcut syntax for creating and initializing an array.
Here's an example of this syntax:
boolean[] answers = { true, false, true, true, false };

The length of the array is determined by the number of values provided between { and }.

Before initialization arrays are always set to contain default values wherever they are created.

2.10 Multidimensional Arrays

A multi-dimensional array of dimension n (i.e., an n-dimensional array or simply n-D array) is a


collection of items which is accessed via n subscript expressions

The Java programming language does not really support multi-dimensional arrays. It does,
however, support arrays of arrays. In Java, a two-dimensional array x is really an array of one-
dimensional arrays:

int[][] x = new int[3][5];

When you allocate memory for multidimensional array, you need only specify the memory for
the first (leftmost) dimension. You can allocate remaining dimensions separately.

public class ArrayOfArraysDemo2 {


public static void main(String[] args) {
int[][] aMatrix = new int[3][];

//populate matrix
aMatrix[0]=new int[]{1};
aMatrix[1]=new int[]{2,3};
aMatrix[2]=new int[]{4,5,6};

26
}
}

2.11 Copying Arrays

Use System's arraycopy method to efficiently copy data from one array into another. The
arraycopy method requires five arguments:

public static void arraycopy(Object source, int srcIndex, Object


dest,int destIndex, int length);

The two Object arguments indicate the array to copy from and the array to copy to. The three
integer arguments indicate the starting location in each the source and the destination array, and
the number of elements to copy. This diagram illustrates how the copy takes place:

The following program, ArrayCopyDemo, uses arraycopy to copy some elements from the
copyFrom array to the copyTo array.

public class ArrayCopyDemo {


public static void main(String[] args) {
char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e',
'i', 'n', 'a', 't', 'e', 'd' };
char[] copyTo = new char[7];

System.arraycopy(copyFrom, 2, copyTo, 0, 7);


System.out.println(new String(copyTo));
}
}

The arraycopy method call in this example program begins the copy at element number 2 in the
source array. Recall that array indices start at 0, so that the copy begins at the array element 'c'.
The arraycopy method call puts the copied elements into the destination array beginning at the
first element (element 0) in the destination array copyTo. The copy copies 7 elements: 'c', 'a', 'f',
'f', 'e', 'i', and 'n'. Effectively, the arraycopy method takes the "caffein" out of "decaffeinated",
like this:

27
Note that the destination array must be allocated before you call arraycopy and must be large
enough to contain the data being copied.

Summary

When you declare a variable, you explicitly set the variable's name and data type. The Java
programming language has two categories of data types: primitive and reference. A variable of
primitive type contains a value. The table in the Data Types section shows all of the primitive
data types along with their sizes and formats. Arrays, classes, and interfaces are reference types.

You can provide an initial value for a variable within its declaration by using the assignment
operator (=). You can declare a variable as final. The value of a final variable cannot change
after it's been initialized.

An array is a fixed-length data structure that can contain multiple objects of the same type. An
array can contain any type of object, including arrays. To declare an array, you use the type of
object that the array can contain and brackets.

The length of the array must be specified when it is created.You can use the new operator to
create an array, or you can use an array initializer. Once created, the size of the array cannot
change. To get the length of the array, you use the length attribute.

An element within an array can be accessed by its index. Indices begin at 0 and end at the length
of the array minus 1.

To copy an array, use the arraycopy method in the System class.

Questions

1. class MCZ11 {
public static void main (String[] args) {
char a = '\c'; // 1
char b = '\r'; // 2
char c = '\"'; // 3
char d = '\b'; // 4

28
char e = '\''; // 5
}
}

A compile-time error is generated at which line?

a.  1
b.  2
c.  3
d.  4
e.  5
f.  None of the above

29
2. class GRC4 {public static void main(String[] args) {}} // 1
class GRC5 {public static void main(String []args) {}} // 2
class GRC6 {public static void main(String args[]) {}} // 3

What is the result of attempting to compile and run the above programs?

a.  Compile-time error at line 1.


b.  Compile-time error at line 2.
c.  Compile-time error at line 3.
d.  An attempt to run GRC4 from the command line fails.
e.  An attempt to run GRC5 from the command line fails.
f.  An attempt to run GRC6 from the command line fails.
g.  None of the above

3. Which of these words belongs to the set of Java keywords?

a.  qualified e.  label i.  value


b.  record f.  to j.  virtual
c.  repeat g.  type k.  xor
d.  restricted h.  until l.  None of the above

4. class Identifiers {
int i1; // 1
int _i2; // 2
int i_3; // 3
int #i4; // 4
int $i5; // 5
int %i6; // 6
int i$7; // 7
int 8i; // 8
}

Compile-time errors are generated at which lines?

a.  1
b.  2
c.  3
d.  4
e.  5
f.  6
g.  7
h.  8

30
5. Which of the following represent the full range of type char?

a.  '\u0000' to '\u7fff'


b.  '\u0000' to '\uffff'
c.  0 to 32767
d.  0 to 65535
e.  -32768 to 32767
f.  -65536 to 65535

31
6. class MWC101 {
public static void main(String[] args) {
int[] a1 = new int[]; // 1
int a2[] = new int[5]; // 2
int[] a3 = new int[]{1,2}; // 3
int []a4 = {1,2}; // 4
int[] a5 = new int[5]{1,2,3,4,5}; // 5
}
}

Compile-time errors are generated at which lines?

a.  1 c.  3 e.  5


b.  2 d.  4

7. class MWC201 {
public static void main(String[] args) {
int[][] a1 = {{1,2,3},{4,5,6},{7,8,9,10}};
System.out.print(a1[0][2]+","+a1[1][0]+","+a1[2][1]);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 3,4,8


b.  Prints: 7,2,6
c.  Compile-time error
d.  Run-time error
e.  None of the above

32
Chapter 3 : Operators
3.1 Operands

An operand can be:


 a numeric variable - integer, floating point or character
 any primitive type variable - numeric and boolean
 reference variable to an object
 a literal - numeric value, boolean value, or string.
 an array element, "a[2]"
 char primitive, which in numeric operations is treated as an unsigned two byte integer

3.2 Operator

An operator performs a function on one, two, or three operands. An operator that requires one
operand is called a unary operator. For example, ++ is a unary operator that increments the
value of its operand by 1. An operator that requires two operands is a binary operator. For
example, = is a binary operator that assigns the value from its right-hand operand to its left-hand
operand. And finally, a ternary operator is one that requires three operands. The Java
programming language has one ternary operator, ?:, which is a short-hand if-else statement.

The unary operators support either prefix or postfix notation. Prefix notation means that the
operator appears before its operand:

operator op //prefix notation

Postfix notation means that the operator appears after its operand:
op operator //postfix notation

All of the binary operators use infix notation, which means that the operator appears between its
operands:
op1 operator op2 //infix notation

The ternary operator is also infix; each component of the operator appears between operands:
op1 ? op2 : op3 //infix notation

In addition to performing the operation, an operator returns a value. The return value and its
type depend on the operator and the type of its operands. For example, the arithmetic operators,
which perform basic arithmetic operations such as addition and subtraction, return numbers-the
result of the arithmetic operation. The data type returned by an arithmetic operator depends on
the type of its operands: If you add two integers, you get an integer back. An operation is said to
evaluate to its result.

33
We divide the operators into these categories:
 Arithmetic Operators
 Increment and decrement operators
 Relational Operators
 Bitwise Operators
 Logical Operators
 Assignment Operators
 Conditional or ternary operator

3.2.1 Arithmetic Operators

The Java programming language supports various arithmetic operators for all floating-point and
integer numbers. These operators are + (addition), - (subtraction), * (multiplication), /
(division), and % (modulo).

The following table summarizes the binary arithmetic operations in the Java programming
language.

Operator Use Description


+ op1 + op2 Adds op1 and op2
- op1 – op2 Subtracts op2 from op1
* op1 * op2 Multiplies op1 by op2
/ op1 / op2 Divides op1 by op2
If floating point arithmetic and op2 = 0.0, then infinity
returned if op1 is not zero otherwise NaN if op1 is zero.
ArthmeticException thrown if op1 & op2 are integer types
and op2 is zero.
% op1 % op2 Computes the remainder of dividing op1 by op2
If floating point arithmetic and op2 = 0.0 or infinity, then
NaN returned
ArthmeticException thrown if op1 & op2 are integer types
and op2 is zero.

public class ArithmeticDemo {


public static void main(String[] args) {
//a few numbers
int i = 37;
int j = 42;
double x = 27.475;
double y = 7.22;
System.out.println("Variable values...");
System.out.println(" i = " + i);
System.out.println(" j = " + j);
System.out.println(" x = " + x);
System.out.println(" y = " + y);

//adding numbers
System.out.println("Adding...");

34
System.out.println(" i + j = " + (i + j));
System.out.println(" x + y = " + (x + y));

//subtracting numbers
System.out.println("Subtracting...");
System.out.println(" i - j = " + (i - j));
System.out.println(" x - y = " + (x - y));

//multiplying numbers
System.out.println("Multiplying...");
System.out.println(" i * j = " + (i * j));
System.out.println(" x * y = " + (x * y));

//dividing numbers
System.out.println("Dividing...");
System.out.println(" i / j = " + (i / j));
System.out.println(" x / y = " + (x / y));

//computing the remainder resulting from dividing numbers


System.out.println("Computing the remainder...");
System.out.println(" i % j = " + (i % j));
System.out.println(" x % y = " + (x % y));

//mixing types
System.out.println("Mixing types...");
System.out.println(" j + y = " + (j + y));
System.out.println(" i * x = " + (i * x));
}
}
Note that when an integer and a floating-point number are used as operands to a single arithmetic
operation, the result is floating point. The integer is implicitly converted to a floating-point
number before the operation takes place. The following table summarizes the data type returned
by the arithmetic operators, based on the data type of the operands. The necessary conversions
take place before the operation is performed.

Data Type of Data Type of Operands


Result
long Neither operand is a float or a double (integer arithmetic); at least
one operand is a long.
int Neither operand is a float or a double (integer arithmetic); neither
operand is a long.
double At least one operand is a double.
float At least one operand is a float; neither operand is a double.

In addition to the binary forms of + and -, each of these operators has unary versions that
perform the following operations:

Operator Use Description


+ +op Promotes op to int if it's a byte, short, or char

35
- -op Arithmetically negates op

3.2.2 Increment and Decrement Operators

Increment operator (++) increments its operand by 1, and decrement operator (--)decrements its
operand by 1. Either ++ or -- can appear before (prefix) or after (postfix) its operand. The prefix
version, ++op/--op, evaluates to the value of the operand after the increment/decrement
operation. The postfix version, op++/op--, evaluates the value of the operand before the
increment/decrement operation.

Operator Use Description


++ op++ Increments op by 1; evaluates to the value of op before it was
incremented
++ ++op Increments op by 1; evaluates to the value of op after it was
incremented
-- op-- Decrements op by 1; evaluates to the value of op before it was
decremented
-- --op Decrements op by 1; evaluates to the value of op after it was
decremented

3.2.3 Relational Operators

A relational operator compares two values and determines the relationship between them. For
example, != returns true if the two operands are unequal. This table summarizes the relational
operators:

Operator Use Returns true if


> op1 > op2 op1 is greater than op2
>= op1 >= op2 op1 is greater than or equal to op2
< op1 < op2 op1 is less than op2
<= op1 <= op2 op1 is less than or equal to op2
== op1 == op2 op1 and op2 are equal
!= op1 != op2 op1 and op2 are not equal

public class RelationalDemo {


public static void main(String[] args) {

//a few numbers


int i = 37;
int j = 42;
int k = 42;
System.out.println("Variable values...");
System.out.println(" i = " + i);
System.out.println(" j = " + j);
System.out.println(" k = " + k);

36
//greater than
System.out.println("Greater than...");
System.out.println(" i > j = " + (i > j)); //false
System.out.println(" j > i = " + (j > i)); //true
System.out.println(" k > j = " + (k > j));
//false, they are equal

//greater than or equal to


System.out.println("Greater than or equal to...");
System.out.println(" i >= j = " + (i >= j)); //false
System.out.println(" j >= i = " + (j >= i)); //true
System.out.println(" k >= j = " + (k >= j)); //true

//less than
System.out.println("Less than...");
System.out.println(" i < j = " + (i < j)); //true
System.out.println(" j < i = " + (j < i)); //false
System.out.println(" k < j = " + (k < j)); //false

//less than or equal to


System.out.println("Less than or equal to...");
System.out.println(" i <= j = " + (i <= j)); //true
System.out.println(" j <= i = " + (j <= i)); //false
System.out.println(" k <= j = " + (k <= j)); //true

//equal to
System.out.println("Equal to...");
System.out.println(" i == j = " + (i == j)); //false
System.out.println(" k == j = " + (k == j)); //true

//not equal to
System.out.println("Not equal to...");
System.out.println(" i != j = " + (i != j)); //true
System.out.println(" k != j = " + (k != j)); //false
}
}

Relational operators often are used with conditional operators to construct more complex
decision-making expressions. The Java programming language supports six conditional
operators-five binary and one unary--as shown in the following table.

Operator Use Returns true if


&& op1 && op2 op1 and op2 are both true, conditionally evaluates op2
|| op1 || op2 either op1 or op2 is true, conditionally evaluates op2
! ! op op is false
& op1 & op2 op1 and op2 are both true, always evaluates op1 and op2
| op1 | op2 either op1 or op2 is true, always evaluates op1 and op2

37
^ op1 ^ op2 if op1 and op2 are different--that is if one or the other of
the operands is true but not both

3.2.4 Bitwise Operators

A shift operator performs bit manipulation on data by shifting the bits of its first operand right or
left. This table summarizes the shift operators available in the Java programming language.

Operator Use Operation


>> op1 >> op2 shift bits of op1 right by distance op2
<< op1 << op2 shift bits of op1 left by distance op2
>>> op1 >>> op2 shift bits of op1 right by distance op2 (unsigned)

Each operator shifts the bits of the left-hand operand over by the number of positions indicated
by the right-hand operand. The shift occurs in the direction indicated by the operator itself. For
example, the following statement shifts the bits of the integer 13 to the right by one position:
13 >> 1;

The binary representation of the number 13 is 1101. The result of the shift operation is 1101
shifted to the right by one position-110, or 6 in decimal. The left-hand bits are filled with 0s as
needed.

The following table shows the four operators the Java programming language provides to
perform bitwise functions on their operands:

Operator Use Operation


& op1 & op2 bitwise and
| op1 | op2 bitwise or
^ op1 ^ op2 bitwise xor
~ ~op2 bitwise complement

When its operands are numbers, the & operation performs the bitwise AND function on each
parallel pair of bits in each operand. The AND function sets the resulting bit to 1 if the
corresponding bit in both operands is 1, as shown in the following table.

op1 op2 Result


0 0 0
0 1 0
1 0 0
1 1 1

38
Suppose that you were to AND the values 13 and 12, like this: 13 & 12. The result of this
operation is 12 because the binary representation of 12 is 1100, and the binary representation of
13 is 1101.
1101 //13
& 1100 //12
------
1100 //12

If both operand bits are 1, the AND function sets the resulting bit to 1; otherwise, the resulting bit
is 0. So, when you line up the two operands and perform the AND function, you can see that the
two high-order bits (the two bits farthest to the left of each number) of each operand are 1. Thus,
the resulting bit in the result is also 1. The low-order bits evaluate to 0 because either one or
both bits in the operands are 0. When both of its operands are numbers, the | operator performs
the inclusive or operation, and ^ performs the exclusive or (XOR) operation. Inclusive or means
that if either of the two bits is 1, the result is 1. The following table shows the results of
inclusive or operations:

op1 op2 Result


0 0 0
0 1 1
1 0 1
1 1 1

Exclusive or means that if the two operand bits are different the result is 1, otherwise the result is
0. The following table shows the results of an exclusive or operation.

op1 op2 Result


0 0 0
0 1 1
1 0 1
1 1 0

And finally, the complement operator inverts the value of each bit of the operand: if the operand
bit is 1 the result is 0 and if the operand bit is 0 the result is 1.

Among other things, bitwise manipulations are useful for managing sets of boolean flags.

static final int VISIBLE = 1;


static final int DRAGGABLE = 2;
static final int SELECTABLE = 4;
static final int EDITABLE = 8;

int flags = 0;

To set the "visible" flag when something became visible you would use this statement:
flags = flags | VISIBLE;

39
To test for visibility, you could then write:
if ((flags & VISIBLE) == VISIBLE) {
...
}

A program example is given below:

public class BitwiseDemo {

static final int VISIBLE = 1;


static final int DRAGGABLE = 2;
static final int SELECTABLE = 4;
static final int EDITABLE = 8;

public static void main(String[] args)


{
int flags = 0;

flags = flags | VISIBLE;


flags = flags | DRAGGABLE;

if ((flags & VISIBLE) == VISIBLE) {


if ((flags & DRAGGABLE) == DRAGGABLE) {
System.out.println("Flags are Visible and
Draggable.");
}
}

flags = flags | EDITABLE;

if ((flags & EDITABLE) == EDITABLE) {


System.out.println("Flags are now also Editable.");
}
}
}

3.2.5 Logical Operators

The relational operators you've learned so far (<, <=, >, >=, !=, ==) are sufficient when you only
need to check one condition. However what if a particular action is to be taken only if several
conditions are true? You can use a sequence of if statements to test the conditions, as follows:

if (x == 2) {
if (y != 2) {
System.out.println("Both conditions are true.");
}
}

40
This, however, is hard to write and harder to read. It only gets worse as you add more conditions.
Fortunately, Java provides an easy way to handle multiple conditions: the logic operators. There
are three logic operators, &&, || and !.

&& is logical and. && combines two boolean values and returns a boolean which is true if and only
if both of its operands are true. For instance

boolean b;
b = 3 > 2 && 5 < 7; // b is true
b = 2 > 3 && 5 < 7; // b is now false

|| is logical or. || combines two boolean variables or expressions and returns a result that is true
if either or both of its operands are true. For instance

boolean b;
b = 3 > 2 || 5 < 7; // b is true
b = 2 > 3 || 5 < 7; // b is still true
b = 2 > 3 || 5 > 7; // now b is false

The last logic operator is ! which means not. It reverses the value of a boolean expression. Thus
if b is true !b is false. If b is false !b is true.

boolean b;
b = !(3 > 2); // b is false
b = !(2 > 3); // b is true

These operators allow you to test multiple conditions more easily. For instance the previous
example can now be written as

if (x == 2 && y != 2) {
System.out.println("Both conditions are true.");
}

The Order of Evaluation of Logic Operators

When Java sees a && operator or a ||, the expression on the left side of the operator is evaluated
first. For example, consider the following:

boolean b, c, d;
b = !(3 > 2); // b is false
c = !(2 > 3); // c is true
d = b && c; // d is false

When Java evaluates the expression d = b && c;, it first checks whether b is true. Here b is false,
so b && c must be false regardless of whether c is or is not true, so Java doesn't bother checking
the value of c.

41
On the other hand when faced with an || Java short circuits the evaluation as soon as it encounters
a true value since the resulting expression must be true. This short circuit evaluation is less
important in Java than in C because in Java the operands of && and || must be booleans which
are unlikely to have side effects that depend on whether or not they are evaluated. Still it's
possible to force them. For instance consider this code.

boolean b = (n == 0) || (m/n > 2);

Even if n is zero this line will never cause a division by zero, because the left hand side is always
evaluated first. If n is zero then the left hand side is true and there's no need to evaluate the right
hand side. Mathematically this makes sense because m/0 is in some sense infinite which is
greater than two.

This isn't a perfect solution though because m may be 0 or it may be negative. If m is negative
and n is zero then m/n is negative infinity which is less than two. And if m is also zero, then m/n
is very undefined.

Therefore if there's a real chance your program will have a divide by zero error think carefully
about what it means and how you should respond to it. If, upon reflection, you decide that what
you really want to know is whether m/n is finite and greater than zero you should use a line like
this

boolean b = (n != 0) && (m/n > 0);

The short circuit effect with logical operators

The logical operators (&& and ||) have a slightly peculiar effect in that they perform "short-
circuited" logical AND and logical OR operations. The Java approach makes sense if you
consider that for an AND, if the first operand is false it doesn't matter what the second operand
evaluates to, the overall result will be false. Also for a logical OR, if the first operand has turned
out true, the overall calculation will show up as true because only one evaluation must return true
to return an overall true. This can have an effect with those clever compressed calculations that
depend on side effects. Take the following example.

public class MyClass1{


public static void main(String argv[]){
int Output=10;
boolean b1 = false;
if((b1==true) && ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}
else
{
System.out.println("Not equal! "+Output);
}
}
}

42
The output will be "Not equal 10".  This illustrates that the Output +=10 calculation was never
performed because processing stopped after the first operand was evaluated to be false. If you
change the value of b1 to true processing occurs as you would expect and the output is "We are
equal 20";.

This may be handy sometimes when you really don't want to process the other operations if any
of them return false, but it can be an unexpected side effect if you are not completely familiar
with it.

Avoiding Short Circuits

If you want all of your boolean expressions evaluated regardless of the truth value of each, then
you can use & and | instead of && and ||. However make sure you use these only on boolean
expressions. Unlike && and ||, & and | also have a meaning for numeric types which is
completely different from their meaning for booleans.

3.2.6 Assignment Operators

You use the basic assignment operator, =, to assign one value to another.

The Java programming language also provides several shortcut assignment operators that allow
you to perform an arithmetic, shift, or bitwise operation and an assignment operation all with one
operator. Suppose you wanted to add a number to a variable and assign the result back into the
variable, like this:
i = i + 2;

You can shorten this statement using the shortcut operator +=, like this:
i += 2;

The two previous lines of code are equivalent.

x operation= y is equivalent to x = x operation y

x and y must be numeric or char types except for "=", which allows x and y also to be object references.
In this case, x must be of the same type of class or interface as y. If mixed floating-point and integer
types, the rules for mixed types in expressions apply.

The following table lists the shortcut assignment operators and their lengthy equivalents:

Operator Use Equivalent to


+= op1 += op2 op1 = op1 + op2
-= op1 -= op2 op1 = op1 - op2
*= op1 *= op2 op1 = op1 * op2
/= op1 /= op2 op1 = op1 / op2

43
%= op1 %= op2 op1 = op1 % op2
&= op1 &= op2 op1 = op1 & op2
|= op1 |= op2 op1 = op1 | op2
^= op1 ^= op2 op1 = op1 ^ op2
<<= op1 <<= op2 op1 = op1 << op2
>>= op1 >>= op2 op1 = op1 >> op2
>>>= op1 >>>= op2 op1 = op1 >>> op2

Other Operators

Operator Description
?: Shortcut if-else statement. Conditional or ternary operator
[] Used to declare arrays, create arrays, and access array elements
. Used to form qualified names
( params ) Delimits a comma-separated list of parameters
( type ) Casts (converts) a value to the specified type
new Creates a new object or a new array
instanceof Determines whether its first operand is an instance of its second operand

3.2.7 Ternary or Conditional operator

The ?: operator is a conditional operator that is short-hand for an if-else statement:


op1 ? op2 : op3

The ?: operator returns op2 if op1 is true or returns op3 if op1 is false.

The value of a variable often depends on whether a particular boolean expression is or is not true
and on nothing else. For instance one common operation is setting the value of a variable to the
maximum of two quantities. In Java you might write

if (a > b) {
max = a;
}
else {
max = b;
}

Setting a single variable to one of two states based on a single condition is such a common use of
if-else that a shortcut has been devised for it, the conditional operator, ?:. Using the
conditional operator you can rewrite the above example in a single line like this:

max = (a > b) ? a : b;

(a > b) ? a : b; is an expression which returns one of two values, a or b. The condition, (a


> b), is tested. If it is true the first value, a, is returned. If it is false, the second value, b, is

44
returned. Whichever value is returned is dependent on the conditional test, a > b. The condition
can be any expression which returns a boolean value.

The conditional operator only works for assigning a value to a variable, using a value in a
method invocation, or in some other way that indicates the type of its second and third
arguments. For example, consider the following

if (name.equals("Rumplestiltskin")) {
System.out.println("Give back child");
}
else {
System.out.println("Laugh");
}

This may not be written like this:

name.equals("Rumplestiltskin")
? System.out.println("Give back child")
: System.out.println("Laugh");

First of all, both the second and third arguments are void. Secondly, no assignment is present to
indicate the type that is expected for the second and third arguments (though you know void
must be wrong).

The first argument to the conditional operator must have or return boolean type and the second
and third arguments must return values compatible with the value the entire expression can be
expected to return. You can never use a void method as an argument to the ? : operator.

3.2.8 The [ ] Operator

You use square brackets to declare arrays, to create arrays, and to access a particular element in
an array. Here's an example of an array declaration:
float[] arrayOfFloats = new float[10];

The previous code declares an array that can hold ten floating point numbers. Here's how you
would access the 7th item in that array:
arrayOfFloats[6];

Note that array indices begin at 0.

3.2.9 The . Operator

The dot (.) operator accesses instance members of an object or class members of a class.

3.2.10 The () Operator

45
When declaring or calling a method, you list the method's arguments between ( and ). You can
specify an empty argument list by using () with nothing between them.

3.2.11 The (type) Operator

Casts (or "converts") a value to the specified type.

3.2.12 The new Operator

You use the new operator to create a new object or a new array. Here's an example of creating a
new Integer object from the Integer class in the java.lang package:

Integer anInteger = new Integer(10);

3.2.13 The instanceof Operator

The instanceof operator tests whether its first operand is an instance of its second.

46
op1 instanceof op2

op1 must be the name of an object and op2 must be the name of a class. An object is considered
to be an instance of a class if that object directly or indirectly descends from that class.

3.3 Expressions
An expression produces a result and returns a value. Examples include:

 i = 2 : the assignment puts 2 into the i variable and returns the value 2

 k++ : returns k, then k is incremented by 1


 x < y : logical "less than" comparison, returns a Boolean true or false value
 i | j : returns the value of a bitwise OR operation on bits in the two variables.

Expressions involve at least one operator. A single operator can have 1, 2 or 3 operands.

3.4 Statements
A statement is essentially any complete sentence that causes some action to occur. It can
encompass multiple operators and operands, as well as multiple sub-statements. For example, the
statement
    int x = 1;

declares a variable x and then assigns the value 1 to it. This statement

   x = 5.3 *(4.1 / Math.cos (0.2*y));

consists of several expressions - multiplication, division, a method call to a math function - but is
still considered a single statement.

3.5 Operator Precedence

Highest Precedence
()
++expr --expr +expr -expr ~ !
* / %
+ -
<< >> >>>
< > <= >= instanceof
== !=
&
^
|
&&
||
?:
= += -= *= /= %= &= ^= |= <<= >>= >>>=

47
Lowest Precedence

Overriding Operator Precedence

Parenthesis is used to override operator precedence.

Sometimes the default order of evaluation isn't what you want. For instance, the formula to
change a Fahrenheit temperature to a Celsius temperature is C = (5/9) (F - 32) where C is degrees
Celsius and F is degrees Fahrenheit. You must subtract 32 from the Fahrenheit temperature
before you multiply by 5/9, not after. You can use parentheses to adjust the order much as they
are used in the above formula. The next program prints a table showing the conversions from
Fahrenheit and Celsius between zero and three hundred degrees Fahrenheit every twenty
degrees.

// Print a Fahrenheit to Celsius table

class FahrToCelsius {

public static void main (String args[]) {

// lower limit of temperature table


double lower = 0.0;

// upper limit of temperature table


double upper = 300.0;

// step size
double step = 20.0;

double fahr = lower;


while (fahr <= upper) {
double celsius = (5.0 / 9.0) * (fahr-32.0);
System.out.println(fahr + " " + celsius);
fahr = fahr + step;
}
}
}

Here's the output:

0 -17.7778
20 -6.66667
40 4.44444
60 15.5556
80 26.6667
100 37.7778
120 48.8889
140 60
160 71.1111
180 82.2222

48
200 93.3333
220 104.444
240 115.556
260 126.667
280 137.778
300 148.889

Everything inside the parentheses will be calculated before anything outside of the parentheses is
calculated.

Operator Associativity

The following operators have Right to Left associativity. All other


operators (see precedence table above) are evaluated left to right.

= ?:
*= new
/= (type cast)
%= ++x
+= --x
-= +x
<<= -x
>>= ~
>>>=
&=
^=
|=

3.6 Type Conversion and Casting

Converting one type of data into another must follow the rules of casting. If a conversion results
in the loss of precision, as in an int value converted to a short, then the compiler will issue an
error message unless an explicit cast is made.

To convert type AA data into type BB data, put the type BB name in parentheses in front of the
type AA data:
    AA a = aData;
    BB b = (BB)a; // cast type AA to type BB

For example, to convert integer data to floating point:


    int i=0;
    float f;
    f=(float)i; // Cast int as float

49
Expressions can promote to a wider type without an explicit cast:

    int i=1;  
    long j=3L; // Literals are int types so require L suffix
    j=i;       // OK

However, you can not assign a value to a more narrow type without an explicit cast:
    i=j;       // Error in assigning long to int
    i=(int)j;  // OK

So a data type with lower precision (fewer bits) can be converted to a type of higher precision
without explicit casting. To convert a higher precision type to a lower precision, however, an
explicit cast is required or the compiler will flag an error.

Note that when you cast a value of a wider type down to a more narrow type, such as an int value
to a byte variable, the upper bytes will be truncated. That is, the lowest order byte in the int value
will be copied to the byte value.

Primitive Type Conversion Table


Below is a table that indicates to which of the other primitive types you can cast a given primitive data type. The
symbol C indicates that an explicit cast is required since the precision is decreasing. The symbol A indicates that the
precision is increasing so an automatic cast occurs without the need for an explicit cast. N indicates that the
conversion is not allowed.

  int long float double char byte short boolean


int - A A* A C C C N
long C - A* A* C C C N
float C C - A C C C N
double C C C - C C C N
char A A A A - C C N
byte A A A A C - A N
short A A A A C C - N
boolean N N N N N N N -

The * asterisk indicates that the least significant digits may be lost in the conversion even though
the target type allows for bigger numbers. For example, a large value in an int type value that
uses all 32 bits will lose some of the lower bits when converted to float since the exponent uses 8
bits of the 32 provided for float values.

Mixed Types in an Expression

If an expression holds a mix of types, the lower precision or narrower value operand is converted
to a higher precision or wider type. This result then must be cast if it goes to a lower precision
type:

50
    float x,y=3;
    int j,i=3;
    x= i*y;       // OK since i will be promoted to float
    j= i*y;       // Error since result is a float value
    j= (int)(i*y) // OK

The process of converting a value to a wider or higher precision integer or floating point type is
called "numeric promotion". The Java VM specification states the following rules for promotion
in an expression of two operands, as in x+i:

 If either operand is of type double, the other is converted to double.


 Otherwise, if either operand is of type float, the other is converted to float.
 Otherwise, if either operand is of type long, the other is converted to long.
 Otherwise, both operands are converted to type int.

The program below uses both ints and doubles, for example.

class IntAndDouble {

public static void main (String args[]) {

int i = 10;
double x = 2.5;
double k;

System.out.println("i is " + i);


System.out.println("x is " + x);

k = i + x;
System.out.println("i + x is " + k);
k = i * x;
System.out.println("i * x is " + k);
k = i - x;
System.out.println("i - x is " + k);
k = x - i;
System.out.println("x - i is " + k);
k = i / x;
System.out.println("i / x is " + k);
k = x / i;
System.out.println("x / i is " + k);
}
}

This program produces the following output:

i is 10
x is 2.5
i + x is 12.5
i * x is 25
i - x is 7.5

51
x - i is -7.5
i / x is 4
x / i is 0.25

Order can make a difference when data types are mixed. For example,

1 / 2 * 3.5 = 0.0
3.5 * 1 / 2 = 1.75
3.5 / 2 = 1.75

You cannot assume that the usual mathematical laws of commutativity apply when mixing data
types, especially integer and floating point types.

1.0 / 2 * 3.5 = 1.75


3.5 * 1.0 / 2 = 1.75
1 / 2.0 * 3.5 = 1.75
3.5 * 1.0 / 2.0 = 1.75

3.7 Automatic Type Promotions

An int divided by an int is an int, and a double divided by a double is a double, but what about an
int divided by a double or a double divided by an int? When doing arithmetic on unlike types
Java tends to widen the types involved so as to avoid losing information. After all 3 * 54.2E18
will be a perfectly valid double but much too big for any int.

The basic rule is that if either of the variables in a binary operation (addition, multiplication,
subtraction, addition, remainder) are doubles then Java treats both values as doubles. If neither
value is a double but one is a float, then Java treats both values as floats. If neither is a float or a
double but one is a long, then Java treats both values as longs. Finally if there are no doubles,
floats or longs, then Java treats both values as an int, even if there aren't any ints in the equation.
Therefore the result will be a double, float, long or int depending on the types of the arguments.

In an assignment statement, i.e. if there's an equals sign, Java compares the type of the left hand
side to the final type of the right hand side. It won't change the type of the left hand side, but it
will check to make sure that the value it has (double, float, int or long) on the right hand side
can fit in the type on the left hand side. Anything can fit in a double. Anything except a double
can fit in a float. Any integral type can fit in a long, but a float or a double can't, and ints,
shorts, and bytes can fit inside ints. If the right hand side can fit inside the left hand side, the
assignment takes place with no further ado.

Assigning long values to int variables or double values to float variables can be equally
troublesome. In fact it's so troublesome the compiler won't let you do it unless you tell it you
really mean it with a cast. When it's necessary to force a value into a particular type, use a cast.
To cast a variable or a literal or an expression to a different data type just precede it with the type
in parentheses. For instance:

int i = (int) (9.0/4.0);

52
A cast lets the compiler know that you're serious about the conversion you plan to make.

When a value is cast down before assignment, series of operations takes place to chop the right
hand side down to size. For a conversion between a floating point number and an int or a long,
the fractional part of the floating point number is truncated (rounded toward zero). This produces
an integer. If the integer is small enough to fit in the left hand side, the assignment is completed.
On the other hand if the number is too large, then the integer is set to the largest possible value of
its type. If the floating point number is too small the integer is set to the smallest possible value
of its type.

This can be a nasty bug in your code. It can also be hard to find since everything may work
perfectly 99 times out of a hundred and only on rare occasions will the rounding become a
problem. However when it does there will be no warning or error message. You need to be very
careful when assigning floating point values to integer types.

Summary

This chapter discussed the operators that you can use in Java to manipulate the values of
variables. It included all the standard arithmetic operators, the increment and decrement
operators, the relational operators, the bit-wise operators, and the shift operators. Finally it
discussed the concept of operator precedence that defined the rules by which the order of
operators is evaluated.

Questions

1. class GFM11{
public static void main (String[] args) {
int x,y,z;
System.out.println(x+y+z);
}
}

What is the result of attempting to compile and run the program?

a.  Prints nothing. d.  Prints: 0 g.  None of the above


b.  Prints an undefined value. e.  Run-time error
c.  Prints: null f.  Compile-time error

2. class EBH201 {
public static void main (String[] args) {
int a = 1 || 2 ^ 3 && 5;
int b = ((1 || 2) ^ 3) && 5;
int c = 1 || (2 ^ (3 && 5));
System.out.print(a + "," + b + "," + c);
}
}

53
What is the result of attempting to compile and run the program?

a.  Prints: 0,0,0 e.  Prints: 3,0,0 i.  Run-time error


b.  Prints: 0,0,3 f.  Prints: 3,0,3 j.  Compile-time error
c.  Prints: 0,3,0 g.  Prints: 3,3,0 k.  None of the above
d.  Prints: 0,3,3 h.  Prints: 3,3,3
3. class MCZ24 {
public static void main (String[] args) {
char a = 061; // 1
char b = '\61'; // 2
char c = '\061'; // 3
char d = 0x0031; // 4
char e = '\u0031'; // 5
System.out.print(""+a+b+c+d+e);
}
}

A compile-time error is generated at which line?

a.  1
b.  2
c.  3
d.  4
e.  5
f.  None of the above

54
4. class EBH012 {
public static void main (String[] args) {
byte x = 3, y = 5;
System.out.print((-x == ~x + 1)+","+(-y == ~y + 1));
}
}

What is the result of attempting to compile and run the program?

a.  Prints: false,false d.  Prints: true,true g.  None of the above
b.  Prints: false,true e.  Run-time error
c.  Prints: true,false f.  Compile-time error

5. class EBH007{
public static void main (String[] s) {
byte b = 5; System.out.println(b<<33);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: -1 d.  Prints: 5 g.  Compile-time error


b.  Prints: 0 e.  Prints: 10 h.  None of the above
c.  Prints: 1 f.  Run-time error

6. class EBH106 {
public static void main(String args[]) {
int a = 1; a += ++a + a++; System.out.print(a);
}
}
What is the result of attempting to compile and run the above program?

a.  Prints: 3 d.  Prints: 6 g.  Compile-time error


b.  Prints: 4 e.  Prints: 7 h.  None of the above
c.  Prints: 5 f.  Run-time error

7. class EBH014 {
public static void main (String[] args) {
byte x = 3, y = 5;
System.out.print((y % x) + ",");
System.out.print(y == ((y/x)*x + (y%x)));

55
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 1,true d.  Prints: 2,false g.  None of the above
b.  Prints: 2,true e.  Run-time error
c.  Prints: 1,false f.  Compile-time error

8. class EBH023 {
static String m1(boolean b){return b?"T":"F";}
public static void main(String [] args) {
boolean b1 = false?false:true?false:true?false:true;
boolean b2 = false?false:(true?false:(true?false:true));
boolean b3 = ((false?false:true)?false:true)?false:true;
System.out.println(m1(b1) + m1(b2) + m1(b3));
}
}

What is the result of attempting to compile and run the program?

a.  Prints: FFF e.  Prints: TFF i.  Run-time error


b.  Prints: FFT f.  Prints: TFT j.  Compile-time error
c.  Prints: FTF g.  Prints: TTF k.  None of the above
d.  Prints: FTT h.  Prints: TTT

56
Chapter 4 : Control flow statements
Without control flow statements, the interpreter executes these statements in the order they
appear in the file from left to right, top to bottom. You can use control flow statements in your
programs to conditionally execute statements, to repeatedly execute a block of statements, and to
otherwise change the normal, sequential flow of control.

Statement Type Keyword


looping while, do-while , for
decision making if-else, switch-case
branching break, continue, label:, return
exception handling try-catch-finally, throws,throw

In the sections that follow, you will see the following notation to describe the general form of a
control flow statement:

control flow statement details {


statement(s)
}

Technically, the braces, { and }, are not required if the block contains only one statement.
However, we recommend that you always use { and }, because the code is easier to read and it
helps to prevent errors when modifying code.

4.1 The while and do-while Statements

You use a while statement to continually execute a block of statements while a condition remains
true. The general syntax of the while statement is:

while (expression) {
statement
}

First, the while statement evaluates expression, which must return a boolean value. If the
expression returns true, then the while statement executes the statement(s) associated with it.
The while statement continues testing the expression and executing its block until the expression
returns false.

public class WhileDemo {


public static void main(String[] args) {

int x=10;
while (x != 0) {
System.out.println(x--);
}
}

57
}

This program prints numbers from 10 to 1 in the descending order

The Java programming language provides another statement that is similar to the while
statement--the do-while statement. The general syntax of the do-while is:

do {
statement(s)
} while (expression);

Instead of evaluating the expression at the top of the loop, do-while evaluates the expression at
the bottom. Thus the statements associated with a do-while are executed at least once.
public class DoWhileDemo {
public static void main(String[] args) {

int x=10;
do {
System.out.println(x--);
}
while(x != 0);
}
}

This program prints numbers from 10 to 0 in the descending order

4.2 The for Statement

The for statement provides a compact way to iterate over a range of values. The general form of
the for statement can be expressed like this:

for (initialization; termination; increment) {


statement
}

The initialization is an expression that initializes the loop-it's executed once at the beginning
of the loop. The termination expression determines when to terminate the loop. This
expression is evaluated at the top of each iteration of the loop. When the expression evaluates to
false, the loop terminates. Finally, increment is an expression that gets invoked after each
iteration through the loop. All these components are optional. In fact, to write an infinite loop,
you omit all three expressions:
for ( ; ; ) { // infinite loop
...
}

The for loop in the sample program iterates over each element of anArray, assigning values to its
elements. The for loop uses anArray.length to determine when to terminate the loop.

58
Here's a simple program, called ArrayDemo, that creates the array, puts some values in it, and
displays the values.

public class ArrayDemo {


public static void main(String[] args) {
int[] anArray; // declare an array of integers
anArray = new int[10]; // create an array of integers
// assign a value to each array element and print
for (int i = 0; i < anArray.length; i++) {
anArray[i] = i;
System.out.print(anArray[i] + " ");
}
System.out.println();
}
}

Often for loops are used to iterate over the elements in an array, or the characters in a string.

public class ForDemo {


public static void main(String[] args) {
int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076,
2000, 8, 622, 127 };
for (int i = 0; i < arrayOfInts.length; i++) {
System.out.print(arrayOfInts[i] + " ");
}
System.out.println();
}
}

Note that you can declare a local variable within the initialization expression of a for loop. The
scope of this variable extends from its declaration to the end of the block governed by the for
statement so it can be used in the termination and increment expressions as well. If the variable
that controls a for loop is not needed outside of the loop, it's best to declare the variable in the
initialization expression. The names i, j, and k are often used to control for loops; declaring
them within the for loop initialization expression limits their life-span and reduces errors.

The expression x[i] selects the ith one-dimensional array; the expression x[i][j] selects the jth
element from that array.

public class ArrayofArraysDemo1 {


public static void main(String args[]) {
int [] [] x = new int [3][5];
int k=0;
for(int i = 0 ; i < 3 ; i++) {
for (int j = 0; j < 5 ; j++) {
x[i][j] = k++;
}
}
for(int i = 0 ; i < x.length ; i++) {

59
for (int j = 0; j < x[i].length ; j++) {
System.out.print(x[i][j] + ‘\t’);
}
System.out.println();
}
}
}

Enhanced for loop (added with Java 5.0)

for (type value : container) statement

This for statement was created especially for collections and arrays. An example to print all
elements in the array.

public class ForEachDemo {


public static void main(String[] args) {
int[] arrayOfInts = { 32, 87, 3, 589, 12,
1076, 2000, 8, 622, 127
};

for (int element : arrayOfInts) {


System.out.print(element + " ");
}
System.out.println();
}
}

You can read the for statement in the preceding snippet like this: For each int element in
arrayOfInts...

4.3 The if/else Statements

All but the most trivial computer programs need to make decisions. They test a condition and
operate differently based on the outcome of the test. This is quite common in real life. For
instance you stick your hand out the window to test if it's raining. If it is raining then you take an
umbrella with you. If it isn't raining then you don't.

All programming languages have some form of an if statement that tests conditions.

This is the simplest version of the if statement: The block governed by the if is executed if a
condition is true. Generally, the simple form of if can be written like this:
if (expression) {
statement(s)
}

60
The arguments to a conditional statement like if must be a boolean value, that is something that
evaluates to true or false. Integers are not permissible.

class HelloProgram {
public static void main(String args[]) {
int x=10;
if(x%10 == 0) {
System.out.println(“Number is divisible by 10”);
}
}
}

In Java numerical greater than and lesser than tests are done with the > and < operators
respectively. You can test whether a number is less than or equal to or greater than or equal to
another number with the <= and >= operators.

It's not uncommon for even experienced programmers to write == when they mean = or vice
versa. Fortunately in Java, you are not allowed to use == and = in the same places. Therefore the
compiler can catch your mistake and make you fix it before you can run the program.

However there is one way you can still get into trouble:

boolean b = true;
if (b = false) {
System.out.println("b is false");
}

To avoid this, some programmers get in the habit of writing condition tests like this:

boolean b = true;
if (false = b) {
System.out.println("b is false");
}

Since you can't assign to a literal, this causes a compiler error if you misuse the = sign when you
mean to write ==.

Using the else statement

class HelloProgram {
public static void main(String args[]) {
int x=10;
if(x%10 == 0) {
System.out.println(“Number is divisible by 10”);
}
else {
System.out.println(“Number is not divisible by 10”);
}
}

61
}

Nested if/else statements

Nested if..else statement is writing an if..else statement into an if block or an else block. There
can be any level of nested if..else statement. Some forms are given below

1. if(condition){
// code to run
if(condition){
// code to run
}
else
{
// other code to run
}
}

2. if(condition){
// code to run
if(condition){
// code to run
}
}
else{
// other code to run
}

3. boolean flag = true;


  if (flag)
{
int flag2 = 1;
if (flag2 < 0)
{
// Do something!
}
else
{
// Do something!
}
}
else
{
// Do something!
}

Example:
if (i == j) {
if (j == k)
System.out.println("i equals k");
}
else {
System.out.println("i doesn't equal j");
}

62
if..else if ladder

The else block is executed if the if part is false. Another form of the else statement, else if,
executes a statement based on another expression. An if statement can have any number of
companion else if statements but only one else.

public class IfElseDemo {


public static void main(String[] args) {

int testscore = 76;


char grade;

if (testscore >= 90) {


grade = 'A';
} else if (testscore >= 80) {
grade = 'B';
} else if (testscore >= 70) {
grade = 'C';
} else if (testscore >= 60) {
grade = 'D';
} else {
grade = 'F';
}
System.out.println("Grade = " + grade);
}
}

4.4 The switch Statement

Use the switch statement to conditionally perform statements based on an integer expression.
public class SwitchDemo {
public static void main(String[] args) {
int month = 8;
switch (month) {
case 1: System.out.println("January"); break;
case 2: System.out.println("February"); break;
case 3: System.out.println("March"); break;
case 4: System.out.println("April"); break;
case 5: System.out.println("May"); break;
case 6: System.out.println("June"); break;
case 7: System.out.println("July"); break;
case 8: System.out.println("August"); break;
case 9: System.out.println("September"); break;
case 10: System.out.println("October"); break;
case 11: System.out.println("November"); break;
case 12: System.out.println("December"); break;
}
}

63
}

The switch statement evaluates its expression, in this case the value of month, and executes the
appropriate case statement.

int month = 8;
if (month == 1) {
System.out.println("January");
} else if (month == 2) {
System.out.println("February");
}
. . . // and so on

Deciding whether to use an if statement or a switch statement is a judgment call. You can
decide which to use, based on readability and other factors. An if 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 value. Also, the value provided to each case statement
must be unique.

Another point of interest in the switch statement is the break statement after each case. Each
break statement terminates the enclosing switch statement, and the flow of control continues
with the first statement following the switch block. The break statements are necessary
because without them, the case statements fall through. That is, without an explicit break,
control will flow sequentially through subsequent case statements.

public class SwitchDemo2 {


public static void main(String[] args) {

int month = 2;
int year = 2000;
int numDays = 0;

switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
numDays = 31;
break;
case 4:
case 6:
case 9:
case 11:
numDays = 30;
break;
case 2:

64
if (((year % 4 == 0) && !(year % 100 == 0))
|| (year % 400 == 0) )
numDays = 29;
else
numDays = 28;
break;
}
System.out.println("Number of Days = " + numDays);
}
}

Technically, the final break is not required because flow would fall out of the switch statement
anyway. However, we recommend using a break for the last case statement just in case you
need to add more case statements at a later date. This makes modifying the code easier and less
error-prone.

Finally, you can use the default statement at the end of the switch to handle all values that aren't
explicitly handled by one of the case statements.

The variable or expression in the switch statement can be of only int or byte or short or char data
types.

4.5 Branching Statements

The Java programming language supports three branching statements:


 The break statement
 The continue statement
 The return statement

label is an identifier placed before a statement. The label is followed by a colon (:):
statementName: someJavaStatement;

4.5.1 The break Statement

The break statement has two forms: unlabeled and labeled. An unlabeled break terminates the
enclosing switch statement, and flow of control transfers to the statement immediately
following the switch. You can also use the unlabeled form of the break statement to terminate
a for, while, or do-while loop.

public static void main(String[] args) {


int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076,
2000, 8, 622, 127 };
int searchfor = 12;
int i = 0;
boolean foundIt = false;
for ( ; i < arrayOfInts.length; i++) {
if (arrayOfInts[i] == searchfor) {
foundIt = true;

65
break;
}
}

if (foundIt) {
System.out.println("Found "+ searchfor +" at index "+ i);
}
else {
System.out.println(searchfor + "not in the array");
}
}
}

The break statement terminates the labeled statement; it does not transfer the flow of control to
the label. The flow of control transfers to the statement immediately following the labeled
(terminated) statement.

public static void main(String[] args) {

int[][] arrayOfInts = { { 32, 87, 3, 589 },


{ 12, 1076, 2000, 8 },
{ 622, 127, 77, 955 }
};
int searchfor = 12;

int i = 0;
int j = 0;
boolean foundIt = false;

search:
for ( ; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length; j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search;
}
}
}

if (foundIt) {
System.out.println("Found "+searchfor+" at "+i+", " + j);
}
else {
System.out.println(searchfor + "not in the array");
}
}
}

4.5.2 The continue Statement

66
You use the continue statement to skip the current iteration of a for, while , or do-while loop.
The unlabeled form skips to the end of the innermost loop's body and evaluates the boolean
expression that controls the loop, basically skipping the remainder of this iteration of the loop.

The labeled form of the continue statement skips the current iteration of an outer loop marked
with the given label.

A continue statement returns to the beginning of the innermost enclosing loop without
completing the rest of the statements in the body of the loop. If you're in a for loop, the counter
is incremented. For example this code fragment skips even elements of an array

for (int i = 0; i < m.length; i++) {


if (m[i] % 2 == 0) continue;
// process odd elements...
}

The continue statement is rarely used in practice, perhaps because most of the instances where
it's useful have simpler implementations. For instance, the above fragment could equally well
have been written as

for (int i = 0; i < m.length; i++) {


if (m[i] % 2 != 0) {
// process odd elements...
}
}

continue with label

public class ContinueWithLabelDemo {


public static void main(String[] args) {

String searchMe = "Look for a substring in me";


String substring = "sub";
boolean foundIt = false;

int max = searchMe.length() - substring.length();

test:
for (int i = 0; i <= max; i++) {
int n = substring.length();
int j = i;
int k = 0;
while (n-- != 0) {
if (searchMe.charAt(j++)
!= substring.charAt(k++)) {
continue test;
}
}
foundIt = true;
break test;

67
}
System.out.println(foundIt ? "Found it" :
"Didn't find it");
}
}

Here is the output from this program:


Found it

4.5.3 The return Statement

You use return to exit from the current method. The flow of control returns to the statement
that follows the original method call. The return statement has two forms: one that returns a
value and one that doesn't. To return a value, simply put the value (or an expression that
calculates the value) after the return keyword:

return ++count;

The data type of the value returned by return must match the type of the method's declared
return value. When a method is declared void, use the form of return that doesn't return a
value:

return;

4.6 Exception Handling Statements

The Java programming language provides a mechanism known as exceptions to help programs
report and handle errors. When an error occurs, the program throws an exception. It means that
the normal flow of the program is interrupted and that the runtime environment attempts to find
an exception handler--a block of code that can handle a particular type of error. The exception
handler can attempt to recover from the error or, if it determines that the error is unrecoverable,
provide a gentle exit from the program.

Three statements play a part in handling exceptions:


 The try statement identifies a block of statements within which an exception might be
thrown.
 The catch statement must be associated with a try statement and identifies a block of
statements that can handle a particular type of exception. The statements are executed if
an exception of a particular type occurs within the try block.
 The finally statement must be associated with a try statement and identifies a block of
statements that are executed regardless of whether or not an error occurs within the try
block.

Here's the general form of these statements:

try {

68
statement(s)
} catch (exceptiontype name) {
statement(s)
} finally {
statement(s)
}

Summary

For controlling the flow of a program, the Java programming language has three loop constructs,
a flexible if-else statement, a switch statement, exception-handling statements, and branching
statements.

Use the while statement to loop over a block of statements while a boolean expression remains
true. Use the do-while statement to loop over a block of statements while a boolean expression
remains true. The expression is evaluated at the bottom of the loop, so the statements within the
do-while block execute at least once. The for statement loops over a block of statements and
includes an initialization expression, a termination condition expression, and an increment
expression

The Java programming language has two decision-making statements: if-else and switch. The
more general-purpose statement is if; use switch to make multiple-choice decisions based on a
single integer value.

Some branching statements change the flow of control in a program to a labeled statement. You
label a statement by placing a legal identifier (the label) followed by a colon ( :) before the
statemen. Use the unlabeled form of the break statement to terminate the innermost switch,
for, while, or do-while statement. Use the labeled form of the break statement to terminate an
outer switch, for, while, or do-while statement with the given label. A continue statement
terminates the current iteration of the innermost loop and evaluates the boolean expression that
controls the loop. The labeled form of the continue statement skips the current iteration of the
loop with the given label. Use return to terminate the current method. You can return a value to
the method's caller, by using the form of return that takes a value.

Questions

1. class Black {
public static void main(String args[]) {
int[] i = {1,2,3,4,5}; // 1
long[] l = new long[5]; // 2
for (int j = 0; j < l.length(); j++) { // 3
l[j] = i[j]; // 4
}
}
}

A compile-time error is generated at which line?

69
a.  1
b.  2
c.  3
d.  4
e.  None of the above

70
2. class MWC206 {
public static void main (String[] args) {
int[][] a1 = {{1,2,3},{4,5,6},{7,8,9}};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(a1[j][i]);
}
}
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 123456789 d.  Prints: 369258147 g.  None of the above
b.  Prints: 147258369 e.  Run-time error
c.  Prints: 321654987 f.  Compile-time error

3. class JMM102 {
public static void main(String args[]) {
for (int i = 0; i<5 ;i++) {
switch(i) {
case 0: System.out.print("v ");break;
case 1: System.out.print("w ");
case 2: System.out.print("x ");break;
case 3: System.out.print("y ");
case 4: System.out.print("z ");break;
default: System.out.print("d ");
}
}
}
}
What is the result of attempting to compile and run the program?

a.  Prints: v w x y z d.  Prints: v w w x y y z d g.  Compile-time error


b.  Prints: v w x y z d e.  Prints: d d d d d d h.  None of the above
c.  Prints: v w x x y z z f.  Run-time error

4. class JMM105 {
public static void main(String args[]) {
int x = 6; int success = 0;
do {
switch(x) {
case 0: System.out.print("0"); x += 5; break;
case 1: System.out.print("1"); x += 3; break;
case 2: System.out.print("2"); x += 1; break;
case 3: System.out.print("3"); success++; break;
case 4: System.out.print("4"); x -= 1; break;
case 5: System.out.print("5"); x -= 4; break;

71
case 6: System.out.print("6"); x -= 5; break;
}
} while ((x != 3) || (success < 2));
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 60514233 c.  Prints: 61433 e.  Run-time error


b.  Prints: 6152433 d.  Prints: 6143 f.  Compile-time error

72
Chapter 5 : Class Fundamentals and OOP
5.1 What Is an Object?

The real-world objects share two characteristics: They all have state and behavior. Software
objects are modeled after real-world objects in that they too have state and behavior. A software
object maintains its state in one or more variables. A software object implements its behavior
with methods. A method is a function (subroutine) associated with an object.

You can represent real-world objects by using software objects.

The following illustration is a common visual representation of a software object:

Everything that the software object knows (state) and can do (behavior) is expressed by the
variables and the methods within that object.

A particular object is called an instance.

The object diagrams show that the object's variables make up the center, or nucleus, of the
object. Methods surround and hide the object's nucleus from other objects in the program.
Packaging an object's variables within the protective custody of its methods is called
encapsulation This conceptual picture of an object-a nucleus of variables packaged within a
protective membrane of methods-is an ideal representation of an object and is the ideal that
designers of object-oriented systems strive for. The access level determines which other objects
and classes can access that variable or method.

Encapsulating related variables and methods into a neat software bundle is a simple yet powerful
idea that provides two primary benefits to software developers:

 Modularity: The source code for an object can be written and maintained independently
of the source code for other objects. Also, an object can be easily passed around in the
system.
 Information hiding: An object has a public interface that other objects can use to
communicate with it. The object can maintain private information and methods that can
be changed at any time without affecting the other objects that depend on it.

73
5.2 What Is a Class?

A class is a blueprint, or prototype, that defines the variables and the methods common to all
objects of a certain kind.

Object is an instance of the class.

The role of classes in Java

Classes are the heart of Java, all Java code occurs within a class. There is no concept of free
standing code and even the most simple application involves the creation of a class.

5.3 What Is a Message?

A single object alone is generally not very useful. Instead, an object usually appears as a
component of a larger program or application that contains many other objects. Through the
interaction of these objects, programmers achieve higher-order functionality and more complex
behavior. Your bicycle hanging from a hook in the garage is just a bunch of metal and rubber; by
itself, the bicycle is incapable of any activity. The bicycle is useful only when another object
(you) interacts with it (pedal).

Software objects interact and communicate with each other by sending messages to each other.
When object A wants object B to perform one of B's methods, object A sends a message to
object B (see the following figure).

Sometimes, the receiving object needs more information so that it knows exactly what to do; for
example, when you want to change gears on your bicycle, you have to indicate which gear you
want. This information is passed along with the message as parameters.

The next figure shows the three parts of a message:

74
 The object to which the message is addressed (YourBicycle)
 The name of the method to perform (changeGears)
 Any parameters needed by the method (lowerGear)

These three components are enough information for the receiving object to perform the desired
method. No other information or context is required.

Messages provide two important benefits.

 An object's behavior is expressed through its methods, so (aside from direct variable
access) message passing supports all possible interactions between objects.
 Objects don't need to be in the same process or even on the same machine to send and
receive messages back and forth to each other.

5.4 Features of Object Oriented Programming

There are four features of OOP.


 Encapsulation
 Inheritance
 Polymorphism
 Abstraction

5.4.1 Encapsulation

Encapsulation is the principal of keeping the internal details of a classes state and behaviours
hidden from the other classes that use it. This allows you to change those details where
necessary, without breaking compatibility. The interconnectness between pieces of code is
called 'coupling', and minimising it makes for more reusable and maintainable classes. The
expectated behaviour of a class or method is referred to as its 'contract'. You do not want to

75
expose any more than the minimum required to support the contract, or you can end up with
tangled interdependent code with poor maintainabilty, and in all likelyhood, poor quality.

Encapsulation also aids polymorphism and inheritance - if the internal details of a class are
exposed and used, it is very hard to substitute a different implementation of the same contract.

To achieve good encapsulation, make everything have the tightest possible access control so if
something should not be used in a given context, limit the access to prohibit it.

Encapsulation involves hiding data of a class and allowing access only through a public
interface.

5.4.2 Inheritance

Generally speaking, objects are defined in terms of classes. You know a lot about an object by
knowing its class. Even if you don't know what a penny-farthing is, if we tell you it was a
bicycle, you would know that it had two wheels, handle bars, and pedals.

Object-oriented systems take this a step further and allow classes to be defined in terms of other
classes. For example, mountain bikes, road bikes, and tandems are all kinds of bicycles. In
object-oriented terminology, mountain bikes, road bikes, and tandems are all subclasses of the
bicycle class. Similarly, the bicycle class is the superclass of mountain bikes, road bikes, and
tandems. This relationship is shown in the following figure.

Each subclass inherits state and behavior from the superclass. Mountain bikes, road bikes, and
tandems share some states: cadence, speed, and the like. Also, each subclass inherits methods
from the superclass. Mountain bikes, road bikes, and tandems share some behaviors: braking and
changing pedaling speed, for example.

76
However, subclasses are not limited to the state and behaviors provided to them by their
superclass. Subclasses can add variables and methods to the ones they inherit from the
superclass.

Subclasses can also override inherited methods and provide specialized implementations for
those methods.

The inheritance tree, or class hierarchy, can be as deep as needed. Methods and variables are
inherited down through the levels. In general, the farther down in the hierarchy a class appears,
the more specialized its behavior.

Note: Class hierarchies should reflect what the classes are. If we implemented a tricycle class, it
might be convenient to make it a subclass of the bicycle class — after all, both tricycles and
bicycles have a current speed and cadence — but because a tricycle is not a bicycle, it's unwise
to publicly tie the two classes together. It could confuse users, make the tricycle class have
methods (such as "change gears") that it doesn't need, and make updating or improving the
tricycle class difficult.

The Object class is at the top of class hierarchy, and each class is its descendant (directly or
indirectly). A variable of type Object can hold a reference to any object, such as an instance of
a class or an array. Object provides behaviors that are required of all objects running in the Java
Virtual Machine.

Inheritance offers the following benefits:

 Subclasses provide specialized behaviors from the basis of common elements provided
by the superclass. Through the use of inheritance, programmers can reuse the code in the
superclass many times.
 Programmers can implement superclasses called abstract classes that define "generic"
behaviors. The abstract superclass defines and may partially implement the behavior, but
much of the class is undefined and unimplemented. Other programmers fill in the details
with specialized subclasses.

5.4.3 Polymorphism

The word polymorphism comes from the Greek for "many forms." It allows one interface to be
used for a general class of action. The specific action is determined by the exact nature of the
situation. Consider a stack. You might have a program that requires three types of stacks. One
stack is used for integer values, one for floating point values and one for characters. The
algorithm that implements each stack is same, even though the data being stored is different. In
an non-object-oriented-programming language, you would require three different sets of stack
routines, with each set using different names. However, because of polymorphism, in Java you
can specify a general set of stack routines that all share same names.

The concept of polymorphism is expressed by the phrase “one interface, multiple methods”. This
means that it is possible to design a generic interface to a group of related activities. This helps

77
reduce complexity by allowing the same interface to be used to specify a general class of action.
It is the compiler’s job to select the specific action (i.e method) as it applies to each situation.
You do not need to make the selection manually. You need only remember to utilize the general
interface.

Polymorphism in Java is implemented with Method Overloading and Overriding.

5.4.4 Abstraction

Humans manage complexity through abstraction. For example, people do not think of a car as a
set of tens of thousands of individual parts. They think of it as a well defined object with its own
unique behavior. This abstraction allows people to use a car to drive to the grocery store without
being overwhelmed by the complexity of thje parts that form the car. They can ignore the details
of how the engine, transmission, and braking systems work. Instead they are free to utilize the
object as a whole.

Abstraction is hiding the irrelevant details and knowing only the relevant ones.

5.5 Defining Classes

The general syntax for defining a class in Java is shown below.

class MyClassName{
  . . .

} //End of class definition.

This syntax defines a class and creates a new type named MyClassName.

5.6 Creating Objects

Declaring a Variable to Refer to an Object

The declared type matches the class of the object:

MyClass myObject = new MyClass();

The declared type is a parent class of the object's class:

MyParent myObject = new MyClass();

The declared type is an interface which the object's class implements:

MyInterface myObject = new MyClass();

You can also declare a variable on its own line, such as:

78
MyClass myObject;

When you use this approach, the value of myObject will be automatically set to null until an
object is actually created and assigned to it. Remember, variable declaration alone does not
actually create an object.

A variable in this state, which currently references no object, is said to hold a null reference.

Instantiating a Class

The new operator instantiates a class by allocating memory for a new object.

Note: The phrase "instantiating a class" means the same thing as "creating an object"; you can
think of the two as being synonymous. When you create an object, you are creating an instance
of a class, therefore "instantiating" a class.

The new operator requires a single, postfix argument: a call to a constructor. The name of the
constructor provides the name of the class to instantiate. The constructor initializes the new
object.

The new operator returns a reference to the object it created. Often, this reference is assigned to a
variable of the appropriate type. If the reference is not assigned to a variable, the object is
unreachable after the statement in which the new operator appears finishes executing.

5.7 Defining Methods in a class

Classes usually consists of two things: instance variables and methods. The general form of a
method is as follows:

type name (parameter-list) {


// body of method
}

The type specifies the return type of the method. This can be any valid type, including class
types that you create. If the method does not return a value, its return type must be void. The
name of the method is specified by name. This can be any legal identifier other than those
already used by other items within the current scope. The parameter-list is a sequence of type
and identifier pairs separated by commas. Parameters are essentially variables that receive the
value of the arguments passed to the method when it is called. If the method has no parameters,
then the parameter list will be empty.

Method Declaration Elements


Element Function
accessLevel (Optional) Access level for the method
static (Optional) Declares a class method

79
abstract (Optional) Indicates that the method is not implemented
final (Optional) Indicates that the method cannot be overridden
native (Optional) Indicates that the method is implemented in another
language
synchronized (Optional) The method requires a monitor to run
returnType The method's return type and name
methodName
( paramList ) The list of arguments to the method
throws exceptions (Optional) The exceptions thrown by the method

Each element of a method declaration can be further defined and is discussed as indicated in the
following list:

accessLevel
As with member variables, you control which other classes have access to a method using
one of four access levels: public, protected, package, and private

static
As with member variables, static declares this method as a class method rather than an
instance method.

abstract
An abstract method has no implementation and must be a member of an abstract class.

final
A final method cannot be overridden by subclasses

native
If you have a significant library of functions written in another language, such as C, you
may wish to preserve that investment and to use those functions from a program written
in the Java programming language. Methods implemented in another language are called
native methods and are declared as such using the native keyword

synchronized
Concurrently running threads often invoke methods that operate on the same data. Mark
these methods with the synchronized keyword to ensure that the threads access
information in a thread-safe manner.

returnType
A method must declare the data type of the value that it returns. If your method does not
return a value, use the keyword void for the return type.
methodName
A method name can be any legal identifier. You need to consider code conventions, name
overloading, and method overriding when naming a method.

( paramlist )
You pass information into a method through its arguments.

80
throws exceptionList
If your method throws any checked exceptions, your method declaration must indicate
the type of those exceptions.

Two of these components comprise the method signature: the method's name and the parameter
list.

Methods that have return type other than void return a value to the calling routine using the
following form of return statement:

return value;

Here, value is the value returned.

Let’s add a method to a Box class.

class Box {
double width, height, depth;

void volume() {
System.out.println(“Volume is :”+
(width * depth * height));
}
}

class BoxDemo {
public static void main(String args[]) {
Box mybox1 = new Box();
mybox1.width = 10;
mybox1.height = 20;
mybox1.depth = 30;
mybox1.volume();
}
}

Naming a Method

Although a method name can be any legal identifier, code conventions restrict method names. In
general, method names should be verbs and should be in mixed case, with the first letter in
lowercase and the first letter of each internal word in uppercase. Here are some examples:

toString
compareTo
isDefined
setX
getX

81
The JavaBeans architecture naming conventions further describe how to name methods for
setting and getting properties.

Passing information to a method

The declaration for a method declares the number and the type of the arguments for that method
or constructor. For example, the following is a method that computes the monthly payments for a
home loan, based on the amount of the loan, the interest rate, the length of the loan (the number
of periods), and the future value of the loan:

public double computePayment(double loanAmt, double rate,


double futureValue,
int numPeriods) {
double I, partial1, denominator, answer;
I = rate / 100.0;
partial1 = Math.pow((1 + I), (0.0 - numPeriods));
denominator = (1 - partial1) / I;
answer = ((-1 * loanAmt) / denominator)
- ((futureValue * partial1) / denominator);
return answer;
}

This method takes four arguments: the loan amount, the interest rate, the future value and the
number of periods. The first three are double-precision floating point numbers, and the fourth is
an integer.

As with this method, the set of arguments to any method or constructor is a comma-separated list
of variable declarations, where each variable declaration is a type/name pair. As you can see
from the body of the computePayment method, you simply use the argument name to refer to the
argument's value.

Argument Types

You can pass an argument of any data type into a method. This includes primitive data types,
such as doubles, floats, and integers, as you saw in the computePayment method, and reference
data types, such as classes and arrays. Here's an example of a factory method that accepts an
array as an argument. In this example, the method creates a new Polygon object and initializes it
from a list of Points (assume that Point is a class that represents an x, y coordinate):

public Polygon polygonFrom(Point[] listOfPoints) {


...
}

The Java programming language doesn't let you pass methods into methods. But you can pass an
object into a method and then invoke the object's methods.

Argument Names

82
When you declare an argument to a method, you provide a name for that argument. This name is
used within the method body to refer to the data.

The name of an argument must be unique in its scope. It cannot be the same as the name of
another argument for the same method or constructor, the name of a local variable within the
method or constructor, or the name of any parameter to a catch clause within the same method or
constructor.

An argument can have the same name as one of the class's member variables. If this is the case,
the argument is said to shadow the member variable. Shadowing member variables can make
your code difficult to read and is conventionally used only within methods that set a particular
member variable. For example, consider the following Circle class and its setOrigin method:

public class Circle {


private int x, y, radius;
public void setOrigin(int x, int y) {
...
}
}

The Circle class has three member variables: x, y, and radius. The setOrigin method accepts
two arguments, each of which has the same name as one of the member variables. Each method
argument shadows the member variable that shares its name. So using the simple names x or y
within the body of the method refers to the argument, not to the member variable. To access the
member variable, you must use a qualified name.

Returning a Value from a Method

You declare a method's return type in its method declaration. Within the body of the method, you
use the return statement to return the value. Any method declared void doesn't return a value
and cannot contain a return statement. Any method that is not declared void must contain a
return statement.

Let's look at the isEmpty method in the Stack class:

public boolean isEmpty() {


if (items.size() == 0) {
return true;
} else {
return false;
}
}

The data type of the return value must match the method's declared return type; you can't return
an integer value from a method declared to return a boolean. The declared return type for the
isEmpty method is boolean, and the implementation of the method returns the boolean value
true or false, depending on the outcome of a test.

83
The isEmpty method returns a primitive type. A method can return a reference type. For
example, Stack declares the pop method that returns the Object reference type:

public Object pop() {


if (top == 0) {
throw new EmptyStackException();
}
Object obj = items[--top];
items[top]=null;
return obj;
}

When a method uses a class name as its return type, such as pop does, the class of the type of the
returned object must be either a subclass of or the exact class of the return type. Suppose that you
have a class hierarchy in which ImaginaryNumber is a subclass of java.lang.Number, which is
in turn a subclass of Object, as illustrated in the following figure.

84
Now suppose that you have a method declared to return a Number:
public Number returnANumber() {
...
}

The returnANumber method can return an ImaginaryNumber but not an Object.


ImaginaryNumber is a Number because it's a subclass of Number. However, an Object is not
necessarily a Number — it could be a String or another type.

You also can use interface names as return types. In this case, the object returned must
implement the specified interface.

5.8 Declaring Variables in a Class

Stack uses the following line of code to define its variables:


class Stack {
int top;
}

This code declares member variable and not other types of variable, such as local variable,
because the declaration appears within the class body but outside any methods.

Variable Declaration Elements


Element Function
accessLeve (Optional) Access level for the variable
l
static (Optional) Declares a class variable
final (Optional) Indicates that the variable is a constant
transient (Optional) Indicates that the variable is transient
volatile (Optional) Indicates that the variable is volatile
type name The type and name of the variable

Each component of a member variable declaration is further defined and discussed in later
sections of this chapter, as follows:

accessLevel
Lets you control what other classes have access to a member variable by specifying one
of four access levels: public, protected, package, and private.

static
Declares this is a class variable rather than an instance variable.

final
Indicates that the value of this member cannot change.

transient

85
Marks member variables that should not be serialized.

volatile
Prevents the compiler from performing certain optimizations on a member

type
Like other variables, a member variable must have a type. You can use primitive type
names such as int, float, or boolean. Or you can use reference types, such as array,
object, or interface names.

name
A member variable's name can be any legal identifier and, by convention, begins with a
lowercase letter. A member variable cannot have the same name as any other member
variable in the same class.

Automatic local variables

Automatic variables are method variables. They come into scope when the method code starts to
execute and cease to exist once the method goes out of scope. As they are only visible within the
method they are typically useful for temporary manipulation of data. If you want a value to
persist between calls to a method then a variable needs to be created at class level.

Variable Initialization

Local variables and member variables can be initialized with an assignment statement when
they're declared. Local variables have to explicitly initialized before their use. The data type of
the variable must match the data type of the value assigned to it.

char aChar = 'S';


boolean aBoolean = true;

Parameters and exception-handler parameters cannot be initialized in this way. The value for a
parameter is set by the caller.

Variable Scope
A variable's scope is the region of a program within which the variable can be referred to by its
simple name. Secondarily, scope also determines when the system creates and destroys memory
for the variable. Scope is distinct from visibility, which applies only to member variables and
determines whether the variable can be used from outside of the class within which it is declared.
Visibility is set with an access modifier. The location of the variable declaration within your
program establishes its scope and places it into one of these four categories:
 member variable
 local variable
 method parameter
 exception-handler parameter

86
A member variable is a member of a class or an object. It is declared within a class but outside
of any method or constructor. A member variable's scope is the entire declaration of the class.
However, the declaration of a member needs to appear before it is used when the use is in a
member initialization expression.

You declare local variables within a block of code. In general, the scope of a local variable
extends from its declaration to the end of the code block in which it was declared. The scope of
each variable in that program extends from the declaration of the variable to the end of the main
method --indicated by the first right curly bracket } in the program code.

Parameters are formal arguments to methods or constructors and are used to pass values into
methods and constructors. The scope of a parameter is the entire method or constructor for
which it is a parameter.

Exception-handler parameters are similar to parameters but are arguments to an exception


handler rather than to a method or a constructor. The scope of an exception-handler parameter is
the code block between { and } that follow a catch statement.

if (...) {
int i = 17;
...
}
System.out.println("The value of i = " + i); // error

The final line won't compile because the local variable i is out of scope. The scope of i is the
block of code between the { and }. The i variable does not exist anymore after the closing }.
Either the variable declaration needs to be moved outside of the if statement block, or the
println method call needs to be moved into the if statement block.

5.9 Instance and Class Members

When you declare a member variable such as aFloat in MyClass:

class MyClass {

87
float aFloat;
}

you declare an instance variable. Every time you create an instance of a class, the runtime
system creates one copy of each the class's instance variables for the instance.

Instance variables are in constrast to class variables (which you declare using the static
modifier). The runtime system allocates class variables once per class regardless of the number
of instances created of that class. The system allocates memory for class variables the first time it
encounters the class. All instances share the same copy of the class's class variables. You can
access class variables through an instance or through the class itself.

Methods are similar: your classes can have instance methods and class methods. Instance
methods operate on the current object's instance variables but also have access to the class
variables. Class methods, on the other hand, cannot access the instance variables declared within
the class (unless it creates a new object and accesses them through the object). Also, class
methods can be invoked on the class, you don't need an instance to call a class method.

By default, unless otherwise specified, a member declared within a class is an instance member.
The class defined below has one instance variable--an integer named x--and two instance
methods--x() and setX()--that let other objects set and query the value of x:

class AnIntegerNamedX {
int x;
public int x() {
return x;
}
public void setX(int newX) {
x = newX;
}
}

Every time you instantiate a new object from a class, you get a new copy of each of the class's
instance variables. These copies are associated with the new object. So, every time you
instantiate a new AnIntegerNamedX object from the class, you get a new copy of x that is
associated with the new AnIntegerNamedX object.

All instances of a class share the same implementation of an instance method; all instances of
AnIntegerNamedX share the same implementation of x() and setX(). Note that both methods, x()
and setX(), refer to the object's instance variable x by name. "But", you ask, "if all instances of
AnIntegerNamedX share the same implementation of x() and setX() isn't this ambiguous?" The
answer is no. Within an instance method, the name of an instance variable refers to the current
object's instance variable (assuming that the instance variable isn't hidden by a method
parameter).

Objects outside of AnIntegerNamedX that wish to access x must do so through a particular


instance of AnIntegerNamedX. Suppose that this code snippet was in another object's method. It

88
creates two different objects of type AnIntegerNamedX, sets their x values to different values,
then displays them:

. . .
AnIntegerNamedX myX = new AnIntegerNamedX();
AnIntegerNamedX anotherX = new AnIntegerNamedX();
myX.setX(1);
anotherX.x = 2;
System.out.println("myX.x = " + myX.x());
System.out.println("anotherX.x = " + anotherX.x());
. . .

Notice that the code used setX() to set the x value for myX but just assigned a value to
anotherX.x directly. Either way, the code is manipulating two different copies of x: the one
contained in the myX object and the one contained in the anotherX object. The output produced
by this code snippet is:
myX.x = 1
anotherX.x = 2

showing that each instance of the class AnIntegerNamedX has its own copy of the instance
variable x and each x has a different value.

You can, when declaring a member variable, specify that the variable is a class rather than an
instance variable. Similarly, you can specify that a method is a class method rather than an
instance method. The system creates a single copy of a class variable the first time it encounters
the class in which the variable is defined. All instances of that class share the same copy of the
class variable. Class methods can only operate on class variables--they cannot access the instance
variables defined in the class.

To specify that a member variable is a class variable, use the static keyword. For example, let's
change the AnIntegerNamedX class such that its x variable is now a class variable:

class AnIntegerNamedX {
static int x;
public int x() {
return x;
}
public void setX(int newX) {
x = newX;
}
}

Now the exact same code snippet from before that creates two instances of AnIntegerNamedX,
sets their x values, and then displays them produces this, different, output.

myX.x = 2
anotherX.x = 2

89
The output is different because x is now a class variable so there is only one copy of the variable
and it is shared by all instances of AnIntegerNamedX including myX and anotherX. When you
invoke setX() on either instance, you change the value of x for all instances of
AnIntegerNamedX.

You use class variables for items that you need only one copy of and which must be accessible
by all objects inheriting from the class in which the variable is declared. For example, class
variables are often used with final to define constants (this is more memory efficient as constants
can't change so you really only need one copy).

Similarly, when declaring a method, you can specify that method to be a class method rather than
an instance method. Class methods can only operate on class variables and cannot access the
instance variables defined in the class.

To specify that a method is a class method, use the static keyword in the method declaration.
Let's change the AnIntegerNamedX class such that its member variable x is once again an
instance variable, and its two methods are now class methods:
class AnIntegerNamedX {
private int x;
static public int x() {
return x;
}
static public void setX(int newX) {
x = newX;
}
}

When you try to compile this version of AnIntegerNamedX, you will get compiler errors:

AnIntegerNamedX.java:4: Can't make a static reference to nonstatic


variable x in class AnIntegerNamedX.

return x;
^
AnIntegerNamedX.java:7: Can't make a static reference to nonstatic
variable x in class AnIntegerNamedX.
x = newX;
^
2 errors

This is because class methods cannot access instance variables unless the method created an
instance of AnIntegerNamedX first and accessed the variable through it.

Let's fix AnIntegerNamedX by making its x variable a class variable:

class AnIntegerNamedX {
static private int x;
static public int x() {

90
return x;
}
static public void setX(int newX) {
x = newX;
}
}

Now the class will compile and the same code snippet from before that creates two instances of
AnIntegerNamedX, sets their x values, and then prints the x values produces this output:

myX.x = 2
anotherX.x = 2

Again, changing x through myX also changes it for other instances of AnIntegerNamedX.

Another difference between instance members and class members is that class members are
accessible from the class itself. You don't need to instantiate a class to access its class members.
Let's rewrite the code snippet from before to access x() and setX() directly from the
AnIntegerNamedX class:

. . .
AnIntegerNamedX.setX(1);
System.out.println("AnIntegerNamedX.x = " + AnIntegerNamedX.x());
. . .

Notice that you no longer have to create myX and anotherX. You can set x and retrieve x directly
from the AnIntegerNamedX class. You cannot do this with instance members, you can only
invoke instance methods from an object and can only access instance variables from an object.
You can access class variables and methods either from an instance of the class or from the class
itself.

Default Values of Variables

Type Default value


boolean false
byte 0
char '\u0000'
short 0
int 0
long 0l
float 0.0f
double 0.0d
Object null
Array based on Array type

Field variables (class members) are automatically initialized to default values. Local variables
(method or constructor variables) are not automatically initialized. Arrays, whether field or local
variables, are automatically initialized to the default values of their declared type.

91
class CheckInit {

// field variable
static int i;
// field array reference variable
static String[] s = new String[10];

static void myMethod(){

int j; // local variable


int[] a = new int[5]; // local variable array

// causes compile error if not explicitly initialized


j = 10;

System.out.println(" Local variable: " + j);


System.out.println(" Local array ref: " + a[3]);
}

public static void main(String[] args) {


System.out.println("Field variable i: " + i);
System.out.println(" Field array ref: " + s[2]);
myMethod();
}
}

Output of CheckInit:

Field variable i: 0 // default value of int


Field array ref: null // default value for String[]
Local variable: 10 // explicit value
Local array ref: 0 // default value of int[]

5.10 Static Initializer

A static initializer block resembles a method with no name, no arguments, and no return type.  It
doesn't need a name, because there is no need to refer to it from outside the class definition.  The
code in a static initializer block is executed by the virtual machine when the class is loaded.

Like a constructor, a static initializer block cannot contain a return statement.  Therefore, it
doesn't need to specify a return type.

Because it is executed automatically when the class is loaded, parameters don't make any sense,
so a static initializer block doesn't have an argument list.

static {

92
Static initializers are blocks of code within a class that are outside the scope of a method. The
code in a static initializer block is executed only once, when the class is loaded. The code is
executed in the same order as it is declared in the class. The following code illustrates the use of
a static initializer block:

1. public class TestStaticInitializer {


2. static String str = "Default";
3.
4. public TestStaticInitializer() {
5. System.out.println("1::str = " + str);
6. }
7.
8. // Static initializer block
9. static {
10. System.out.println("2::str = " + str);
11. str = "Static";
12. }
13.
14. // Main routine to test the class
15. public static void main(String[] args) {
16. TestStaticInitializer tsi = new TestStaticInitializer();
17. }
18. }

A static string is declared on Line 2 and set to "Default." Next, a static initializer block prints the
string out and resets it to the value "Static" on Lines 8-12. The constructor on Lines 4-6 merely
prints the variable out.

The output of this program is:

2:: str = Default


1:: str = Static

When the class is loaded (because it was constructed) on line 17, lines 9-12 are executed before
the constructor is called. The code in static initializer blocks is always executed when the class is
loaded and before any method in the class is executed.

Only static members can be referenced within static initializer. Static initializer blocks may be
used for executing code that initializes the state of the object or for providing debugging
functionality. However, overuse of this feature can lead to complex and unreadable code.

Multiple static initializer blocks

You may include any number of static initializer blocks in your class definition.  The static
initializer blocks will be executed in the order in which they appear in the code.

5.11 Variable Shadowing

93
A field declaration can be shadowed by a local variable declaration

class TestShadowing {
static int x = 1; // field variable

public static void main(String[] args) {


int x = 0; // local variable
System.out.println("x = " + x);
System.out.println("TestShadowing.x = " + TestShadowing.x)
}
}

Output:

x=0
TestShadowing.x = 1

because the identifier x is used within a code block main() a search is made for a declaration of x
within the body of main(). As one is found, int x = 0, the simple identifier name x is assumed to
be within scope as a local variable.

To access the field variable x, you must use its fully-qualified name TestShadowing.x

5.12 Pass by value and Pass by reference

Primitive data type operations deal only with value. For example, the following code shows that
assigning primitive data variable i to another named j simply passes a copy of the value in i into
j. That is, a data value passes and not a reference or pointer to a data location.

  int i = 1;
  int j = i; // Now j holds "1"
             // that is, i's value passes to j
  i = 2;       // j still holds "1"

Similarly, in method arguments, primitive variables pass by value. That is, a copy is made and
passed to the method. Changes to the passed value do not affect the variable in the calling code.

The following shows code on top that creates an instance of AClass and invokes the aMethod
with an int argument. The code on the bottom shows the AClass definition and the aMethod.

94
  ...   

  int i = 2;
  AClass a1 = new AClass ();

  a1.aMethod (i);

  int m = i; // m = i = 2 not 5
  ...

 class AClass
 {
  int j = 1;
  void aMethod (int k)
  {
    int i = 10 * k; 
    k = 5;
    j = k * 10;
  }
 }

The value in variable i in the code on the left will be passed to variable k in the aMethod
argument list. When that method assigns a value of 5 to k, it has no affect whatsoever on variable
i the code on the left.

Modify Reference Variables

You can always assign a new object to a reference variable. For example, in the following code,
we create two instances of the AClass, "a" and "b", and then assign new values to the "j"
variable for each object:

  ...
  AClass a,b;
  a = new AClass ();
  b = new AClass ();
  
  a.j = 4;
  b.j = 40;
  
  a = b;       // a now references same
               // object as does the b variable.
  a.j = 400;
  
  int x = b.j; // x = 400 since a and b now
               // reference same object.
 ...
public class AClass
 {
  public int j = 1;
  void aMethod (int k)

95
  {
    int i = 10*k; 
    k = 5;
    j = k * 10;
  }
 }

Then we assign the "b" object to the "a" reference with the a=b; statement. So both the "a" and
"b" variables now reference the same object.

Note that assigning a new object to the "a" variable orphans the original object that "a" pointed
to previously. If an object is no longer referenced by any other variables, then the garbage
collector will eventually reclaim the memory that it occupies.

References in Method Arguments

The argument list of a method can include object references. The methods and data of that object
can be accessed and modified by the method.

However, the reference itself passes by value. That is, the JVM makes a copy of the internal
memory pointer and the copy of the pointer goes into the argument value.

So if the reference variable in the method is set to a new object, that will have no affect on the
reference variable in the calling method.

For example, in the following code, a reference to a BClass object passes to the method of a
AClass object. In that method, the argument variable is assigned to a new instance of the
BClass. However, when the process returns to the calling code, the original reference remains
unaffected.

...   

  int i = 2;
  AClass a;
  BClass b;
 
  a = new AClass ();
  b = new BClass ();

  b.j = 5;   

  a.aMethod (b);

  j = b.j;// j = 20 not 5 or 100


  ...

class AClass {
   void aMethod (BClass bb) {

96
    bb.j = 20;
    bb= new BClass ();
    bb.j = 100;
   }
 }

class BClass {
  int j = 0;
 }

Since reference variables only hold pointers, the test

       if (a == b)...

simply tests whether a and b point to the same object, not if the referenced objects have equal
data values.

If you need to test whether two objects hold the same data values, many classes provide an
"equals()" method such that

       a.equals(b)

returns true if the object b data matches that in object a.

Let's look at a method called getRGBColor within a class called Pen. This method is attempting
to return three values by setting the values of its arguments:

public class Pen {


private int redValue, greenValue, blueValue;
...
//This method does not work as intended.
public void getRGBColor(int red, int green, int blue) {
red = redValue;
green = greenValue;
blue = blueValue;
}
}

This simply does not work. The red, green, and blue variables exist only within the scope of
the getRGBColor method. When that method returns, those variables are gone and any changes
to them lost.

Let's rewrite the getRGBColor method so that it does what was intended. First, we need a new
type of object, RGBColor, that can hold the red, green, and blue values of a color in RGB space:

public class RGBColor {


public int red, green, blue;
}

97
Now we can rewrite getRGBColor so that it accepts an RGBColor object as an argument. The
getRGBColor method returns the current color of the pen by setting the red, green, and blue
member variables of its RGBColor argument:

public class Pen {


private int redValue, greenValue, blueValue;
...
public void getRGBColor(RGBColor aColor) {
aColor.red = redValue;

98
aColor.green = greenValue;
aColor.blue = blueValue;
}
}

The changes made to the RGBColor object within the getRGBColor method persist after the
method returns, because aColor is a reference to an object that exists outside the scope of the
method.

5.13 Access Control

Access or visibility rules determine whether a method or a data variable can be accessed by
another method in another class or subclass.

Java provides for 4 access modifiers :

1. public - access by any other class anywhere.

2. protected - accessible by the package classes and any subclasses that are in other
packages .
3. Default - (also known as "package private") accessible to classes in the same package but
not by classes in other packages, even if these are subclasses.
4. private - accessible only within the class. Even methods in subclasses in the same
package do not have access.

These access rules allow one to control the degree of encapsulation of your classes. For example,
you may distribute your class files to other users who can make subclasses of them. By making
some of your data and methods private, you can prevent the subclass code from interfering
with the internal workings of your classes.

Also, if you distribute new versions of your classes at a later point, you can change or eliminate
these private attributes and methods without worrying that these changes will affect the
subclasses.

Access levels affect you in two ways. First, when you use classes that come from another source,
such as the classes in the Java platform, access levels determine which members of those classes
your classes can use. Second, when you write a class, you need to decide what access level every
member variable and every method in your class should have. One way of thinking about access
levels is in terms of the API: access levels directly affect the public API of a class and determine
which members of the class can be used by other classes. You need to put as much effort into
deciding the access level for a member as you put into making other decisions about your class's
API, such as naming methods.

Modifier Used with Description


public Classes A Class or Interface may be accessed from outside its package.
Interfaces Constructors, Inner Classes, Methods and Field variables may be
Constructors accessed from wherever their class is accessed.

99
Inner Classes
Methods
Field variables
protected Constructors May be accessed by other classes in the same package or from any
Inner Classes subclasses of the class in which they are declared.
Methods
Field variables
private Constructors May be accessed only from within the class in which they are
Inner Classes declared.
Methods
Field variables
no modifier Classes May only be accessed from within the package in which they are
Interfaces declared.
Constructors
Inner Classes
Methods
Field variables

Private

Private variables are only visible from within the same class as they are created in. This means
they are NOT visible within sub classes. This allows a variable to be insulated from being
modified by any methods except those in the current class.

class Base{
private int iEnc=10;
public void setEnc(int iEncVal){
if(iEncVal < 1000){
iEnc=iEncVal;
}
else {
System.out.println("Enc value must be less than 1000");
}//End if
}
public static void main(String args[]) {
Base b=new Base();
b.iEnc = 20;
}
}

class Enc{
public static void main(String argv[]){
Base b = new Base();
b.iEnc = 20; //compile-time error
b.setEnc(20);
}//End of main
}

If the constructors are declared private then the object of that class can be created only in that
class. It cannot be created outside the class definition.

100
Public

The public modifier can be applied to a variable (field) or a class. It is the first modifier you are
likely to come across in learning Java.

A public class has global scope, and an instance can be created from anywhere within or outside
of a program. Only one non inner class in any file can be defined with the public keyword. If you
define more than one non inner class in a file with the keyword public the compiler will generate
an error.

Using the public modifier with a variable makes it available from anywhere. It is used as follows,

public int myint =10;

If you want to create a variable that can be modified from anywhere you can declare it as public.
You can then access it using the dot notation similar to that used when calling a method.

class Base {
public int iNoEnc=77;
}

class NoEnc{
public static void main(String argv[]){
Base b = new Base();
b.iNoEnc=2;
System.out.println(b.iNoEnc);
}//End of main
}

One .java file can contain multiple classes but only one public class. The public classes should be
stored in separate class files. The name of the class file should be same as that of the public class.

Protected

A protected variable is visible within a class, and in sub classes, the same package but not
elsewhere. The qualification that it is visible from the same package can give more visibility than
you might suspect. Any class in the same directory is considered to be in the default package,
and thus protected classes will be visible. This means that a protected variable is more visible
than a variable defined with no access modifier.

A variable defined with no access modifier is said to have default visibility. Default visibility
means a variable can be seen within the class, and from elsewhere within the same package, but
not from sub-classes that is not in the same package.

Access Modifiers and encapsulation

The visibility modifiers are part of the encapsulation mechanism for Java. Encapsulation allows
separation of the interface from the implementation of methods.

101
The visibility modifiers are a key part of the encapsulation mechanism for java. Encapsulation
allows separation of the interface from the implementation of methods. The benefit of this is that
the details of the code inside a class can be changed without it affecting other objects that use it.
This is a key concept of the Object Oriented paradigm.

Encapsulation generally takes form of methods to retrieve and update the values of private class
variables. These methods are known as a accessor and mutator methods. The accessor (or get)
method retrieves the value and the mutator changes (or sets) the value. The naming convention
for these methods are setFoo to change a variable and getFoo to obtain the contents of a variable.
An aside note: the use of get and set in the naming of these methods is more significant than just
programmer convenience and is an important part of the Javabeans system.

Take the example where you had a variable used to store the age of a student.

You might store it simply with a public integer variable

int iAge;

later when your application is delivered you find that some of your students have a recorded age
of more than 200 years and some have an age of less than zero. You are asked to put in code to
check for these error conditions. So wherever your programs change the age value, you write if
statements that check for the range.

if(iAge > 70){


//do something
}
if (iAge <3){ //do something
}

In the process of doing this you miss some code that used the iAge variable and you get called
back because you have a 19 year old student who is on your records has being 190 years old.

The Object Oriented approach to this problem using encapsulation, is to create methods that
access a private field containing the age value, with names like setAge and getAge. The setAge
method might take an integer parameter and update the private value for Age and the getAge
method would take no parameter but return the value from the private age field.

public void setAge(int iStudentAge){


iAge = iStudentAge;
}

public int getAge(){


return iAge;
}

At first this seems a little pointless as the code seems to be a long way around something that
could be done with simple variable manipulation. However when they come back to you with the

102
requirement to do more and more validation on the iAge field you can do it all in these methods
without affecting existing code that uses this information.

By this approach the implementation of code, (the actual lines of program code), can be changed
whilst the way it looks to the outside world (the interface) remains the same.

5.14 Constructors

Classes have a special method called a constructor that is called implicitly when a class instance
is created. The class constructor always has the same name as the class and no return type.

Note: If you do not write your own constructor, the compiler adds an empty constructor, which
calls the no-arguments constructor of its parent class. The empty constructor is called the default
constructor. The default constructor initializes all non-initialized fields and variables to zero.

If you create constructors of your own, Java does not supply the default zero parameter
constructor

class LessonTwoD {
String text;

//Constructor
LessonTwoD(){
text = "I'm a Simple Program";
}

//Accessor method
String getText(){
return text;
}

public static void main(String[] args){


LessonTwoD progInst = new LessonTwoD();
String retrievedText = progInst.getText();
System.out.println(retrievedText);
}
}

As soon as you create any constructors of your own you loose the default no parameter
constructor. If you then try to create an instance of the class without passing any parameters (i.e.
invoking the class with a zero parameter constructor), you will get an error. Thus as soon as you
create any constructors for a class you need to create a zero parameter constructor.

The following example illustrates code that will not compile. When the compiler checks to create
the instance of the Base class called c it inserts a call to the zero parameter constructor. Because
Base has an integer constructor the zero parameter constructor is not available and a compile
time error occurs. This can be fixed by creating a "do nothing" zero parameter constructor in the
class Base.

103
//Warning: will not compile.
class Base{
Base(int i){
System.out.println("single int constructor");
}
}

public class Cons {


public static void main(String argv[]){
Base c = new Base();
}
}

//This will compile


class Base{
Base(int i){
System.out.println("single int constructor");
}
Base(){}
}
public class Cons {
public static void main(String argv[]){
Base c = new Base();
}
}

Constructors cannot be native, abstract, static, synchronized or final.

5.15 The this keyword

Within an instance method or a constructor, this is a reference to the current object — the
object whose method or constructor is being called. You can refer to any member of the current
object from within an instance method or a constructor by using this. The most common reason
for doing so is that a member variable is hidden by an argument to the method or the constructor.

For example, the following constructor for the HSBColor class initializes the object's member
variables according to the arguments passed into the constructor. Each argument to the
constructor hides one of the object's member variables, so this constructor must refer to the
object's member variables through this:

public class HSBColor {


private int hue, saturation, brightness;
public HSBColor (int hue, int saturation,
int brightness) {
this.hue = hue;
this.saturation = saturation;
this.brightness = brightness;
}
}

104
this keyword cannot be used in a static reference.

5.16 Overloading

The Java programming language supports name overloading for methods, which means that
multiple methods in the same class can share the same name if they have different parameter
lists. Suppose that you have a class that can draw various types of data (strings, integers, and so
on) and that contains a method for drawing each data type. In other languages, you have to think
of a new name for each method, for example, drawString, drawInteger, drawFloat, and so on. In
the Java programming language, you can use the same name for all the drawing methods but
pass a different type of argument to each method. Thus, the data drawing class might declare
three methods named draw, each of which takes a different type of argument.

public class DataArtist {


...
public void draw(String s) {
...
}
public void draw(int i) {
...
}
public void draw(float f) {
...
}
}

Overloaded methods are differentiated by the number and the type of the arguments passed into
the method. In the code sample, draw(String s) and draw(int i) are distinct and unique
methods because they require different argument types. You cannot declare more than one
method with the same name and the same number and type of arguments, because the compiler
cannot tell them apart. The compiler does not consider return type when differentiating methods,
so you cannot declare two methods with the same signature even if they have a different return
type.

Overloading is a one of the ways in which Java implements one of the key concepts of Object
orientation, polymorphism. Polymorphism is a word constructed from Poly meaning "many" and
"morphism" implying meaning. Thus a overloading allows the same method name to have
multiple meanings or uses. The method call is resolved during the compile-time hence it uses
static or early binding.

Thus imagine you were designing the interface for a system to run mock Java certification
exams. An answer may come in as an integer, a boolean or a text string. You could create a
version of the method for each parameter type and give it a matching name thus.

markanswerboolean(boolean answer){

105
markanswerint(int answer){

markanswerString(String answer){

This would work but it means that future users of your classes have to be aware of more method
names than is strictly necessary. It would be more useful if you could use a single method name
and the compiler would resolve what actual code to call according to the type and number of
parameters in the call.

The following is not an example of overloading and will cause a compile time error indicating a
duplicate method declaration.

void markanswer(String answer){

void markanswer(String title){

The return type does not form part of the signature for the purpose of overloading. 

Thus changing one of the above to have an int return value will still result in a compile time
error, but this time indicating that a method cannot be redefined with a different return type. 

Overloaded methods do not have any restrictions on what exceptions can be thrown. That is
something to worry about with overriding.

Overloaded methods are differentiated only on the number, type and order of parameters, not on
the return type of the method

Overloading Constructors

You can define multiple constructors to provide optional ways to create and initialize instances
of the class.

class Test
{
  int i;
  boolean b=true;
 
  Test(int j, boolean a) This constructor
  { initializes the two
    i = j; properties to the
    b = a; values passed as

106
  } arguements.

  Test(int j) A second constructor


  { passes an initial
    i = j; value to just one of
  } the variables.

  int get()
  {
    return i;
  }
}

Note that if a class includes one or more explicit constructors, the java compiler does not create
the default constructor. So for the class shown above, the code

   Test ex = new Test();

will generate a compiler error stating that no such constructor exists.

Use of this()

From within a constructor, you can also use the this keyword to call another constructor in the
same class. Doing so is called an explicit constructor invocation.

public class Rectangle {


private int x, y;
private int width, height;
public Rectangle() {
this(0, 0, 0, 0);
}
public Rectangle(int width, int height) {
this(0, 0, width, height);
}
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
...
}

This class contains a set of constructors. Each constructor initializes some or all of the rectangle's
member variables. The constructors provide a default value for any member variable whose
initial value is not provided by an argument. For example, the no-argument constructor calls the
four-argument constructor, using 0s as default values. As before, the compiler determines which
constructor to call, based on the number and the type of arguments.

107
If present, an explicit constructor invocation must be the first line in the constructor.

5.17 Recursion

Recursion is a process of defining something in terms of itself. Recursion is an attribute that


allows a method to call itself. A method that calls itself is said to be recursive.

//A simple example of recursion


class Factorial {

//this is a recursive function


int fact(int n) {
int result;
if(n == 1) return 1;
result = fact(n-1) * n;
return result;
}
}

class Recursion {
public static void main(String args[]) {
Factorial f = new Factorial();
System.out.println(“Factorial of 3 is “+f.fact(3));
}
}

5.18 Native Methods

The native modifier is used only for methods and indicates that the body of the code is written in
a language other than Java such as C or C++. Native methods are often written for platform
specific purposes such as accessing some item of hardware that the Java Virtual Machine is not
aware of. Another reason is where greater performance is required.

A native method ends with a semicolon rather than a code block. Thus the following would call
an external routine, written perhaps in C++.

public native void fastcalc();

The implementation of native is out of the scope of this course.

5.19 Arrays of Objects

Arrays can hold reference types as well as primitive types. You create such an array in much the
same way you create an array with primitive types. Here's a small program,
ArrayOfStringsDemo that creates an array containing three string objects then prints the strings
in all lower case letters.
public class ArrayOfStringsDemo {

108
public static void main(String[] args) {
String[] anArray = { "String One", "String Two",
"String Three" };
for (int i = 0; i < anArray.length; i++) {
System.out.println(anArray[i].toLowerCase());
}
}
}

This program creates and populates the array in a single statement. However, you can create an
array without putting any elements in it. This brings us to a potential stumbling block, often
encountered by new programmers, when using arrays that contain objects. Consider this line of
code:
String[] anArray = new String[5];

After this line of code is executed, the array called anArray exists and has enough room to hold
5 string objects. However, the array doesn't contain any strings yet. It is empty. The program
must explicitly create strings and put them in the array. This might seem obvious, however,
many beginners assume that the previous line of code creates the array and creates 5 empty
strings in it. Thus they end up writing code like the following, which generates a
NullPointerException:

String[] anArray = new String[5];


for (int i = 0; i < anArray.length; i++) {
// ERROR: the following line gives a runtime error
System.out.println(anArray[i].toLowerCase());
}

Arrays of Arrays

ArrayOfArraysDemo creates an array and uses an initializer to populate it with four sub-arrays.
public class ArrayOfArraysDemo {
public static void main(String[] args) {
String[][] cartoons =
{
{ "Flintstones", "Fred", "Wilma", "Pebbles", "Dino" },
{ "Rubbles", "Barney", "Betty", "Bam Bam" },
{ "Jetsons", "George", "Jane", "Elroy", "Judy", "Rosie",
“Astro" },
{ "Scooby Doo Gang", "Scooby Doo", "Shaggy", "Velma",
"Fred", "Daphne" }
};

for (int i = 0; i < cartoons.length; i++) {


System.out.print(cartoons[i][0] + ": ");
for (int j = 1; j < cartoons[i].length; j++) {
System.out.print(cartoons[i][j] + " ");
}

109
System.out.println();
}
}
}

Notice that the sub-arrays are all of different lengths. The names of the sub-arrays are
cartoons[0], cartoons[1], and so on.

5.20 Nested and Inner Classes

You can define a class as a member of another class. Such a class is called a nested class and is
illustrated here:
class EnclosingClass {
...
class ANestedClass {
...
}
}

You use nested classes to reflect and to enforce the relationship between two classes. You should
define a class within another class when the nested class makes sense only in the context of its
enclosing class or when it relies on the enclosing class for its function. For example, a text cursor
might make sense only in the context of a text component.

As a member of its enclosing class, a nested class has a special privilege: It has unlimited access
to its enclosing class's members, even if they are declared private. However, this special
privilege isn't really special at all. It is fully consistent with the meaning of private and the other
access specifiers. The access specifiers restrict access to members for classes outside the
enclosing class. The nested class is inside its enclosing class so that it has access to its enclosing
class's members.

Like other members, a nested class can be declared static (or not). A static nested class is called
just that: a static nested class. A nonstatic nested class is called an inner class.

class EnclosingClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}

For example, suppose a class named WireFrameModel represents a set of lines in three-
dimensional space. (Such models are used to represent three-dimensional objects in graphics
programs.) Suppose that the WireFrameModel class contains a static nested class, Line, that

110
represents a single line. Then, outside of the class WireFrameModel, the Line class would be
referred to as WireFrameModel.Line. Of course, this just follows the normal naming convention
for static members of a class. The definition of the WireFrameModel class with its nested Line
class would look, in outline, like this:

public class WireFrameModel {

. . . // other members of the WireFrameModel class

static public class Line {


// Represents a line from the point (x1,y1,z1)
// to the point (x2,y2,z2) in 3-dimensional space.
double x1, y1, z1;
double x2, y2, z2;
} // end class Line

. . . // other members of the WireFrameModel class

} // end WireFrameModel

Inside the WireframeModel class, a Line object would be created with the constructor "new
Line()". Outside the class, "new WireFrameModel.Line()" would be used.

A static nested class has full access to the members of the containing class, even to the private
members. This can be another motivation for declaring a nested class, since it lets you give one
class access to the private members of another class without making those members generally
available to other classes.

When you compile the above class definition, two class files will be created. Even though the
definition of Line is nested inside WireFrameModel, the compiled Line class is stored in a
separate file. The name of the class file for Line will be WireFrameModel$Line.class.

As with static methods and variables, which we call class methods and variables, a static nested
class is associated with its enclosing class. And like class methods, a static nested class cannot
refer directly to instance variables or methods defined in its enclosing class — it can use them
only through an object reference.

As with instance methods and variables, an inner class is associated with an instance of its
enclosing class and has direct access to that object's instance variables and methods. Also,
because an inner class is associated with an instance, it cannot define any static members itself.

To help further differentiate the terms nested class and inner class, it's useful to think about them
in the following way. The term nested class reflects the syntactic relationship between two
classes; that is, syntactically, the code for one class appears within the code of another. In
contrast, the term inner class reflects the relationship between objects that are instances of the
two classes. Consider the following classes:

class EnclosingClass {

111
...
class InnerClass {
...
}
}

The interesting feature about the relationship between these two classes is not that InnerClass is
syntactically defined within EnclosingClass. Rather, it's that an instance of InnerClass can
exist only within an instance of EnclosingClass and that it has direct access to the instance
variables and methods of its enclosing instance. The next figure illustrates this idea.

Any non-static member of a class is not really part of the class itself (although its source code is
contained in the class definition). This is true for non-static nested classes, just as it is for any
other non-static part of a class. The non-static members of a class specify what will be contained
in objects that are created from that class. The same is true -- at least logically -- for non-static
nested classes. It's as if each object that belongs to the containing class has its own copy of the
nested class. This copy has access to all the instance methods and instance variables of the
object. Two copies of the nested class in different objects differ because the instance variables
and methods they refer to are in different objects. In fact, the rule for deciding whether a nested
class should be static or non-static is simple: If the class needs to use any instance variable or
instance method, make it non-static. Otherwise, it might as well be static.

From outside the containing class, a non-static nested class has to be referred to as
variableName.NestedClassName, where variableName is a variable that refers to the object that
contains the class. This is actually rather rare, however. A non-static nested class is generally
used only inside the class in which it is nested, and there it can be referred to by its simple name.

In order to create an object that belongs to a non-static nested class, you must first have an object
that belongs to the containing class. (When working inside the class, the object " this" is used
implicitly.) The nested class object is permanently associated with the containing class object,
and it has complete access to the members of the containing class object. Looking at an example
will help, and will hopefully convince you that non-static nested classes are really very natural.
Consider a class that represents poker games. This class might include a nested class to represent
the players of the game. This structure of the PokerGame class could be:

class PokerGame { // Represents a game of poker.

class Player {
// Represents one of the players in this game.
.

112
.
.
} // end class Player

private Deck deck;


// A deck of cards for playing the game.
private int pot;
// The amount of money that has been bet.

.
.
.

} // end class PokerGame

If game is a variable of type PokerGame, then, conceptually, game contains its own copy of the
Player class. In an an instance method of a PokerGame object, a new Player object would be
created by saying "new Player()", just as for any other class. (A Player object could be created
outside the PokerGame class with an expression such as " new game.Player()". Again, however,
this is rather rare.) The Player object will have access to the deck and pot instance variables in
the PokerGame object. Each PokerGame object has its own deck and pot and Players. Players
of that poker game use the deck and pot for that game; playes of another poker game use the
other game's deck and pot. That's the effect of making the Player class non-static. This is the
most natural way for players to behave. A Player object represents a player of one particular
poker game. If Player were a static nested class, on the other hand, it would represent the
general idea of a poker player, independent of a particular poker game.

You may encounter nested classes of both kinds in the Java platform API and be required to use
them.

To define a non-static nested class either in a class or method scope:

Place the class definition (for the nested class) inside another class definition (the outer class) or
a method.

Write code in a non-static method of the outer class to construct an instance of the nested
class.

Inner x = new Inner();

constructs an instance of Inner where Inner is a nested class defined in the current class.

Write code to construct an instance on a nested class where either no this object exists, or
the current this object is not an instance of the outer class.

You must create an instance of the outer class first. Given a class, Outer, containing a nested
class Inner:

113
Outer.Inner y = new Outer().new Inner();

The above creates an instance of Inner called y, but it had to construct an instance of Outer first.
The following example creates the Outer instance on a separate line, the syntax in the second line
is the one you use when you already have an instance of the outer class.

Outer x = new Outer();


Outer.Inner y = x.new Inner();

If Inner is static, you can use:


Outer.Inner I= new Outer.Inner();

5.21 Command-Line Arguments

A Java application can accept any number of arguments from the command line. Command-line
arguments allow the user to affect the operation of an application for one invocation. For
example, an application might allow the user to specify verbose mode--that is, specify that the
application display a lot of trace information. This is done using the command-line argument
-verbose.

Purity Tip:  Programs that use command-line arguments are not 100% Pure Java because some
systems, like the Mac OS, don't normally have a command line or command-line arguments.
Consider using properties instead so that your programs fit more naturally into the environment.

Arrays have lengths and you can access that length by referencing the variable
arrayname.length You test the length of the args array as follows.

// This is the Hello program in Java

class Hello {
public static void main (String args[]) {
if (args.length > 0) {
System.out.println("Hello " + args[0]);
}
}
}

System.out.println(args[0]) was wrapped in a conditional test, if (args.length > 0) {


}. The code inside the braces, System.out.println(args[0]), now gets executed if and only if
the length of the args array is greater than zero.

You can derive the number of command-line arguments with the array's length attribute:

numberOfArgs = args.length;

In Java, you always know the name of the application because it's the name of the class in which
the main method is defined. So the Java runtime system does not pass the class name you invoke

114
to the main method. Rather, it passes only the items on the command line that appear after the
class name. For example, consider the following statement, which is used to invoke a Java
application:

java diff file1 file2

The following simple application displays each of its command-line arguments on a line by
itself:
public class Echo {
public static void main (String[] args) {
for (int i = 0; i < args.length; i++)
System.out.println(args[i]);
}
}

Here's an example of how to invoke the application. You enter the words that are shown here in a
different font:
java Echo Drink Hot Java

Drink
Hot
Java

Note that the application displays each word--Drink, Hot, and Java--on a line by itself. This is
because the space character separates command-line arguments. If you want Drink, Hot, and
Java to be interpreted as a single argument, you would join them by enclosing them within
double quotation marks.

java Echo "Drink Hot Java"

Drink Hot Java

Parsing Numeric Command-Line Arguments

If your program needs to support a numeric command-line argument, it must convert a String
argument that represents a number, such as "34", to a number. Here's a code snippet that converts
a command-line argument to an int:
int firstArg;
if (args.length > 0)
firstArg = Integer.parseInt(args[0]);

parseInt throws a NumberFormatException if the format of args[0] isn't valid. All of the
Number classes--Integer, Float, Double, and so on--have parseXXX methods that convert a
String representing a number to an object of their type.

115
5.22 Enumerated types

Enumerated types is a new feature introduced in J2SE 5.0. An enumerated type is a type whose
legal values consist of a fixed set of constants. Common examples include compass directions,
which take the values North, South, East and West and days of the week, which take the values
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, and Saturday.

In the Java programming language, you define an enumerated type by using the enum keyword.
For example, you would specify a days of the week enumerated type as:

enum Days { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,


FRIDAY, SATURDAY };

Notice that by convention the names of an enumerated type's values are spelled in uppercase
letters.

You should use enumerated types any time you need to represent a fixed set of constants. That
includes natural enumerated types such as the planets in our solar system, the days of the week,
and the suits in a deck of cards as well as sets where you know all possible values at compile
time, for example the choices on a menu, rounding modes, command line flags, and so on.

Java programming language enumerated types are much more powerful than their counterparts in
other languages, which are just glorified integers. The enum declaration defines a class (called an
enum type). These are the most important properties of enum types:

 Printed values are informative.


 They are typesafe.
 They exist in their own namespace.
 The set of constants is not required to stay fixed for all time.
 You can switch on an enumeration constant.
 They have a static values method that returns an array containing all of the values of the
enum type in the order they are declared. This method is commonly used in combination
with the for-each construct to iterate over the values of an enumerated type.
 You can provide methods and fields, implement interfaces, and more.
 They provide implementations of all the Object methods. They are Comparable and
Serializable, and the serial form is designed to withstand changes in the enum type.

In the following example, Planet is an enumerated type that represents the planets in the solar
system. A Planet has constant mass and radius properties. Each enum constant is declared with
values for the mass and radius parameters that are passed to the constructor when it is created.
Note that the constructor for an enum type is implicitly private. If you attempt to create a public
constructor for an enum type, the compiler displays an error message.

public enum Planet {


MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),

116
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7),
PLUTO (1.27e+22, 1.137e6);

private final double mass; //in kilograms


private final double radius; //in meters
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
public double mass() { return mass; }
public double radius() { return radius; }

//universal gravitational constant (m3 kg-1 s-2)


public static final double G = 6.67300E-11;

public double surfaceGravity() {


return G * mass / (radius * radius);
}
public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
}

In addition to its properties, Planet has methods that allow you to retrieve the surface gravity
and weight of an object on each planet. Here is a sample program that takes your weight on earth
(in any unit) and calculates and prints your weight on all of the planets (in the same unit):

public static void main(String[] args) {


double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight/EARTH.surfaceGravity();
for (Planet p : Planet.values()) {
System.out.printf("Your weight on %s is %f%n",
p, p.surfaceWeight(mass));
}
}

Here's the output:

java Planet 175


Your weight on MERCURY is 66.107583
Your weight on VENUS is 158.374842
Your weight on EARTH is 175.000000
Your weight on MARS is 66.279007
Your weight on JUPITER is 442.847567
Your weight on SATURN is 186.552719
Your weight on URANUS is 158.397260
Your weight on NEPTUNE is 199.207413

117
Your weight on PLUTO is 11.703031

There's one limitation of enum types: although enum types are classes, you cannot define a
hierarchy of enums. In other words, it's not possible for one enum type to extend another enum
type.

Enumerated types in switch statement

An example of using enumerated type in switch statement.

public class SwitchEnumDemo {


public enum Month { JANUARY, FEBRUARY, MARCH, APRIL,
MAY, JUNE, JULY, AUGUST, SEPTEMBER,
OCTOBER, NOVEMBER, DECEMBER }

public static void main(String[] args) {


Month month = Month.FEBRUARY;
int year = 2000;
int numDays = 0;

switch (month) {
case JANUARY:
case MARCH:
case MAY:
case JULY:
case AUGUST:
case OCTOBER:
case DECEMBER:
numDays = 31;
break;
case APRIL:
case JUNE:
case SEPTEMBER:
case NOVEMBER:
numDays = 30;
break;
case FEBRUARY:
if ( ((year % 4 == 0) && !(year % 100 == 0))
|| (year % 400 == 0) )
numDays = 29;
else
numDays = 28;
break;
default:
numDays=0;
break;
}
System.out.println("Number of Days = " + numDays);
}

118
5.23 Garbage Collection

Some object-oriented languages require that you keep track of all the objects you create and that
you explicitly destroy them when they are no longer needed. Managing memory explicitly is
tedious and error prone. The Java platform allows you to create as many objects as you want
(limited, of course, by what your system can handle), and you don't have to worry about
destroying them. The Java runtime environment deletes objects when it determines that they are
no longer being used. This process is called garbage collection.

An object is eligible for garbage collection when there are no more references to that object.
References that are held in a variable are usually dropped when the variable goes out of scope.
Or, you can explicitly drop an object reference by setting the variable to the special value null.
Remember that a program can have multiple references to the same object; all references to an
object must be dropped before the object is eligible for garbage collection.

The Garbage Collector

The Java runtime environment has a garbage collector that periodically frees the memory used
by objects that are no longer referenced. The garbage collector does its job automatically,
although, in some situations, you may want to run the garbage collection explicitly by calling the
gc method in the System class. For instance, you might want to run the garbage collector after a
section of code that creates a large amount of garbage or before a section of code that needs a lot
of memory.

Finalization

Before an object gets garbage-collected, the garbage collector gives the object an opportunity to
clean up after itself through a call to the object's finalize method. This process is known as
finalization.

Most programmers don't have to worry about implementing the finalize method. In rare cases,
however, a programmer might have to implement a finalize method to release resources, such as
native peers, that aren't under the control of the garbage collector.

The finalize method is a member of the Object class, which is the top of the Java platform's
class hierarchy and a superclass of all classes. A class can override the finalize method to
perform any finalization necessary for objects of that type. If you override finalize, your
implementation of the method should call super.finalize as the last thing it does.

Summary

A class definition has two parts: a class declaration and a class body. The class body contains
member variables, methods, and constructors for the class. A class uses member variables to
contain state and uses methods to implement behavior.

119
A class method or class variable is associated with a particular class. The runtime system
allocates a class variable once per class, no matter how many instances exist of that class. You
access class variables and methods through the class.

An instance method or instance variable is associated with a particular object (an instance of a
class). Every time you create an object, the new object gets a copy of every instance variable
defined in its class. You access instance variables and methods through objects.

You can specify a class member variable or a class method by using the static keyword in the
member's declaration. A member that is not declared as static is implicitly an instance
member. Class variables are shared by all instance of a class and can be accessed through the
class name. Instances of a class get their own copy of each instance variable, which must be
accessed through an instance reference.

You create an object from a class by using the new operator and a constructor. The new operator
returns a reference to the object that was created. You can assign the reference to a variable or
use it directly.

A class controls access to its instance variables and methods by using the Java platform’s access
mechanism. Instance variables and methods that are accessible to code outside of the class that
they are declared in can be referred to by using a qualified name. The qualified name of an
instance variable looks like this:

objectReference.variableName

The qualified name of a method looks like this:


objectReference.methodName(argumentList)

or

objectReference.methodName()

Constructors initialize a new instance of a class and have the same name as the class.

You can control access to member variables and methods in the same way: by using an access
specifier, such as private or public, in the member's declaration.

A class defined within another class is called a nested class. Like other members of a class, a
nested class can be declared static or not. A nonstatic nested class is called an inner class. An
instance of an inner class can exist only within an instance of its enclosing class and has access
to its enclosing class's members even if they are declared private.

The garbage collector automatically cleans up unused objects. An object is unused if the program
holds no more references to it. You can explicitly drop a reference by setting the variable holding
the reference to null.

120
Questions
1. class GRC7 {public void main(String[] args) {}} // 1
class GRC8 {public void main(String []args) {}} // 2
class GRC9 {public void main(String args[]) {}} // 3

What is the result of attempting to compile and run the above programs?

a.  Compile-time error at line 1.


b.  Compile-time error at line 2.
c.  Compile-time error at line 3.
d.  An attempt to run GRC7 from the command line fails.
e.  An attempt to run GRC8 from the command line fails.
f.  An attempt to run GRC9 from the command line fails.

2. class GRC1 {public static void main(String[] args) {}} // 1


class GRC2 {protected static void main(String[] args) {}} // 2
class GRC3 {private static void main(String[] args) {}} // 3

What is the result of attempting to compile each of the three class declarations and invoke each main method from
the command line?

a.  Compile-time error at line 1.


b.  Compile-time error at line 2.
c.  Compile-time error at line 3.
d.  An attempt to run GRC1 from the command line fails.
e.  An attempt to run GRC2 from the command line fails.
f.  An attempt to run GRC3 from the command line fails.

3. class GFM12 {
static int x; // 1
public static void main(String[] args) { // 2
int y; // 3
System.out.println("x="+x); // 4
System.out.println("y="+y); // 5
}
}
What is the result of attempting to compile and run the program?

a.  Compile-time error at line 1. e.  Compile-time error at line 5.


b.  Compile-time error at line 2. f.  Run-time error
c.  Compile-time error at line 3. g.  None of the above
d.  Compile-time error at line 4.

121
4. class GFM13 {
static byte a; static short b; static char c;
static int d; static long e; static String s;
public static void main(String[] args) {
System.out.println(a+b+c+d+e+s);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 00000null d.  Prints: 0 g.  Run-time error


b.  Prints: 00000 e.  Prints: null h.  None of the above
c.  Prints: 0null f.  Compile-time error

5. class GFM16 {
static int m1 (int i1, int i2) {
int i3;
if (i1 > 0) {i3 = i1 + i2;}
return i3;
}

public static void main(String[] args) {


System.out.println(m1(1,2));
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 0
b.  Prints: 1
c.  Compile-time error
d.  Run-time error
e.  None of the above

122
6. class GRC10 {
public static void main (String[] s) {
System.out.print(s[1] + s[2] + s[3]);
}
}

java GRC10 A B C D E F

What is the result of attempting to compile and run the program using the specified command line?

a.  Prints: ABC d.  Prints: A B C g.  Compile-time error


b.  Prints: BCD e.  Prints: B C D h.  Run-time error
c.  Prints: CDE f.  Prints: C D E i.  None of the above

7. class GFC215 {
static String m(float i) {return "float";}
static String m(double i) {return "double";}
public static void main (String[] args) {
int a1 = 1; long b1 = 2;
System.out.print(m(a1)+","+ m(b1));
}
}

What is the result of attempting to compile and run the program?

a.  Prints: float,float d.  Prints: double,double g.  None of the above
b.  Prints: float,double e.  Compile-time error
c.  Prints: double,float f.  Run-time error

8. class GFC301 {
private String name;
public GFC301(String name) {this.name = name;}
public void setName(String name) {this.name = name;}
public String getName() {return name;}
public static void m1(GFC301 r1, GFC301 r2) {
r1.setName("Bird");
r2 = r1;
}
public static void main (String[] args) {
GFC301 pet1 = new GFC301("Dog");
GFC301 pet2 = new GFC301("Cat");
m1(pet1,pet2);

123
System.out.println(pet1.getName() + "," +
pet2.getName());
}
}

What is the result of attempting to compile and run the program?

a.  Prints: Dog,Cat d.  Prints: Bird,Bird g.  None of the above
b.  Prints: Dog,Bird e.  Run-time error
c.  Prints: Bird,Cat f.  Compile-time error

9. class Maroon {
public static void main (String[] args) {
int a = 1; // 1
short b = 1; // 2
long c = 1; // 3
a = c + a; // 4
c = b + a; // 5
}
}

A compile-time error is generated at which line?

a.  1
b.  2
c.  3
d.  4
e.  5
f.  None of the above

124
10. class GFC304 {
static void m1(int[] i1, int[] i2) {
int[] i3 = i1; i1 = i2; i2 = i3;
}

public static void main (String[] args) {


int[] i1 = {1}, i2 = {3}; m1(i1, i2);
System.out.print(i1[0] + "," + i2[0]);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 1,1 d.  Prints: 3,3 g.  None of the above
b.  Prints: 1,3 e.  Run-time error
c.  Prints: 3,1 f.  Compile-time error

11. class GFC100 {


public static void main(String[] args) {
final short s1 = 1; // 1
final char c1 = 1; // 2
byte b1 = s1; // 3
byte b2 = c1; // 4
byte b3 = 1; // 5
byte b4 = 1L; // 6
byte b5 = 1.0; // 7
byte b6 = 1.0d; // 8
}
}

Compile-time errors are generated at which lines?

a.  1
b.  2
c.  3
d.  4
e.  5
f.  6
g.  7
h.  8

125
12. class JSC201 {
static byte m1() {
final char c1 = '\u0001';
return c1; // 1
}

static byte m2(final char c2) {return c2;} // 2


public static void main(String[] args) {
char c3 = '\u0003';
System.out.print(""+m1()+m2(c3)); // 3
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 13
b.  Prints: 4
c.  Compile-time error at 1
d.  Compile-time error at 2
e.  Run-time error
f.  None of the above

126
127
Chapter 6 : Inheritance
6.1 Inheritance Basics

Inheritance is the capability of a class to use the properties and methods of another class while
adding its own functionality. An example of where this could be useful is with an employee
records system. You could create a generic employee class with states and actions that are
common to all employees. Then more specific classes could be defined for salaried,
commissioned and hourly employees. The generic class is known as the parent (or superclass or
base class) and the specific classes as children (or subclasses or derived classes). The concept of
inheritance greatly enhances the ability to reuse code as well as making design a much simpler
and cleaner process.

Java uses the extends keyword to set the relationship between a child class and a parent class.

The Circle is a simple class that distinguishes circle objects only by their radii. Suppose, instead,
that we want to represent circles that have both a size and a position. For example, a circle of
radius 1.0 centered at point 0,0 in the Cartesian plane is different from the circle of radius 1.0
centered at point 1,2. To do this, we need a new class, which we'll call PlaneCircle. We'd like to
add the ability to represent the position of a circle without losing any of the existing functionality
of the Circle class. This is done by defining PlaneCircle as a subclass of Circle, so that
PlaneCircle inherits the fields and methods of its superclass, Circle.

class Circle {
double radius;

public double area() {


return Math.PI * radius * radius;
}
}

public class PlaneCircle extends Circle {

// We automatically inherit the fields and methods of Circle,


// so we only have to put the new stuff here.
// New instance fields that store the center point of the circle

double cx, cy;

// The area() method is inherited from Circle


// A new instance method that checks whether a point is inside
// the circle
// Note that it uses the inherited instance field radius

public boolean isInside(double x, double y) {


double dx = x - cx, dy = y - cy;
// Distance from center
double distance = Math.sqrt(dx*dx + dy*dy);

128
// Pythagorean theorem
return (distance < radius);
// Returns true or false
}

public static void main(String args[]) {


PlaneCircle pc=new PlaneCircle();
pc.radius = 10.0;
pc.cx = 50.0;
pc.cy = 40.0;
System.out.println(“Area of the circle :” +
pc.area());
//check whether a point (60,60) is within the circle
if(pc.isInside(60,60)) {
System.out.println(“Point 60,60 is inside the
circle “);
}
else {
System.out.println(“Point 60,60 is outside the
circle“);
}
}
}

A subclass inherits all the member variables and methods from its superclass. However, the
subclass might not have access to an inherited member variable or method. For example, a
subclass cannot access a private member inherited from its superclass. One might say, then, that
the item was not inherited at all. But the item is inherited. This becomes important when using an
inner class, which does have access to its enclosing class's private members. Note that
constructors are not members and so are not inherited by subclasses.

The Object class, defined in the java.lang package, defines and implements behavior that every
class needs. Normally, when a class is defined in Java, the inheritance from the Object class is
implicit. Therefore, the following two declarations of class "MyClass" are equivalent:

public class MyClass{

public class MyClass extends Object {

As depicted in the following figure, many classes derive from Object, many classes derive from
those classes, and so on, forming a hierarchy of classes.

129
At the top of the hierarchy, Object is the most general of all classes. Classes near the bottom of
the hierarchy provide more specialized behavior. A subclass derives from another class. The
term superclass refers to a class's direct ancestor or to any of its ascendant classes. Every class
has one and only one immediate superclass.

Java was designed without multiple inheritance. The overall design of Java supports the solution
of problems commonly solved with multiple inheritance in other ways. In particular, the singly
rooted hierarchy (with Object as the ultimate ancestor of all classes) and Java interfaces solves
most problems that are commonly solved using multiple inheritance in C++.

Example of Multi-level Inheritance

public class AstronomicalObject {


double magnitude;
}

public class Star extends AstronomicalObject {


double surfaceTemperature;
}

public class RedDwarf extends Star {


String subtype;
}

Using superclass variable to access subclass object

A superclass variable upwards in the hierarchy of Inheritance till the Object class can be used to
used to assign the subclass object. For example, in the above code the object of RedDwarf can be
created as follows:

RedDwarf rd = new RedDrawf();


Star rd = new RedDrawf();
AstronomicalObject rd = new RedDrawf();
Object rd = new RedDrawf();

130
6.2 Understanding how Constructors are called

A constructor for the base class is always called in the constructor for a derived class, chaining
upward so that a constructor for every base class is called. This makes sense because the
constructor has a special job: to see that the object is built properly. A derived class has access to
its own members only, and not to those of the base class (whose members are typically private).
Only the base-class constructor has the proper knowledge and access to initialize its own
elements. Therefore, it’s essential that all constructors get called, otherwise the entire object
wouldn’t be constructed properly. That’s why the compiler enforces a constructor call for every
portion of a derived class. It will silently call the default constructor if you don’t explicitly call a
base-class constructor in the derived-class constructor body. If there is no default constructor, the
compiler will complain. (In the case where a class has no constructors, the compiler will
automatically synthesize a default constructor.)

Let’s take a look at an example that shows the effects of composition, inheritance, and
polymorphism on the order of construction:
// Sandwich.java
// Order of constructor calls

class Meal {
Meal() { System.out.println("Meal()"); }
}

class Bread {
Bread() { System.out.println("Bread()"); }
}

class Cheese {
Cheese() { System.out.println("Cheese()"); }
}

class Lettuce {
Lettuce() { System.out.println("Lettuce()"); }
}

class Lunch extends Meal {


Lunch() { System.out.println("Lunch()");}
}

class PortableLunch extends Lunch {


PortableLunch() {
System.out.println("PortableLunch()");
}
}

class Sandwich extends PortableLunch {


Bread b;
Cheese c;
Lettuce l;

131
Sandwich() {
b = new Bread();
c = new Cheese();
l = new Lettuce();
System.out.println("Sandwich()");
}

public static void main(String[] args) {


new Sandwich();
}
}

This example creates a complex class out of other classes, and each class has a constructor that
announces itself. The important class is Sandwich, which reflects three levels of inheritance
(four, if you count the implicit inheritance from Object) and three member objects. When a
Sandwich object is created in main( ), the output is:
Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()

This means that the order of constructor calls for a complex object is as follows:
1. The base-class constructor is called. This step is repeated recursively such that the root of
the hierarchy is constructed first, followed by the next-derived class, etc., until the most-
derived class is reached.
2. Member initializers are called in the order of declaration.
3. The body of the derived-class constructor is called.

The order of the constructor calls is important. When you inherit, you know all about the base
class and can access any public and protected members of the base class. This means that you
must be able to assume that all the members of the base class are valid when you’re in the
derived class. In a normal method, construction has already taken place, so all the members of all
parts of the object have been built. Inside the constructor, however, you must be able to assume
that all members that you use have been built. The only way to guarantee this is for the base-
class constructor to be called first. Then when you’re in the derived-class constructor, all the
members you can access in the base class have been initialized. “Knowing that all members are
valid” inside the constructor is also the reason that, whenever possible, you should initialize all
member objects (that is, objects placed in the class using composition) at their point of definition
in the class (e.g.: b, c, and l in the example above). If you follow this practice, you will help
ensure that all base class members and member objects of the current object have been
initialized.

Use of super keyword

132
You can also use super within a constructor to invoke a superclass's constructor. Calling the
constructor for the superclass must be the first statement in the body of a constructor. If you are
satisfied with the default constructor in the superclass, there is no need to make a call to it
because it will be supplied automatically.

An object has the fields of its own class plus all fields of its parent class, grandparent class, all
the way up to the root class Object. It's necessary to initialize all fields, therefore all constructors
must be called! The Java compiler automatically inserts the necessary constructor calls in the
process of constructor chaining, or you can do it explicitly.

The Java compiler inserts a call to the parent constructor (super) if you don't have a constructor
call as the first statement of you constructor.

public class Point {


int m_x;
int m_y;

//============ Constructor
public Point() {
m_x = 10;
m_y = 20;
}
}

The following is the equivalent of the constuctor above.

//============ Constructor (same as in above example)


public Point() {
super(); // Calls the constructor of Object class
m_x = 10;
m_y = 20;
}

Normally, you don't explicitly write the constructor for your parent class, but there are two cases
where this is necessary:
 Passing parameters. You want to call a parent constructor which has parameters (the
default construct has no parameters).
 No parameterless constructor. There is no parent constructor with no parameters.

Example of class without parameterless constructor

/////////////////// class without a parameterless constructor.


// If any constructor is defined, the compiler doesn't
// automatically create a default parameterless constructor.

class Parent {
int _x;
Parent(int x) { // constructor
_x = x;

133
}
}

////////////////// class that must call super in constructor


class Child extends Parent {
int _y;
Child(int y) { // WRONG, needs explicit call to super.
_y = y;
}
}

In the example above, there is no explicit call to a constructor in the first line of constructor, so
the compiler will insert a call to the parameterless constructor of the parent, but there is no
parameterless parent constructor! Therefore this produces a compilation error. This problem can
be solved as follows :

Parent class can define a parameterless constructor.


/////////////////// class without a parameterless constructor.
// If any constructor is defined, the compiler doesn't
// automatically create a default parameterless constructor.
class Parent {
int _x;

Parent(int x) { // constructor with parameter


_x = x;
}

Parent() { // constructor without parameters


_x = 0;
}
}

A better way to define the parameterless constructor is to call the parameterized constructor so
that any changes that are made only have to be made in one constructor.

Parent() { // constructor without parameters


this(0);
}
}

Note that each of these constructors implicitly calls the parameterless constructor for its parent
class, etc, until the Object class is finally reached.

Example of passing parameters to the base class constructor.

class Circle {
double radius;

Circle(double radius) {

134
this.radius = radius;
}
}

class Cylinder extends Circle {


double height; //radius is inherited

Cylinder(double height, double radius) {


super (radius);
this.height = height;
}

public static void main(String args[]) {


Cylinder obj = new Cylinder(30,40);
}
}

6.3 Overriding Methods

In a derived class, if you include a method definition that has the same name and exactly the
same number and types of parameters as a method already defined in the base class, this new
definition replaces the old definition of the method.

A subclass inherits methods from a superclass. Sometimes, it is necessary for the subclass to
modify the methods defined in the superclass. This is referred to as method overriding. The
following example demonstrates method overriding.

class Circle {
//declaring the instance variable
protected double radius;

Circle(double radius) {
this.radius=radius;
}

// other method definitions here

public double getArea() {


return Math.PI*radius*radius;
}//this method returns the area of the circle

}// end of class circle

When the getArea method is invoked from an instance of the Circle class, the method returns the
area of the circle.

The next step is to define a subclass to override the getArea() method in the Circle class. The
derived class will be the Cylinder class. The getArea() method in the Circle class computes the
area of a circle, while the getArea method in the Cylinder class computes the surface area of a
cylinder. The Cylinder class is defined below.

135
class Cylinder extends Circle {
//declaring the instance variable
protected double length;

Cylinder(double radius,double length) {


super(radius);
this.length = length;
}

// other method definitions here


public double getArea() { // method overriden here
return 2*super.getArea()+2*Math.PI*radius*length;
} //this method returns the cylinder surface area

public static void main(String args[]) {


Circle myCircle;
myCircle = new Circle(1.20);
System.out.println(“Area of circle :”+ myCircle.getArea();

Cylinder myCylinder;
myCylinder = new Cylinder(1.20,2.50);
System.out.println(“Surface area of cylinder :” +
myCylinder.getArea());
}

}// end of class Cylinder

When the overriden method (getArea) is invoked for an object of the Cylinder class, the new
definition of the method is called and not the old definition from the superclass(Circle).

The ability of a subclass to override a method in its superclass allows a class to inherit from a
superclass whose behavior is "close enough" and then override methods as needed.

For example, all classes are descendents of the Object class. Object contains the toString
method, which returns a String object containing the name of the object's class and its hash code.
Most, if not all, classes will want to override this method and print out something meaningful for
that class.

public class Employee


{
private String name;

// overrides Object's toString method


public String toString() {
return name;
}

public static void main(String args[]) {


Employee e1 = new Employee();
e1.name = “John Smith”;

136
System.out.println(e1);
}
}

The toString() method is called implicitly when you try to print the object.

The return type, method name, and number and type of the parameters for the overriding method
must match those in the overridden method. The overriding method can have a different throws
clause as long as it doesn't declare any types not declared by the throws clause in the overridden
method. Also, the access specifier for the overriding method can allow more access than the
overridden method, but not less. For example, a protected method in the superclass can be
made public but not private.

Calling the Overridden Method

Sometimes, you don't want to completely override a method. Rather, you want to add more
functionality to it. To do this, simply call the overridden method using the super keyword. For
example,
super.overriddenMethodName();

Consider this class, Superclass:

public class Superclass {


public boolean aVariable;

public void aMethod() {


aVariable = true;
}
}

Now, here's a subclass, called Subclass, that overrides aMethod.

public class Subclass extends Superclass {


public void aMethod() {
//overrides aMethod in Superclass
aVariable = false;
super.aMethod();
System.out.println(aVariable);
}
}

super keyword cannot be used in a static reference.

Methods a Subclass Cannot Override

A subclass cannot override methods that are declared final in the superclass (by definition, final
methods cannot be overridden). These are discussed later.

137
Also, a subclass cannot override methods that are declared static in the superclass. In other
words, a subclass cannot override a class method. A subclass can hide a static method in the
superclass by declaring a static method in the subclass with the same signature as the static
method in the superclass.

Let's look at an example to see why. This example contains two classes. The first is Animal,
which contains one instance method and one class method:

public class Animal {


public static void hide() {
System.out.println("The hide method in Animal.");
}
public void override() {
System.out.println("The override method in Animal.");
}
}

The second class, a subclass of Animal, is called Cat:

public class Cat extends Animal {


public static void hide() {
System.out.println("The hide method in Cat.");
}
public void override() {
System.out.println("The override method in Cat.");
}
public static void main(String[] args) {
Cat myCat = new Cat();
Animal myAnimal = (Animal)myCat;
myAnimal.hide();
myAnimal.override();
}
}

The Cat class overrides the instance method in Animal called override and hides the class
method in Animal called hide. The main method in this class creates an instance of Cat, casts it
to a Animal reference, and then calls both the hide and the override methods on the instance. The
output from this program is as follows:

The hide method in Animal.


The override method in Cat.

The version of the hidden method that gets invoked is the one in the superclass, and the version
of the overridden method that gets invoked is the one in the subclass. For class methods, the
runtime system invokes the method defined in the compile-time type of the reference on which
the method is called. In the example, the compile-time type of myAnimal is Animal. Thus, the
runtime system invokes the hide method defined in Animal. For instance methods, the runtime
system invokes the method defined in the runtime type of the reference on which the method is

138
called. In the example, the runtime type of myAnimal is Cat. Thus, the runtime system invokes
the override method defined in Cat.

An instance method cannot override a static method, and a static method cannot hide an instance
method.

6.4 Dynamic Method Dispatch

Dynamic Inheritance is the ability of an object to inherit classes at runtime and provides several
key abilities. It is a mechanism by which a call to an overridden function is resolved at run time,
rather than compile time (run-time polymorphism). The principle is a superclass reference
variable can refer to a subclass object. It is the type of the object being referred to (not the type
of of the reference variable) that determines which version of an overridden method will be
executed

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; // reference variable of type a

r = a; // r refers to an A object
r.callme(); //calls A’s version of callme

r = b; // r refers to B object
r.callme(); //calls B’s version of callme

r = c; //refers to C object
r.callme(); //calls B’s version of callme

139
}
}

6.5 Annotations

Introduced in J2SE 5.0, annotations provide a way for programmers to instruct the compiler on
how to handle certain situations. For example, an annotation can indicate that a particular method
or class should be overridden in a subclass or that certain compiler error messages shouldn't be
printed. There are three useful annotations built-in to release 5.0 that will be discussed.

Annotations use the form @annotation and can be applied to methods or classes. For
example:

@Override class Cat extends Pet {

or

@Override void feedTheDog() { }

The following example illustrates all three built-in annotation types, using methods:

import java.util.List;
class Food {}
class Hay extends Food {}
class Animal {
Food getPreferredFood() {
return null;
}

@Deprecated static void deprecatedMethod() {

}
}

class Horse extends Animal {


Horse() {
return;
}

@Override //compiler error if getPreferredFood


//overloaded, not overridden
//Notice the return type is different
//(covariant return type).

Hay getPreferredFood() {
return new Hay();
}

140
@SuppressWarnings({"deprecation", "unchecked"})
void useDeprecatedMethod(List raw) {
//deprecation warning - suppressed
Animal.deprecateMethod();
//unchecked warning - suppressed
raw.add(new Horse());
}
}

java.lang.Override

The @Override annotation indicates that a method defined in the current class must override a
method is one of its superclasses. In the preceding example, the override annotation is used to
indicate that the getPreferredFood method in the Horse class is overriding the
getPreferredFood method in the Animal class. Note that this method is returning a different
type (Hay) than the superclass (Food) — this practice is called covariant return types.

If a method marked with @Override does not override the same method in one of its
superclasses, the compiler will generate an error message.

java.lang.Deprecated

The @Deprecated annotation indicates that the marked method should no longer be used.

Note: The @deprecated tag used by the Javadoc tool achieves the same result as
TM

@Deprecation. As of J2SE 5.0, the compiler-based @Deprecation annotation replaces the


Javadoc @deprecation tag.

In the preceding example, the deprecatedMethod in the Animal class is marked with the
deprecated annotation. Invoking or overriding the deprecatedMethod method will generate a
compile-time warning, unless that warning is suppressed in the subclass.

java.lang.SuppressWarnings

The @SuppressWarnings annotation indicates that the named compiler warnings should be
suppressed.

Note: This annotation can be used as of release 5.0 and some Java compiler implementations
may suppress compiler warnings, but this feature won't be fully implemented in javac until
release 6.0.

In the preceding example, the useDeprecatedMethod method in the Horse class uses the
suppress warnings annotation to suppress both the unchecked and deprecation warnings that
would otherwise occur.

141
It is strongly recommended that you suppressed warnings only where necessary. For example,
using the SuppressWarnings annotation on the entire Horse class is not recommended because
genuine errors in the code might be hidden.

6.6 Hiding Member Variables

Member variables defined in the subclass hide member variables that have the same name in the
superclass.

One interesting feature of Java member variables is that a class can access a hidden member
variable through its superclass. Consider the following superclass and subclass pair:

class Super {
Number aNumber;
}

class Subbie extends Super {


Float aNumber;
}

The aNumber variable in Subbie hides aNumber in Super. But you can access Super's aNumber
from Subbie with
super.aNumber

super keyword allows a method to refer to hidden variables.

Another example of variable hiding.

class SuperA {
int x = 10;
}

class SubA extends SuperA {


int x = 20; // hides x in superclass

void methodA() {
System.out.println(“ x in SuperA :” + super.x);
System.out.println(“ x in SuperA :” +
((SuperA)this).x);
System.out.println(“ x in SubA :” + x);
}

public static void main(String args[]) {


new SubA().methodA();
}
}

142
You can access a hidden variable by casting the object to its superclass, with the syntax
((Superclass)object).name.

6.7 Abstract Classes

Sometimes, a class that you define represents an abstract concept and, as such, should not be
instantiated. Take, for example, food in the real world. Have you ever seen an instance of food?
No. What you see instead are instances of carrot, apple, and chocolate. Food represents the
abstract concept of things that we all can eat. It doesn't make sense for an instance of food to
exist.

Similarly in object-oriented programming, you may want to model an abstract concept without
being able to create an instance of it. For example, the Number class in the java.lang package
represents the abstract concept of numbers. It makes sense to model numbers in a program, but
it doesn't make sense to create a generic number object. Instead, the Number class makes sense
only as a superclass to classes like Integer and Float, both of which implement specific kinds of
numbers. A class such as Number, which represents an abstract concept and should not be
instantiated, is called an abstract class. An abstract class is a class that can only be subclassed--
it cannot be instantiated.

To declare that your class is an abstract class, use the keyword abstract before the class keyword
in your class declaration:

abstract class Number {


. . .
}

If you attempt to instantiate an abstract class, the compiler displays an error similar to the
following and refuses to compile your program:
AbstractTest.java:6: class AbstractTest is an abstract class.
It can't be instantiated.
new AbstractTest();
^
1 error

Abstract class can contain static methods.

public abstract class test {


public static void main(String [] args) {
    int x = 3;
    int y = 1;
   if (x == y)
     System.out.println("Not equal");
  else
    System.out.println("Equal");
  }
}

143
6.8 Abstract Methods

An abstract class may contain abstract methods, that is, methods with no implementation. In this
way, an abstract class can define a complete programming interface, thereby providing its
subclasses with the method declarations for all of the methods necessary to implement that
programming interface. However, the abstract class can leave some or all of the implementation
details of those methods up to its subclasses.

Let's look at an example of when you might want to create an abstract class with an abstract
method in it. In an object-oriented drawing application, you can draw circles, rectangles, lines,
Bezier curves, and so on. Each of these graphic objects share certain states (position, bounding
box) and behavior (move, resize, draw). You can take advantage of these similarities and declare
them all to inherit from the same parent object--GraphicObject.

However, the graphic objects are also substantially different in many ways: drawing a circle is
quite different from drawing a rectangle. The graphics objects cannot share these types of states
or behavior. On the other hand, all GraphicObjects must know how to draw themselves; they
just differ in how they are drawn. This is a perfect situation for an abstract superclass.

First you would declare an abstract class, GraphicObject, to provide member variables and
methods that were wholly shared by all subclasses, such as the current position and the moveTo
method. GraphicObject also declares abstract methods for methods, such as draw, that need to
be implemented by all subclasses, but are implemented in entirely different ways (no default
implementation in the superclass makes sense). The GraphicObject class would look something
like this:

abstract class GraphicObject {


int x, y;
. . .
void moveTo(int newX, int newY) {
. . .
}
abstract void draw();
}

Each non-abstract subclass of GraphicObject, such as Circle and Rectangle, would have to
provide an implementation for the draw method.
class Circle extends GraphicObject {
void draw() {
. . .
}

144
}

class Rectangle extends GraphicObject {


void draw() {
. . .
}
}

An abstract class is not required to have an abstract method in it. But any class that has an
abstract method in it or that does not provide an implementation for any abstract methods
declared in its superclasses must be declared as an abstract class.

A subclass must override methods that are declared abstract in the superclass, or the subclass
itself must be abstract.

An abstract method cannot be static, synchronized or a final method.


public abstract class Shape {
public abstract double area(); // Abstract methods:
note
public abstract double circumference();
// semicolon instead of body.
}

class Circle extends Shape {


public static final double PI = 3.14;
protected double r;
// Instance data

public Circle(double r) { this.r = r; } //Constructor


public double getRadius() { return r; } //Accessor

// implementation abstract methods.


public double area() { return PI*r*r; }
public double circumference() { return 2*PI*r; }
}

class Rectangle extends Shape {


protected double w, h; // Instance data

public Rectangle(double w, double h) {


this.w = w; this.h = h;
}

public double getWidth() { return w; }


public double getHeight() { return h; }

public double area() { return w*h; }


public double circumference() { return 2*(w + h); }
}

145
class ShapeExample {
public static void main(String args[]) {
Shape[] shapes = new Shape[3];
// Create an array to hold shapes
shapes[0] = new Circle(2.0);
// Fill in the array
shapes[1] = new Rectangle(1.0, 3.0);
shapes[2] = new Rectangle(4.0, 2.0);

double total_area = 0;
for(int i = 0; i < shapes.length; i++)
total_area += shapes[i].area();
// Compute the area of the shapes
}
}

6.9 Final Classes

You can declare that your class is final, that is, that your class cannot be subclassed. There are
(at least) two reasons why you might want to do this: to increase system security by preventing
system subversion, and for reasons of good object-oriented design.

Security:

One mechanism that hackers use to subvert systems is to create a subclass of a class and then
substitute their class for the original. The subclass looks and feels like the original class but does
vastly different things, possibly causing damage or getting into private information. To prevent
this kind of subversion, you can declare your class to be final and thereby prevent any subclasses
from being created. The String class in the java.lang package is a final class for just this
reason. This class is so vital to the operation of the compiler and the interpreter that the Java
system must guarantee that whenever a method or object uses a String it gets exactly a
java.lang.String and not some other string. This ensures that all strings have no strange,
inconsistent, undesirable, or unpredictable properties.

If you try to compile a subclass of a final class, the compiler prints an error message and refuses
to compile your program. In addition, the bytecode verifier ensures that the subversion is not
taking place at the bytecode level. It does this by checking to make sure that a class is not a
subclass of a final class.

Design:

You may also wish to declare a class as final for object-oriented design reasons. You may think
that your class is "perfect" or that, conceptually, your class should have no subclasses.

To specify that your class is final, use the keyword final before the class keyword in your class
declaration.

146
For example, if you wanted to declare your (perfect) ChessAlgorithm class as final, its
declaration should look like this:

final class ChessAlgorithm {


. . .
}

Any subsequent attempts to subclass ChessAlgorithm will result in a compiler error such as the
following:
Chess.java:6: Can't subclass final classes: class ChessAlgorithm
class BetterChessAlgorithm extends ChessAlgorithm {
^
1 error

Another example of final class

class SmallBrain {}

final class Dinosaur {


int i = 7;
int j = 1;
SmallBrain x = new SmallBrain();
void f() {}
}

// class Further extends Dinosaur {}


// error: Cannot extend final class 'Dinosaur'

public class Jurassic {


public static void main(String[] args) {
Dinosaur n = new Dinosaur();
n.f();
n.i = 40;
n.j++;
}
}

6.10 Final Methods

Does creating a final class seem heavy-handed for your needs? Do you really just want to protect
some of your class's methods from being overridden? You can use the final keyword in a
method declaration to indicate to the compiler that the method cannot be overridden by
subclasses. As just shown, the Object class does this; some of its methods are final and some
are not.

You might wish to make a method final if it has an implementation that should not be changed
and it is critical to the consistent state of the object. For example, instead of making your
ChessAlgorithm class final, you might want instead to make the nextMove method final:

147
class ChessAlgorithm {
. . .
final void nextMove(ChessPiece pieceMoved,
BoardLocation newLocation)
{
...
}
. . .
}

Final methods cannot be abstract methods. All methods of final class are implicitly final.

Final Arguments

class Gizmo {
public void spin() {}
}

public class FinalArguments {


void with(final Gizmo g) {
// g = new Gizmo(); // Illegal -- g is final
g.spin();
}
void without(Gizmo g) {
g = new Gizmo(); // OK -- g not final
g.spin();
}

// void f(final int i) { i++; } // Can't change


// You can only read from a final primitive:

int g(final int i) { return i + 1; }


public static void main(String[] args) {
FinalArguments bf = new FinalArguments();
bf.without(null);
bf.with(null);
}
}

If a method is not final it can be overridden in the subclass. As seen above the object of the super
class can use dynamic method

6.11 Access control and Inheritance

When you are creating a subclass make sure that the super class is present in the same package.
If not, you will have to import the package using import statement discussed in the next chapter.
If you are not using packages, then take care to save the subclass in the same directory as the
baseclass as the directory acts as an unnamed package.

148
The private members in the base class are not inherited in the subclass. Hence private methods in
the base class are not overridden even though there is a method with the same name and same
signature in the subclass.

The protected members are inherited by the subclasses. If the base class is in the different
package import the package and you can use the protected members.

The members with no access specifier are of the type “package private”. Hence they can be used
only by the classes in that package or by the classes in the unnamed package. Hence if the
classes are of package type then they cannot be used outside the package. If you want to use
them outside the package declare them as public.

6.12 Anonymous Inner Class

Anonymous classes are classes that don’t have a name (hence the term anonymous). Because
they don’t have a name, there is no way to refer to them. For this reason, their declaration must
be given at creation time, as part of the new statement.

That requires yet another form of the new statement, as follows:

new <class or interface> <class’ body>

This form of the new statement declares a new anonymous class that extends a given class. It
also creates a new instance of that class and returns it as the result of the statement.

If the anonymous class extends another class, its body can access the class’s members, override
its methods, and so on, like any other regular class. If the anonymous class implements an
interface, its body must implement the interface’s methods.

Notice that the declaration of the anonymous class is made at compile time, and the instantiation
at runtime. That means that a new statement inside a for loop, for example, creates several
instances of the same anonymous class, and not one instance of several different anonymous
classes.

Technically, anonymous classes are considered nonstatic inner classes, so they have the same
privileges and limitations of nonstatic inner classes declared inside a method.

Anonymous classes are great when you need to perform some task that needs an object, but that
doesn’t justify creating a whole new class, maybe because the needed class is too simple or
because it's used only inside a single method. Anonymous classes are particularly useful for
quickly creating event handlers in Swing applications.

To define, in method scope, an anonymous nested class that implements a specified


interface:

An anonymous nested class is defined where is it instantiated (in a method). An anonymous


nested class must either implement an interface or extend a class, but the implements or extends

149
keywords are not used. For example the following line causes the method to return an object
which is an instance of an anonymous nested class:

return new SomeClass() { /*body of the anonymous class goes here*/ };

You might like to think of an anonymous nested class as part of a really long new statement,
which happens to contain a class definition, and which is why it has a ";" at the end. The
following example calls someMethod(), passing an instance of the anonymous nested class:

someMethod(new SomeClass() { /*body of the anonymous class goes here*/ });

In both cases SomeClass() is not the name of the anonymous class (anonymous means it has no
name) rather is it the name of the class that you are extending or the interface you are
implementing. These classes cannot define a constructor, as they do not have a name that you
can use to declare the constructor method. If SomeClass() is a class, the default constructor of
that class is called, if you want to use a non-default constructor instead, you supply arguments
e.g.:

return new SomeClass(12) { /*body of the anonymous class goes here*/ };

will call the SomeClass constructor which takes an int.

Examples:

public MyClass makeObj(final String name)


{
     return new SubClassOfMyClass() {
           public String toString()
           {
                 return "My name is "+name;
           }
     };
}

Only final members of the outer class can be accessed in the methods of the anonymous inner
class.

public Object makeObj(String name)


{
     final String objName = "My name is " + name;
 
     return new Object() {
           public String toString()
           {
                 return objName;
           }
     };
}

150
6.13 The Object class

Methods of Object class

protected native Object clone() throws CloneNotSupportedException

Creates a new object of the same class as this object. It then initializes each of the new object's
fields by assigning it the same value as the corresponding field in this object. No constructor is
called.

The clone method of class Object will only clone an object whose class indicates that it is willing
for its instances to be cloned. A class indicates that its instances can be cloned by declaring that
it implements the Cloneable interface.

An example of cloning an object:

class Car extends Cloneable {


String color;

Car(String color) {
this.color = color;
}

public String toString() {


return color + “Colored Car”;
}
}

class CloneExample {
public static void main(String args[])
throws CloneNotSupportedException {
Car c1 = new Car(“Red”);
System.out.println(c1);
Car c2 = (Car)c1.clone();
System.out.println(c2);
}
}

public boolean equals(Object obj)

Compares two Objects for equality. The equals method implements an equivalence relation:
 It is reflexive: for any reference value x, x.equals(x) should return true.
 It is symmetric: for any reference values x and y, x.equals(y) should return true if and
only if y.equals(x) returns true.
 It is transitive: for any reference values x, y, and z, if x.equals(y) returns true and
y.equals(z) returns true, then x.equals(z) should return true.

151
 It is consistent: for any reference values x and y, multiple invocations of x.equals(y)
consistently return true or consistently return false.
 For any reference value x, x.equals(null) should return false.

The equals method for class Object implements the most discriminating possible equivalence
relation on objects; that is, for any reference values x and y, this method returns true if and only
if x and y refer to the same object (x==y has the value true).

protected void finalize() throws Throwable

Called by the garbage collector on an object when garbage collection determines that there are
no more references to the object. A subclass overrides the finalize method to dispose of system
resources or to perform other cleanup.

Any exception thrown by the finalize method causes the finalization of this object to be halted,
but is otherwise ignored. The finalize method in Object does nothing.
public final native Class getClass()

Returns the runtime class of an object.

public native int hashCode()

Returns a hash code value for the object. This method is supported for the benefit of hashtables
such as those provided by java.util.Hashtable. The general contract of hashCode is:
 Whenever it is invoked on the same object more than once during an execution of a Java
application, the hashCode method must consistently return the same integer. This integer
need not remain consistent from one execution of an application to another execution of
the same application.
 If two objects are equal according to the equals method, then calling the hashCode
method on each of the two objects must produce the same integer result.

public final native void notify()

Wakes up a single thread that is waiting on this object's monitor. A thread waits on an object's
monitor by calling one of the wait methods.

This method should only be called by a thread that is the owner of this object's monitor. A thread
becomes the owner of the object's monitor in one of three ways:

 By executing a synchronized instance method of that object.


 By executing the body of a synchronized statement that synchronizes on the object.
 For objects of type Class, by executing a synchronized static method of that class.

Only one thread at a time can own an object's monitor.

152
public final native void notifyAll()

Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's
monitor by calling one of the wait methods.

This method should only be called by a thread that is the owner of this object's monitor. See the
notify method for a description of the ways in which a thread can become the owner of a
monitor.

public String toString()

Returns a string representation of the object. In general, the toString method returns a string
that "textually represents" this object. The result should be a concise but informative
representation that is easy for a person to read. It is recommended that all subclasses override
this method.

The toString method for class Object returns a string consisting of the name of the class of which
the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation
of the hash code of the object.

public final void wait() throws InterruptedException

Waits to be notified by another thread of a change in this object. The current thread must own
this object's monitor. The thread releases ownership of this monitor and waits until another
thread notifies threads waiting on this object's monitor to wake up either through a call to the
notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of
the monitor and resumes execution.

This method should only be called by a thread that is the owner of this object's monitor. See the
notify method for a description of the ways in which a thread can become the owner of a
monitor.

public final native void wait(long timeout) throws


InterruptedException

Waits to be notified by another thread of a change in this object.

The current thread must own this object's monitor. The thread releases ownership of this monitor
and waits until either of the following two conditions has occurred:
 Another thread notifies threads waiting on this object's monitor to wake up either through
a call to the notify method or the notifyAll method.
 The timeout period, specified by the timeout argument in milliseconds, has elapsed.

153
The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

This method should only be called by a thread that is the owner of this object's monitor. See the
notify method for a description of the ways in which a thread can become the owner of a
monitor.

public final void wait(long timeout, int nanos) throws


InterruptedException

Waits to be notified by another thread of a change in this object.

This method is similar to the wait method of one argument, but it allows finer control over the
amount of time to wait for a notification before giving up.

The current thread must own this object's monitor. The thread releases ownership of this monitor
and waits until either of the following two conditions has occurred:
 Another thread notifies threads waiting on this object's monitor to wake up either through
a call to the notify method or the notifyAll method.
 The timeout period, specified by timeout milliseconds plus nanos nanoseconds
arguments, has elapsed.

The thread then waits until it can re-obtain ownership of the monitor and resumes execution

This method should only be called by a thread that is the owner of this object's monitor. See the
notify method for a description of the ways in which a thread can become the owner of a
monitor.

Summary

Extending an existing class often provides an easy way to create a new type.  This is primarily
true when an existing class creates a type whose features are close to, but not identical to the
features needed in the new type. When an existing class is extended to define a new class, the
existing class is often called the superclass and the new class is often called the subclass. The
subclass inherits all of the variables and all of the methods defined in the superclass and its
superclasses. Inheritance provides a formal mechanism for code reuse.

Except for the Object class, a class has exactly one direct superclass. A class inherits member
variables and methods from all its superclasses, whether direct or indirect. A subclass can
override methods that it inherits, or it can hide variables or methods that it inherits. The Object
class is the top of the class hierarchy. All classes are descendants from this class and inherit
methods from it. Useful methods inherited from Object include toString, equals, clone, getClass,
wait, notify, and notifyAll. You can prevent a class from being subclassed by using the final
keyword in the class's declaration. Similarly, you can prevent a method from being overridden
by subclasses by declaring it as a final method.

154
An abstract class can only be subclassed; it cannot be instantiated. An abstract class can contain
abstract methods — methods that are declared but not implemented. Subclasses provide the
implementations for abstract methods.

Questions

1. class Color {}
class Red extends Color {}
class Blue extends Color {}
class A {
public static void main (String[] args) {
Color color1 = new Red(); Red color2 = new Red();
boolean b1 = color1 instanceof Color;
boolean b2 = color1 instanceof Blue;
boolean b3 = color2 instanceof Blue;
System.out.print(b1+","+b2+","+b3);
}
}

What is the result of attempting to compile and run the program?

a.  false,false,false e.  true,false,false i.  Run-time error


b.  false,false,true f.  true,false,true j.  Compile-time error
c.  false,true,false g.  true,true,false k.  None of the above
d.  false,true,true h.  true,true,true

2. Which of the following modifiers can be applied to the declaration of a field?

a.  abstract c.  private e.  public


b.  final d.  protected

3. class A {A(int i) {}} // 1


class B extends A {} // 2

Which of the following statements are true?

a.  The compiler attempts to create a default constructor for class A.


b.  The compiler attempts to create a default constructor for class B.
c.  Compile-time error at 1.
d.  Compile-time error at 2

4. Which of the follow statements is true.


a.  An anonymous class can be declared abstract.

155
b.  A local class can be declared abstract.
c.  An abstract class can be instantiated.
d.  An abstract class is implicitly final.
e.  An abstract class must declare at least one abstract method.
f.  An abstract class can not extend a concrete class.
5. public class Basics {} // 1
class Basics1 {} // 2
protected class Basics2 {} // 3
private class Basics3 {} // 4
Class Basics4 {} // 5

Suppose these are top-level class declarations and not nested class declarations; and suppose that
all of the declarations are contained in one file named Basics.java. Compile-time errors are
generated at which lines?

a. 1 c.  3 e.  5
b.  2 d.  4

6. class A11 {public String toString() {return "A11";}}


class A12 {
public static void main(String[] arg) {
A11[] a1 = new A11[1]; // 1
A11[][] a2 = new A11[2][]; // 2
A11[][][] a3 = new A11[3][][]; // 3
a1[0] = new A11(); // 4
a2[0] = a2[1] = a1; // 5
a3[0] = a3[1] = a3[2] = a2; // 6
System.out.print(a3[2][1][0]); // 7
}
}

What is the result of attempting to compile and run the program?

a.  Prints: null g.  Compile-time error at 5.


b.  Prints: A11 h.  Compile-time error at 6.
c.  Compile-time error at 1. i.  Compile-time error at 7.
d.  Compile-time error at 2. j.  Run-time error
e.  Compile-time error at 3. k.  None of the above
f.  Compile-time error at 4.

156
Chapter 7 : Packages and Interfaces
7.1 Packages

To make classes easier to find and to use, to avoid naming conflicts, and to control access,
programmers bundle groups of related classes and interfaces into packages.

Definition:  A package is a collection of related classes and interfaces providing access


protection and namespace management.

The classes and interfaces that are part of the Java platform are members of various packages
that bundle classes by function: fundamental classes are in java.lang, classes for reading and
writing (input and output) are in java.io, and so on. You can put your classes and interfaces in
packages, too.

Let's look at a set of classes and examine why you might want to put them in a package.
Suppose that you write a group of classes that represent a collection of graphic objects, such as
circles, rectangles, lines, and points. You also write an interface, Draggable, that classes
implement if they can be dragged with the mouse by the user:

//in the Graphic.java file


public abstract class Graphic {
. . .
}

//in the Circle.java file


public class Circle extends Graphic implements Draggable {
. . .
}

//in the Rectangle.java file


public class Rectangle extends Graphic implements Draggable {
. . .
}

//in the Draggable.java file


public interface Draggable {
. . .
}

You should bundle these classes and the interface in a package for several reasons:
 You and other programmers can easily determine that these classes and interfaces are
related.
 You and other programmers know where to find classes and interfaces that provide
graphics-related functions.
 The names of your classes wont conflict with class names in other packages, because the
package creates a new namespace.

157
You can allow classes within the package to have unrestricted access to one another yet still
restrict access for classes outside the package.

Package declarations

Each file must have a package declaration which precedes all non-comment code. The package
name must be the same as the enclosing directory. For example, here are two files in the
packagetest directory.

//ClassA.java
package packagetest;
class ClassA {
public static void main(String[] args) {
ClassB.greet();
}
}

//ClassB.java
package packagetest;
class ClassB {
static void greet() {
System.out.println("Hi");
}
}

Note that these source files must be named ClassA.java and ClassB.java (case matters) and they
must be in a directory named packagetest.

Package names are identifiers - they can use mixed case and be of any length. Conventionally,
package names start with a lowercase letter.

While the Java Language specification does not put a limit on the length of a package name, it
does recommend that package names be used as directory names. UNIX operating systems
typically require that the full path to a file, from root through file name, be limited to 1024
characters total. It is recommended to use package names of a dozen characters or less.

If the package declaration is not given, then the class in the source file is placed in the unnamed
package. The unnamed package is often used when creating classes for small applications.
However, for larger projects all code should be placed in a named package - such as one named
after the application. This helps avoid potential name space collisions.

Another example of creating a package

package world;

public class HelloWorld {


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

158
}
}

Create a folder world in c: drive and save the class file as HelloWorld.java

Compiling and running packages from a command line

To compile the above example, you must be outside the packagetest directory. To compile the
classes:
javac packagetest/ClassB.java
javac packagetest/ClassA.java

To run the main program in ClassA.


java packagetest.ClassA
or
java packagetest/ClassA

In windows the "/" can be replaced by the "\" in the javac command, but not in the java
command. Generally use a forward slash ("/") because it is used more commonly than the
backslash in other places as well.

Setting up the CLASSPATH

If the HelloWorld class is saved as described above the classpath can be set as follows. On the
command prompt type this

set CLASSPATH=.;C:\;

We set the CLASSPATH to point to 2 places, . (dot) and C:\ directory.

If you used to play around with DOS or UNIX, you may be familiar with . (dot) and .. (dot dot).
We use . as an alias for the current directory and .. for the parent directory. In our CLASSPATH we
include this for convenient reason. Java will find our class file not only from C: directory but
from the current directory as well. Also, we use ; (semicolon) to separate the directory location in
case we keep class files in many places.

When compiling HelloWorld class, we just go to the world directory and type the command:

C:\world>javac HelloWorld.java

If you try to run this HelloWorld using java HelloWorld, you will get the following error:
C:\world>java HelloWorld
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld (wrong
name:
world/HelloWorld)
at java.lang.ClassLoader.defineClass0(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:442)

159
at
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:101)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:248)
at java.net.URLClassLoader.access$1(URLClassLoader.java:216)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:191)
at java.lang.ClassLoader.loadClass(ClassLoader.java:290)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:286)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

The reason is right now the HelloWorld class belongs to the package world. If we want to run it,
we have to tell JVM about its fully-qualified class name (world.HelloWorld) instead of its
plain class name (HelloWorld).
C:\world>java world.HelloWorld
C:\world>Hello World

Note: fully-qualified class name is the name of the java class that includes its package name

Nesting packages

Package declarations may be a string of names, separated by dots, to create nested packages.
This is useful for creating a hierarchy of packages. For instance, there may be a project "abc"
package in which are found several nested packages for "vis" work, "database" work, and so
forth. Within the "vis" package may be several more nested packages to do data management,
rendering, etc.

package abc.vis.renderer;

class MyClass
{

7.2 Using package members


Only public package members are accessible outside the package in which they are defined. To
use a public package member from outside its package, you must do one or more of the
following:
 Refer to the member by its long (qualified) name
 Import the package member
 Import the member's entire package

Referring to a Package Member by Name

So far, the examples in this book have referred to types by their simple names, such as
Rectangle, Circle etc. You can use a package member's simple name if the code you are
writing is in the same package as that member or if that member has been imported.

160
However, if you are trying to use a member from a different package and that package has not
been imported, you must use the member's qualified name, which includes the package name.
This is the qualified name for the ClassA class declared in the packagetest package in the
previous example:

packagetest.ClassA

You could use this long name to create an instance of packagetest.

packagetest.ClassA obj = new packagetest.ClassA();

You'll find that using long names is okay for one-shot uses. But you'd likely get annoyed if you
had to write packagetest.ClassA again and again. Also, your code would get messy and difficult to
read. In such cases, you can just import the member instead.

Importing a Package Member

To import a specific member into the current file, put an import statement at the beginning of
your file before any class or interface definitions but after the package statement, if there is one.
Here's how you would import the ClassA class from the packagetest package created in the
previous section:

import packagetest.ClassA;

Now you can refer to the ClassA class by its simple name:

ClassA obj = new ClassA();

This approach works well if you use just a few members from the packagetest package. But if
you use many types from a package, you can import the entire package.

Importing an Entire Package

To import all the types contained in a particular package, use the import statement with the
asterisk (*) wildcard character:

import packagetest.*;

Now you can refer to any class or interface in the graphics package by its short name:

ClassA obj = new ClassA();


ClassB objB = new ClassB();

The asterisk in the import statement can be used only to specify all the classes within a package,
as shown here. It cannot be used to match a subset of the classes in a package. For example, the
following does not match all the classes in the packagetest package that begin with C:

161
import packagetest.C*; // does not work

Instead, it generates a compiler error. With the import statement, you generally import only a
single package member or an entire package.

Note: Another, less common form of import allows you to import only a class and its public
inner classes. For example, if the packagetest.ClassB class contained useful inner classes, like
ClassB.Rectangle and ClassB.Square, you could import ClassB and its inner classes this way:

import packagetest.ClassB.*;

For your convenience, the Java compiler automatically imports three entire packages:

 The default package (the package with no name)


 The java.lang package

Note: Packages aren't hierarchical. For example, importing java.util.* doesn't let you refer to
the Pattern class as regex.Pattern. You must always refer to it as either
java.util.regex.Pattern or (if you import java.util.regex.*) simply Pattern.

Disambiguating a Name

If by some chance a member in one package shares the same name with a member in another
package and both packages are imported, you must refer to each member by its qualified name.
For example, lets consider that you have created this package

package graphics;

class Rectangle {

The java.awt package also contains a Rectangle class. If both graphics and java.awt have
been imported, the following is ambiguous:

Rectangle rect;

In such a situation, you have to be more specific and use the member's qualified name to indicate
exactly which Rectangle class you want:

graphics.Rectangle rect;

Avoid duplicating import statement. Also there is no need to import the classes in the same
package. Don’t import unnecessary classes.

If a class contains package declaration, import statement and class definition they should be
written only in the same given order.

162
7.3 Interfaces

Interfaces are part of what is known as “programming by contract”. This means that a
programmer creates something that obliges other programmers to follow a set of conditions.
Interfaces are also considered to be the way Java gains some of the benefits of multiple
inheritance without the drawbacks.

In Java an interface is similar to an abstract class in that its members are not implemented. In
interfaces, _none_ of the methods are implemented. There is no code at all associated with an
interface. For example

public interface Comparable


{
boolean less(Object m);
boolean greater(Object m);
boolean lessEqual(Object m);
boolean greaterEqual(Object m);
}

All instance methods are implicitly public and abstract. You can mark them as such, but are
discouraged from doing so as the marking is considered obsolete practice. The interfaces
themselves need not be public and several interfaces in the standard libraries are not public and
thus used only internally.

All constant values defined in an interface are implicitly public, static, and final. Member
declarations in an interface disallow the use of some declaration modifiers; you cannot use
transient, volatile, or synchronized in a member declaration in an interface. Also, you may
not use the private and protected specifiers when declaring members of an interface.

An interface creates a protocol that classes may implement. Note that one can extend an interface
(to get a new interface) just as you can extend a class. One can actually extend several interfaces.
Interfaces thus enjoy the benefits of multiple inheritance. (Classes do not.) There are almost no
disadvantages to multiple inheritance of interface (small name conflict problems are one
exception).

The Polynomial class that implements Comparable will need to implement all of the functions
declared in the interface.

public class Polynomial implements Comparable


{ . . .
boolean less(Object m){ . . . }
boolean greater(Object m){ . . . }
boolean lessEqual(Object m){ . . . }
boolean greaterEqual(Object m){ . . . }

Polynomial multiply(Polynomial P){ . . . }


. . .
}

163
A class may choose to implement any number of interfaces. A class that implements an interface
must provide bodies for all methods of that interface. Also, an abstract class can choose to
implement part of an interface leaving the rest for non-abstract subclasses.

The usefulness of interfaces goes far beyond simply publishing protocols for other programmers.

Consider the simple example of a class Car that implements interface Vehicle. Interface Vehicle
has a single method called start(). Class Car will implement the interface by providing a start()
method. Other functionality in the Car class has been left out for the sake of clarity.

interface Vehicle {
 // All  vehicle implementations must implement the start
//method
   public void start();
}

class Car implements Vehicle{


    //  Required to implement Vehicle
   public void start(){ ... }
}

Having laid the foundations of the Car object, we can create another object called Driver. It is the
Driver's job to start the Car and bring it to the restaurant patron. The Driver object can be written
without interfaces, as follows:

class Driver {
   public Car getCar( Car c){ ... }
}

The Driver object has a method called getCar that returns a Car object. This code example
satisfies the functional requirements of the system, but it forever links the Driver object with that
of the Car. In this situation, the two objects are said to be tightly coupled. The Driver object
requires knowledge of the Car object and has access to all public methods and variables
contained within that object. It is best to avoid such tight coupling of code because it increases
dependencies and reduces flexibility.

To code the Driver object using interfaces, the following implementation could be used:

class Driver{
   public Vehicle getVehicle( Vehicle c) {  ...  }
}

While the code changes are fairly minor -- changing the references from Car to Vehicle -- the
effects on the development cycle are considerable. Using the second implementation, the Driver
has knowledge only of the methods and variables defined in the Vehicle interface. Any other
public methods and data contained in the specific implementation of the Vehicle interface are
hidden from the user of the Vehicle object.

164
This simple code change has ensured the proper concealment of information and implementation
from other objects, and has therefore eliminated the possibility that developers will use
undesirable methods.

Defining object types with interfaces

The Java interface keyword declares a type and the implements keyword guarantees that a class
either implements or defers the implementation of all operations for each type specified in the
implements clause. That guarantees that objects instantiated from concrete classes possess
implementation code for all the operations of each type specified in the implements clause.

Consider the following interface and class definitions:

interface Foo
{
  String m3();
}

public class Base


{
   public String m1()
   {
     return "Base.m1()";
   }

   public String m2( String s )


   {
     return "Base.m2(" + s + ")";
   }

   private String p()


   {
     return "Base.p()";
   }
}

public class Derived extends Base implements Foo


{
  public String m1()
  {
    return "Derived.m1";
  }

  public String m3()


  {
    return "Derived.m3()";
  }
}

165
Interface Foo declares a new type, Foo, with a single operation, m3(). The definition of class
Derived differs from before only by the addition of the implements Foo clause.

The additional implements Foo clause means type Derived also subtypes Foo. Thus you achieve
multiple type inheritance: type Derived subtypes type Base and type Foo. Let's examine the
ramifications of these type definitions.

Derived derived = new Derived();


Foo  foo  = derived;
Base base = derived;
foo = base;                        // REJECT

The first statement attaches a type Derived variable to a type Derived object-creation expression.
The second statement attaches a variable of type Foo to the created object. The type-checker
enforces conformance between the type Derived variable and the type Foo variable by verifying
that Derived actually subtypes Foo. The third statement similarly passes type-checking. Note that
these conformance checks consider the variable type, not the attached object type. The type-
checker rejects the fourth statement since Foo does not subtype Base, even though foo and base
point to the same object. Incompatible variable types prevent this attempt to attach a variable to
the very object to which it is already attached.

Now let's take a look at method invocation via the different variable types.

Derived derived = new Derived();


Foo  foo  = derived;
Base base = derived;

// call m3()
System.out.println( derived.m3() );
System.out.println( foo.m3() );
System.out.println( base.m3() );      // REJECT

// call m1()
System.out.println( derived.m1() );
System.out.println( foo.m1() );       // REJECT
System.out.println( base.m1() );

Section 1 calls method m3() through three different reference variable types. Since type Base
does not possess operation m3(), the type-checker rejects the section's third statement. Similarly,
the type-checker rejects the second statement in Section 2 since type Foo does not possess
operation m1(). Remarkably, the three variables remain attached to the same object for every
method call, and that object has implementation for both the m1() and m3() methods. In the
rejected statements, the type-checker overrules the underlying Derived object's ability to perform
the specified method call by enforcing variable type conformance.

Implementing multiple inheritance in Java

If you want to write something similar to:

166
//this code will give compile time error
public class Employee extends Person, Employment {
// detail omitted
}

Here, Person is a concrete class that represents a person, while Employment is another concrete
class that represents the details of a person who is employed. If you could only put them
together, you would have everything necessary to define and implement an Employee class.
Inheriting implementation from more than one superclass - multiple implementation inheritance -
is not a feature of Java. Java allows a class to have a single superclass and no more.

On the other hand, a class can implement multiple interfaces. In other words, Java supports
multiple interface inheritance. Suppose the PersonLike interface is:

public interface PersonLike {


String getName();
int getAge();
}

and the EmployeeLike interface is:

public interface EmployeeLike {


float getSalary();
java.util.Date getHireDate();
}

You can create an Employee class like this :

public class Employee implements PersonLike,EmploymentLike {


//details omitted
}

Difference between an Interface and an Abstract class

An Abstract class declares have at least one instance method that is declared abstract which will
be implemented by the subclasses. An abstract class can have instance methods that implement a
default behavior. An Interface can only declare constants and instance methods, but cannot
implement default behavior.

Subinterfaces

One interface may be described as a subinterface of another if it extends its properties (i.e.,
contains additional methods.)

In Java, each subinterface must be explicitly listed as extending one or more other interfaces,
implicitly inheriting all of the super-interface operations. For example:

interface File {

167
public void open(String name);
public void close();
}

interface ReadableFile extends File {


public byte readByte();
}

interface WritableFile extends File {


public void writeByte(byte b);
}

interface ReadWriteFile extends ReadableFile, WritableFile {


public void seek(int position);
}

7.4 Static Import

Many classes, including many in the Java core libraries, contain static constants that are used
within the class and are also useful outside the class. For example, the java.lang.Math class
contains the constants PI and E for pi and e, respectively.

Prior to Java version 5.0, the only way to access those constants was by fully spelling out the
names Math.PI, Math.E, BorderLayout.NORTH, etc. in your code. With static imports, you can
use just PI, E, and NORTH without all the extra typing. To use static imports, add the static
keyword to the import statement as follows:

  import static java.lang.Math.PI;

Then in the code body you can use

  double area = PI * radius * radius;

instead of

  double area = Math.PI * radius * radius;

Wildcards also work in the import static statement:

  import static java.lang.Math.*;

For occasional use, simply typing the Math.PI is probably easier, but if constants from another
class are used extensively, then the static import feature will reduce the code and also make it
easier to read.

In addition to the constants, all the many static methods in the Math class are also available when
you use the wildcard static import line above. For example,

  double logarithm = log (number);

168
instead of

  double logarithm = Math.log (number);

Interfaces with Constants Only

Before the static import became available, a trick for avoiding the need to write the class name
for static constants was to create an interface whose only purpose is to hold constants.

For example, say that you need the constants ALPHA and OMEGA for several different programs.
The first option is to create a utility class that holds the constants. e.g.:

  public class MyConstants


  {
     final static double ALPHA = 1.1;
     final static double OMEGA = 901.0
  }

Then in your other classes, you would refer to these constants with

  MyConstants.ALPHA
  MyConstants.OMEGA

However, placing the MyConstants class name wherever these constants appear can be tedious
and also makes the code less readable, especially in a formula like

   x = (3.1 * MyConstants.ALPHA)/(1.0 + MyConstants.OMEGA);

An alternative is to put the constants into an interface. This will not interfere with the class
design since there is no limit to the number of interfaces that a class can implement.

  public interface MyConstantsImpl


  {
    static final double ALPHA = 1.1;
    static final double OMEGA = 901.0
  }

Any class that needs these constants can implement MyConstantsImpl. The methods in the
program will then refer to the constants simply with ALPHA and OMEGA.

Then a method in the class that implements MyConstantsImpl could use the constants in an
equation without the class reference:

   x = (3.1*ALPHA)/(1.0 + OMEGA);

whcih is far more readable.

169
This technique, however, violates the object-oriented design of the language. That is, you are not
really implementing anything. You would not think of a class that implements MyConstantsImpl
as a MyConstants object in the sense of taking on an identifiable behavior of an interface.

So constants-only interfaces are ill advised and considered bad programming style . Use a class
instead and then statically import the class.

7.5 strictfp

The keyword "strictfp" is used to control certain aspects of floating-point arithmetic.

You can use strictfp as a modifier of class, interface, and method declarations, like this:

// legal uses of strictfp


strictfp interface A {}
public strictfp class FpDemo1 {
strictfp void f() {}
}

You cannot use strictfp on constructors or methods within interfaces:

// illegal uses of strictfp


interface A {
strictfp void f();
}
public class FpDemo2 {
strictfp FpDemo2() {}
}

The strictfp keyword is used to designate an expression as "FP-strict." If a class, interface, or


method is declared using strictfp, then the class, interface, or method is FP-strict. So too are all
classes, interfaces, methods, constructors, instance initializers, variable initializers, and static
initializers within the declaration.

An expression is FP-strict if it occurs anywhere within one of these FP-strict declarations, or if it


is a compile-time constant expression. In practical terms, this means that if a class or method is
declared with strictfp, any expression that occurs within the class or method is an FP-strict
expression.

Because constructors cannot be declared using strictfp, they are FP-strict only if their defining
class is FP-strict. Methods within interfaces cannot be declared using strictfp because this is an
implementation rather than an interface property.

So what does FP-strict actually mean? Consider the following example:

public strictfp class FpDemo3 {


public static void main(String[] args) {
double d = 8e+307;

170
System.out.println(4.0 * d * 0.5);
System.out.println(2.0 * d);
}
}

The maximum value of a double (Double.MAX_VALUE) is approximately 1.8e+308. In the


FpDemo3 example, the first expression is evaluated as:

(4.0 * d) * 0.5

because the Java programming language guarantees a left-to-right order of evaluation. When the
first part of the expression is evaluated, the result is 32e+307 or 3.2e+308, which is larger than
Double.MAX_VALUE.

Because the expression is FP-strict, the implementation is required to evaluate the whole
expression as resulting in positive infinity (which the program prints as "Infinity"). This is true
even though the later multiplication by 0.5 produces a final value for the expression of 1.6e+308,
which is less than Double.MAX_VALUE.

By contrast, if the expression is not FP-strict, an implementation is allowed to use an extended


exponent range to represent intermediate results. In the FpDemo3 example, this could keep the
expression from overflowing, and produce a final result that is within range. An implementation
is not required to do this; it can, in effect, use FP-strict rules everywhere.

Note that multiplication in this example is not associative, in that:

(4.0 * d) * 0.5 != 4.0 * (d * 0.5)

strictfp is important because its use guarantees common behavior across different Java
implementations. In other words, you can know that the floating-point arithmetic in your
application behaves the same when you move your application to a different Java
implementation or hardware platform.

Summary

Packages are important as they act as a namespace. They help to avoid conflict in classes and
you can group the related classes together as a single package. Interfaces are used as a
programming discipline. They are also helpful while using multiple inheritance. The static
import is a new concept of J2SE 5.0. It helps you to use the class members without using the
class name.

Questions

1. interface I1 {} interface I2 {}
class Base implements I1 {}
class Sub extends Base implements I2 {}
class Red {
public static void main(String args[]) {

171
Sub s1 = new Sub();
I2 i2 = s1; // 1
I1 i1 = s1; // 2
Base base = s1; // 3
Sub s2 = (Sub)base; // 4
}
}

A compile-time error is generated at which line?

a.  1
b.  2
c.  3
d.  4
e.  None of the above

172
2. package com.dan.chisholm;
public class A {
public void m1() {System.out.print("A.m1, ");}
protected void m2() {System.out.print("A.m2, ");}
private void m3() {System.out.print("A.m3, ");}
void m4() {System.out.print("A.m4, ");}
}
class B {
public static void main(String[] args) {
A a = new A();
a.m1(); // 1
a.m2(); // 2
a.m3(); // 3
a.m4(); // 4
}}

Assume that the code appears in a single file named A.java. What is the result of attempting to
compile and run the program?

a.  Prints: A.m1, A.m2, A.m3, A.m4, d.  Compile-time error at 3.


b.  Compile-time error at 1. e.  Compile-time error at 4.
c.  Compile-time error at 2. f.  None of the above

173
Chapter 8 : Assertions and Exception handling
8.1 What is an Exception?

The Java language uses exceptions to provide error-handling capabilities for its programs. An
exception is an event that occurs during the execution of a program that disrupts the normal flow
of instructions.

The term exception is shorthand for the phrase "exceptional event."

Many kinds of errors can cause exceptions--problems ranging from serious hardware errors, such
as a hard disk crash, to simple programming errors, such as trying to access an out-of-bounds
array element. When such an error occurs within a Java method, the method creates an
exception object and hands it off to the runtime system. The exception object contains
information about the exception, including its type and the state of the program when the error
occurred. The runtime system is then responsible for finding some code to handle the error. In
Java terminology, creating an exception object and handing it to the runtime system is called
throwing an exception.

After a method throws an exception, the runtime system leaps into action to find someone to
handle the exception. The set of possible "someones" to handle the exception is the set of
methods in the call stack of the method where the error occurred. The runtime system searches
backwards through the call stack, beginning with the method in which the error occurred, until it
finds a method that contains an appropriate exception handler. An exception handler is
considered appropriate if the type of the exception thrown is the same as the type of exception
handled by the handler. Thus the exception bubbles up through the call stack until an
appropriate handler is found and one of the calling methods handles the exception. The
exception handler chosen is said to catch the exception.

If the runtime system exhaustively searches all of the methods on the call stack without finding
an appropriate exception handler, the runtime system (and consequently the Java program)
terminates.

By using exceptions to manage errors, Java programs have the following advantages over
traditional error management techniques:

 Advantage 1: Separating Error Handling Code from "Regular" Code


 Advantage 2: Propagating Errors Up the Call Stack
 Advantage 3: Grouping Error Types and Error Differentiation

Advantage 1: Separating Error Handling Code from "Regular" Code

In pseudo-code, your function might look something like this:


readFile {
open the file;

174
determine its size;
allocate that much memory;
read the file into memory;
close the file;
}

At first glance this function seems simple enough, but it ignores all of these potential errors:
 What happens if the file can't be opened?
 What happens if the length of the file can't be determined?
 What happens if enough memory can't be allocated?
 What happens if the read fails?
 What happens if the file can't be closed?

To answer these questions within your read_file function, you'd have to add a lot of code to do
error detection, reporting and handling. Your function would end up looking something like this:
errorCodeType readFile {
initialize errorCode = 0;
open the file;
if (theFileIsOpen) {
determine the length of the file;
if (gotTheFileLength) {
allocate that much memory;
if (gotEnoughMemory) {
read the file into memory;
if (readFailed) {
errorCode = -1;
}
} else {
errorCode = -2;
}
} else {
errorCode = -3;
}
close the file;
if (theFileDidntClose && errorCode == 0) {
errorCode = -4;
} else {
errorCode = errorCode and -4;
}
} else {
errorCode = -5;
}
return errorCode;
}

There's so much error detection, reporting, and returning that the original 7 lines of code are lost
in the clutter. And worse yet, the logical flow of the code has also been lost in the clutter,
making it difficult to tell if the code is doing the right thing: Is the file really being closed if the

175
function fails to allocate enough memory? It's even more difficult to ensure that the code
continues to do the right thing after you modify the function three months after writing it. Many
programmers "solve" this problem by simply ignoring it--errors are "reported" when their
programs crash.

Java provides an elegant solution to the problem of error management: exceptions. Exceptions
enable you to write the main flow of your code and deal with the, well, exceptional cases
elsewhere. If your read_file function used exceptions instead of traditional error management
techniques, it would look something like this:

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;
}
}

Advantage 2: Propagating Errors Up the Call Stack

A second advantage of exceptions is the ability to propagate error reporting up the call stack of
methods. Suppose that the readFile method is the fourth method in a series of nested method
calls made by your main program: method1 calls method2, which calls method3, which finally
calls readFile.
method1 {
call method2;
}
method2 {
call method3;
}
method3 {
call readFile;
}

Suppose also that method1 is the only method interested in the errors that occur within
readFile. Traditional error notification techniques force method2 and method3 to propagate the

176
error codes returned by readFile up the call stack until the error codes finally reach method1--
the only method that is interested in them.
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;
}

The Java runtime system searches backwards through the call stack to find any methods that are
interested in handling a particular exception. A Java method can "duck" any exceptions thrown
within it, thereby allowing a method further up the call stack to catch it. Thus only the methods
that care about errors have to worry about detecting errors.

method1 {
try {
call method2;
} catch (exception) {
doErrorProcessing;
}
}
method2 throws exception {
call method3;
}
method3 throws exception {
call readFile;
}

However, as you can see from the pseudo-code, ducking an exception does require some effort
on the part of the "middleman" methods. Any checked exceptions that can be thrown within a
method are part of that method's public programming interface and must be specified in the

177
throws clause of the method. Thus a method informs its callers about the exceptions that it can
throw, so that the callers can intelligently and consciously decide what to do about those
exceptions.

Note again the difference in the bloat factor and code obfuscation factor of these two error
management techniques. The code that uses exceptions is more compact and easier to
understand.

Advantage 3: Grouping Error Types and Error Differentiation

Often exceptions fall into categories or groups.

Java exceptions must be instances of Throwable or any Throwable descendant. As for other Java
classes, you can create subclasses of the Throwable class and subclasses of your subclasses.
Each "leaf" class (a class with no subclasses) represents a specific type of exception and each
"node" class (a class with one or more subclasses) represents a group of related exceptions.

ArrayException is a subclass of Exception (a subclass of Throwable) and has three subclasses.

InvalidIndexException, ElementTypeException, and NoSuchElementException are all leaf


classes. Each one represents a specific type of error that can occur when manipulating an array.
One way a method can catch exceptions is to catch only those that are instances of a leaf class.
For example, an exception handler that handles only invalid index exceptions has a catch
statement like this:
catch (InvalidIndexException e) {
. . .
}

ArrayException is a node class and represents any error that can occur when manipulating an
array object, including those errors specifically represented by one of its subclasses. A method
can catch an exception based on its group or general type by specifying any of the exception's
superclasses in the catch statement. For example, to catch all array exceptions regardless of
their specific type, an exception handler would specify an ArrayException argument:
catch (ArrayException e) {
. . .
}

178
This handler would catch all array exceptions including InvalidIndexException,
ElementTypeException, and NoSuchElementException. You can find out precisely which
type of exception occurred by querying the exception handler parameter e. You could even set
up an exception handler that handles any Exception with this handler:
catch (Exception e) {
. . .
}

Exception handlers that are too general, such as the one shown here, can make your code more
error prone by catching and handling exceptions that you didn't anticipate and therefore are not
correctly handled within the handler.

8.2 Types of Exceptions

All exception classes are the subclass of java.lang.Throwable class.

Java has different types of exceptions, including I/O Exceptions, runtime exceptions, and
exceptions of your own creation, to name a few. Runtime exceptions are those exceptions that
occur within the Java runtime system. This includes arithmetic exceptions (such as when
dividing by zero), pointer exceptions (such as trying to access an object through a null
reference), and indexing exceptions (such as attempting to access an array element through an
index that is too large or too small).

Runtime exceptions can occur anywhere in a program and in a typical program can be very
numerous. The cost of checking for runtime exceptions often exceeds the benefit of catching or
specifying them. Thus the compiler does not require that you catch or specify runtime
exceptions, although you can. Checked exceptions are exceptions that are not runtime exceptions
and are checked by the compiler; the compiler checks that these exceptions are caught or
specified.

The Throwable Class and Its Subclasses

Throwable has two direct descendants: Error and Exception.

179
Errors

When a dynamic linking failure or some other "hard" failure in the virtual machine occurs, the
virtual machine throws an Error. Typical Java programs should not catch Errors. In addition,
it's unlikely that typical Java programs will ever throw Errors either.

Exceptions

Most programs throw and catch objects that derive from the Exception class.

The Exception class has many descendants defined in the Java packages. These descendants
indicate various types of exceptions that can occur. For example, IllegalAccessException signals
that a particular method could not be found, and NegativeArraySizeException indicates that a
program attempted to create an array with a negative size.

One Exception subclass is RuntimeException.

Runtime Exceptions

The RuntimeException class represents exceptions that occur within the Java virtual machine
(during runtime). An example of a runtime exception is NullPointerException, which occurs
when a method tries to access a member of an object through a null reference. A
NullPointerException can occur anywhere a program tries to dereference a reference to an
object. The cost of checking for the exception often outweighs the benefit of catching it.

The Java packages define several RuntimeException classes. You can catch these exceptions
just like other exceptions. However, a method is not required to specify that it throws
RuntimeExceptions.

You can create your own RuntimeException subclasses.

Runtime exceptions can occur anywhere in a program and in a typical program can be very
numerous. Typically, the cost of checking for runtime exceptions exceeds the benefit of catching
or specifying them. Thus the compiler does not require that you catch or specify runtime
exceptions, although you can.

What does it cost you if you throw a RuntimeException or create a subclass of


RuntimeException just because you don't want to deal with specifying it? Simply, you get the
ability to throw an exception without specifying that you do so. In other words, it is a way to
avoid documenting the exceptions that a method can throw. When is this good? Well, when is it
ever good to avoid documenting a method's behavior? The answer is "hardly ever."

8.3 Catching and Handling Exceptions

The first step in writing an exception handler is to enclose the statements that might throw an
exception within a try block. The try block is said to govern the statements enclosed within it

180
and defines the scope of any exception handlers (established by subsequent catch blocks)
associated with it.

Next, you associate exception handlers with a try block by providing one or more catch blocks
directly after the try block.

Java's finally block provides a mechanism that allows your method to clean up after itself
regardless of what happens within the try block. Use the finally block to close files or release
other system resources.

The try Block

The first step in constructing an exception handler is to enclose the statements that might throw
an exception within a try block. In general, a try block looks like this:
try {
Java statements
}

The segment of code labelled Java statements is composed of one or more legal Java statements
that could throw an exception.

You could put each statement that might potentially throw an exception within its own try
statement, and provide separate exception handlers for each try. Or you could put all of the
statements within a single try statement and associate multiple handlers with it. The following
listing uses one try statement for the entire method because the code tends to be easier to read.

PrintWriter out = null;

try {
System.out.println("Entering try statement");
out = new PrintWriter(new FileWriter("OutFile.txt"),true);
for (int i = 0; i < size; i++)
out.println("Value at: " + i + " = " + victor.elementAt(i));
}

The try statement governs the statements enclosed within it and defines the scope of any
exception handlers associated with it. In other words, if an exception occurs within the try
statement, that exception is handled by the appropriate exception handler associated with this
try statement.

A try statement must be accompanied by at least one catch block or one finally block.

The catch Block(s)

181
The try statement defines the scope of its associated exception handlers. You associate
exception handlers with a try statement by providing one or more catch blocks directly after
the try block:

try {
. . .
} catch ( . . . ) {
. . .
} catch ( . . . ) {
. . .
} . . .

There can be no intervening code between the end of the try statement and the beginning of the
first catch statement. The general form of Java's catch statement is:
catch (SomeThrowableObject variableName) {
Java statements
}

As you can see, the catch statement requires a single formal argument. The argument to the
catch statement looks like an argument declaration for a method. The argument type,
SomeThrowableObject, declares the type of exception that the handler can handle and must be
the name of a class that inherits from the Throwable class defined in the java.lang package.
When Java programs throw an exception they are really just throwing an object, and only objects
that derive from Throwable can be thrown.

The catch block contains a series of legal Java statements. These statements are executed if and
when the exception handler is invoked. The runtime system invokes the exception handler when
the handler is the first one in the call stack whose type matches that of the exception thrown.

try {
. . .
}
catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Caught ArrayIndexOutOfBoundsException:" +
e.getMessage());
}
catch (IOException e) {
System.err.println("Caught IOException: "+e.getMessage());
}

When you have to write multiple catch blocks and the exception classes in the blocks are related
to each other then take care to write the catch block for the subclass first and then the catch block
for the superclass. If the superclass catch block is written first then the catch block of subclass
becomes unreachable and gives compile-time error.

An example of using multiple catch blocks

class MultiCatch {

182
public static void main (String args[]) {
try {
int a = args.length;
System.out.println("a = " + a);
int b = 42 / a ;
int c[] ={ 1 };
c[42] = 99;
}
catch (ArithmeticException e) {
System.out.println ("Divide by 0:" + e);
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println ("Array Index oob:" + e);
}
System.out.println ("After try/catch blocks.");
}
}

Catching Multiple Exception Types with One Handler

Each handles only one type of exception. The Java language allows you to write general
exception handlers that handle multiple types of exceptions.

Your exception handler can be written to handle any class that inherits from Throwable.

The closest common ancester of IOException and ArrayIndexOutOfBoundsException is the


Exception class. An exception handler that handles both types of exceptions looks like this:

try {
. . .
}
catch (Exception e) {
System.err.println("Exception caught:"+e.getMessage());
}

Handlers that can catch most or all exceptions are typically useless for error recovery because the
handler has to determine what type of exception occurred anyway to determine the best recovery
strategy. Also, exception handlers that are too general can make code more error prone by
catching and handling exceptions that weren't anticipated by the programmer and for which the
handler was not intended.

The finally Block

The final step in setting up an exception handler is providing a mechanism for cleaning up the
state of the method before (possibly) allowing control to be passed to a different part of the
program. You do this by enclosing the cleanup code within a finally block.

The runtime system always executes the statements within the finally block regardless of what
happens within the try block. Regardless of whether control exits the writeList method's try

183
block due to one of the three scenarios listed previously, the code within the finally block will
be executed.

This is the finally block for the writeList method. It cleans up and closes the PrintWriter.

finally {
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
} else {
System.out.println("PrintWriter not open");
}
}

Displaying a description of an exception

Throwable overrides the toString() so that it returns a string containing a description of the
exception. You can display this description in a println() statement by simply passing the
exception as an argument.

You access the instance variables and methods of exceptions in the same manner that you access
the instance variables and methods of other objects. getMessage is a method provided by the
Throwable class that prints additional information about the error that occurred. The Throwable
class also implements two methods for filling in and printing the contents of the execution stack
when the exception occurred.

Accessing Stack Trace Information

Definition:  A stack trace provides information on the execution history of the current thread
and lists the names of the classes and methods that were called at the point when the exception
occurred. A stack trace is a useful debugging tool that you'll normally take advantage of when an
exception has been thrown.

The following code shows how to call the getStackTrace method on the exception object:

catch (Exception cause) {


StackTraceElement elements[] = cause.getStackTrace();
for (int i = 0; n = elements.length; i < n; i++) {
System.err.println(elements[i].getFileName() + ":"
+ elements[i].getLineNumber() + ">> " +
elements[i].getMethodName() + "()");
}
}

Nested try statements

Each time a try statement is entered, the context of that exception is pushed on the stack. If an
inner try statement does not have a catch handler for a particular exception, the stack is unwound

184
and the next try statement’s catch handlers are inspected for a match. This continues until one of
the catch statements succeeds, or until the entire nested try statements are exhausted. If no catch
statement matches, then the Java runtime system will handle the exception.

Nesting of try statements can occur in less obvious ways when method calls are involved. You
can enclose a call to a method within a try block. Inside that method is another try statement. In
this case, the try statement within the method is still nested inside the outer try block, which calls
the method.

//An Example of nested try statements.


class NestTry
{
public static void main (String args[])
{
try
{
int a = args.length;
/* if no command-line args are present
the following statement will generate
a divide-by-zero exception*/
int b = 42 / a;
System.out.println(“a = “ + a);
try //nested try block
{
/* if one command line arg is used ,
then a divide-by-zero exception
will be generated by the following
code*/
if (a == 1)
a = a / (a – a);
// division by zero
 
/* if two command line arg is used ,
then generate an out of bounds exception .*/
if( a = 2 )
{
int c [] = { 1 };
c[ 42 ] = 99;
//generate an out of bound exception
}
}
catch (ArrayIndexOutOfBoundsException e)
{
System.out.println(e);
}
}
catch (ArithmeticException e)
{
System.out.println(“Divide by zero”);
}
}

185
}
 
Sample outputs:
1)
C:\> java NestTry
Divide by zero.

2)
C:\> java NestTry One
a = 1
divide by zero

3)
C:\> java NestTry One Two
a = 2
Array index out of bounds.  

8.4 The throw Statement

All Java methods use the throw statement to throw an exception. The throw statement requires
a single argument: a throwable object. In the Java system, throwable objects are instances of any
subclass of the Throwable class. Here's an example of a throw statement:

throw someThrowableObject;

If you attempt to throw an object that is not throwable, the compiler refuses to compile your
program and displays an error message similar to the following:

testing.java:10: Cannot throw class java.lang.Integer;


it must be a subclass of class java.lang.Throwable.
throw new Integer(4);

public Object pop() throws EmptyStackException {


Object obj;

if (size == 0)
throw new EmptyStackException();

obj = objectAt(size - 1);


setObjectAt(size - 1, null);
size--;
return obj;
}

The EmptyStackException class is defined in the java.util package.

// Demonstrate throw.
class ThrowDemo {
static void demoproc() {

186
try {
throw new NullPointerException("demo");
}
catch(NullPointerException e) {
System.out.println("Caught inside demoproc.");
throw e; // re-throw the exception
}
}
 
public static void main(String args[]) {
try {
demoproc();
}
catch(NullPointerException e) {
System.out.println("Recaught " );
}
}
}
 
The resulting output is

Caught inside demoproc.


Recaught  

One more example using finally.

class FinallyDemo {
// Through an exception out of the method.
static void procA() {
try {
System.out.println("inside procA");
throw new RuntimeException("demo");
}
finally {
System.out.println("procA's finally");
}
}

// Return from within a try block.


static void procB() {
try {
System.out.println("inside procB");
return;
}
finally {
System.out.println("procB's finally");
}
}
 
// Execute a try block normally.
static void procC() {

187
try {
System.out.println("inside procC");
}
finally {
System.out.println("procC's finally");
}
}
 
public static void main(String args[]) {
try {
procA();
}
catch (Exception e) {
System.out.println("Exception caught");
}
procB();
procC();
}
}
   
The resulting Output is:

inside procA
procA's finally
Exception caught
inside procB
procB's finally
inside procC
procC's finally

8.5 The throws Clause

The declaration of the pop method contains this clause:

throws EmptyStackException

The throws clause specifies that the method can throw an EmptyStackException.

Java requires that a method either catch or specify all checked exceptions that can be thrown
within the scope of the method.

A method can catch an exception by providing an exception handler i.e. using a try..catch block
for that type of exception.

If a method chooses not to catch an exception, the method must specify that it can throw that
exception. The throws clause specifies that if an exception occurs it is not explicitly handled.

Specifying the Exceptions Thrown by a Method

188
public void writeList() {
PrintWriter out =
new PrintWriter(new FileWriter("OutFile.txt"), true);
for (int i = 0; i < size; i++)
out.println("Value at: " + i + " = " + victor.elementAt(i));
}

The throws clause is composed of the throws keyword followed by a comma-separated list of all
the exceptions thrown by that method. The throws clause goes after the method name and
argument list and before the curly bracket that defines the scope of the method. Here's an
example:

public void writeList() throws IOException,


ArrayIndexOutOfBoundsException {

Remember that ArrayIndexOutofBoundsException is a runtime exception, so you don't have


to specify it in the throws clause, although you can.

class ThrowsDemo {
static void throwOne() throws IllegalAccessException {
System.out.println("Inside throwOne.");
throw new IllegalAccessException("demo");
}
public static void main(String args[]) {
try {
throwOne();
}
catch (IllegalAccessException e) {
System.out.println("Caught “);
}
}
}
 
The resulting Output is

Inside throwOne.
Caught

8.6 Overriding methods that throw exceptions

An overriding method in a subclass may only throw exceptions declared in the parent class or
children of the exceptions declared in the parent class. This is only true for overriding methods
not overloading methods. Thus if a method has exactly the same name and arguments it can only
throw exceptions declared in the parent class, or exceptions that are children of exceptions in the
parent declaration. It can however throw fewer or no exceptions. Thus the following example
will not compile

import java.io.*;

189
class Base{
public static void amethod()throws FileNotFoundException{}
}

public class ExcepDemo extends Base{


//Will not compile, exception not in base version of method
public static void amethod()throws IOException{}
}

If it were the method in the parent class that was throwing IOException and the method in the
child class that was throwing FileNotFoundException this code would compile. Again,
remember that this only applies to overridden methods, there are no similar rules to overloaded
methods. Also an overridden method in a sub class may throw Exceptions.

8.7 Java’s built in exceptions

Inside the standard package java.lang, Java defines several exception classes. The most general
of these are subclasses of RuntimeException. Since, java.lang is implicitly imported to all Java
programs, most exceptions derived from RuntimeException are automatically available. They
need not be included in any method’s throws list. They are called unchecked exceptions because
the compiler does not check to see if a method handles, or throws these exceptions. Checked
exceptions are those defined by java.lang that must be included in a method’s throws list if that
method can generate one of these exceptions and does not handle it itself.

RuntimeException subclasses (unchecked):

 ArithmeticException
 ArrayIndexOutOfBoundsException
 ArrayStoreException
 ClassCastException
 IllegalArgumentException
 IllegalMonitorStateException
 IllegalStateException
 IllegalThreadStateException
 IndexOutOfBoundsException
 NegativeArraySizeException
 NullPointerException
 NumberFormatException
 SecurityException
 StringIndexOutOfBoundsException
 UnsupportedOperationException

Checked Exceptions defined in java.lang

 ClassNotFoundException

190
 CloneNotSupportedException
 IllegalAccessException
 InstantiationException
 InterruptedException
 NoSuchfieldException
 NoSuchMethodException

ArithmeticException

Attempting to divide an integer by zero or take a modulus by zero throw the


ArithmeticException--no other arithmetic operation in Java throws an exception.

For example, the following code causes an ArithmeticException to be thrown:

class Arith {
public static void main(String args[]) {
int j = 0;
j = j / j;
}
}

NullPointerException

An attempt to access a variable or method in a null object or a element in a null array throws a
NullPointerException. For example, the accesses o.length and a[0] in the following class
declaration throws a NullPointerException at runtime.

class Null {
public static void main(String args[]) {
String o = null;
int a[] = null;
o.length();
a[0] = 0;
}
}

It is interesting to note that if you throw a null object you actually throw a NullPointerException.

IncompatibleClassChangeException

In general the IncompatibleClassChangeException is thrown whenever one class's definition


changes but other classes that reference the first class aren't recompiled. Four specific changes
that throw a IncompatibleClassChangeException at runtime are:
 A variable's declaration is changed from static to non-static in one class but other classes
that access the changed variable aren't recompiled.
 A variable's declaration is changed from non-static to static in one class but other classes
that access the changed variable aren't recompiled.

191
 A field that is declared in one class is deleted but other classes that access the field aren't
recompiled.
 A method that is declared in one class is deleted but other classes that access the method
aren't recompiled.

ClassCastException

A ClassCastException is thrown if an attempt is made to cast an object O into a class C and O is


neither C nor a subclass of C.

The following class declaration results in a ClassCastException at runtime:

class ClassCast {
public static void main(String args[]) {
Object o = new Object();
String s = (String)o; // the cast attempt
s.length();
}
}

NegativeArraySizeException

A NegativeArraySizeException is thrown if an array is created with a negative size. For


example, the following class definition throws a NegativeArraySizeException at runtime:

class NegArray {
public static void main(String args[]) {
int a[] = new int[-1];
a[0] = 0;
}
}

OutOfMemoryException

An OutOfMemoryException is thrown when the system can no longer suppy the application with
memory. The OutOfMemoryException can only occur during the creation of an object, i.e., when
new is called. For example, the following code results in an OutOfMemoryException at runtime:

class Link {
int a[] = new int[1000000];
Link l;
}
class OutOfMem {
public static void main(String args[]) {
Link root = new Link();
Link cur = root;
while(true) {
cur.l = new Link();
cur = cur.l;

192
}
}
}

NoClassDefFoundException

A NoClassDefFoundException is thrown if a class is referenced but the runtime system cannot


find the referenced class.

For example, class NoClass is declared:

class NoClass {
public static void main(String args[]) {
C c = new C();
}
}

When NoClass is run, if the runtime system can't find C.class it throws the
NoClassDefFoundException.

C class must have existed at the time NoClass is compiled.

IncompatibleTypeException

An IncompatibleTypeException is thrown if an attempt is made to instantiate an interface. For


example, the following code causes an IncompatibleTypeException to be thrown.

interface I {
}

class IncompType {
public static void main(String args[]) {
I r = (I)new("I");
}
}

ArrayIndexOutOfBoundsException

An attempt to access an invalid element in an array throws an


ArrayIndexOutOfBoundsException. For example:

class ArrayOut {
public static void main(String args[]) {
int a[] = new int[0];
a[0] = 0;
}
}

193
UnsatisfiedLinkException

An UnsatisfiedLinkException is thrown if a method is declared native and the method cannot be


linked to a routine in the runtime.

class NoLink {
static native void foo();

public static void main(String args[]) {


foo();
}
}

8.8 Chained Exceptions

Chained exceptions allow you to rethrow an exception, providing additional information without
losing the original cause of the exception. The chained exception API was introduced in 1.4 by
adding a cause property of type Throwable to exceptions. Two methods and two constructors
were added to Throwable, the class from which all exceptions inherit. Since every Throwable
can have a cause, each exception can have a cause, which itself can have a cause, and so on.

The methods and constructors in Throwable that support chained exceptions are:

Throwable getCause()
Throwable initCause(Throwable)
Throwable(String, Throwable)
Throwable(Throwable)

The Throwable argument to initCause and the Throwable constructors is the exception that
caused the current exception. getCause returns the exception that caused the current exception,
and initCause returns the current exception.

The following example shows how to use a chained exception:

try {
...
}
catch (IOException e) {
throw new SampleException("Other IOException", e);
}

In this example, when an IOException is caught, a new SampleException exception is created


with the original cause attached and the chain of exceptions is thrown up to the next higher level
exception handler.

What is a cause?

194
A cause is a reference to another Throwable object.  The intent is that this object will be
interpreted as the thing that caused this throwable to get thrown in the first place.

However, you could encapsulate any Throwable object in a new Throwable object, whether or
not it had anything to do with the true cause.  All that you are required to do is pass a Throwable
object's reference to the constructor for a new Throwable object, or invoke the initCause method
on an existing Throwable object, passing a reference to another Throwable object as a
parameter.  It then becomes a cause.

Two ways to encapsulate a cause

As suggested above, you can associate a cause with a Throwable in two different ways.  One
way is to invoke one of the constructors that accepts a Throwable as a parameter.  This assumes,
of course, that the class from which you are instantiating the new object has such a constructor. 

The other way to associate a cause with a Throwable is to invoke the initCause method on an
existing Throwable object's reference, passing a reference to another Throwable object as a
parameter.  This works even when you are instantiating a new object from a class that doesn't
have a constructor that accepts a parameter of type Throwable.

import java.io.*;

class Excep20{
public static void main(String[] args){
    try{
      new Class01().meth01();
    }
catch(NewEx01 e){
      System.out.println("In main catch block");
      System.out.println("Msg is:\n" + e.getMessage());
      System.out.println("Cause is:\n" + e.getCause());
      System.out.println();//blank line
      System.out.println("Print StackTrace");
      e.printStackTrace();
    }//end catch
  }//end main
}//end Excep20

//This is a new exception class


class NewEx01 extends Exception{
public NewEx01() {

  }
 
public NewEx01(String message){
    super(message);
  }

  public NewEx01(Throwable throwable){

195
    super(throwable);
  }

  public NewEx01(String message,Throwable throwable){


    super(message, throwable);
  }
}//end NewEx01

//This is a new exception class


class NewEx02 extends Exception{
public NewEx02() {
 
}

  public NewEx02(String message){


    super(message);
  }
 
public NewEx02(Throwable throwable){
    super(throwable);
  }

  public NewEx02(String message,Throwable throwable){


    super(message, throwable);
  }
}//end NewEx02

class Class01{
void meth01() throws NewEx01{
    try{
      meth02();
    }
catch(NewEx02 e){
      System.out.println("In meth01 catch block");
      System.out.println("Msg is:\n" + e.getMessage());
      System.out.println("Cause is:\n" + e.getCause());
      System.out.println();//blank line
      throw new NewEx01("Msg from meth01",e);
    }//end catch
  }//end meth01
  
  void meth02() throws NewEx02{
    try{
      meth03();
    }
catch(RuntimeException e){
      System.out.println("In meth02 catch block");
      System.out.println("Msg is:\n" + e.getMessage());
      System.out.println("Cause is:\n" + e.getCause());
      System.out.println();
      throw new NewEx02("Msg from meth02",e);
    }//end catch

196
  }//end meth02
  
  void meth03(){
    try{
      int x = 3/0;
    }
catch(ArithmeticException e){
IndexOutOfBoundsException ex = 
new IndexOutOfBoundsException("Msg from metho03");
ex.initCause(e);
     throw ex;
}//end catch
  }//end meth03
}//end Class01

8.9 Creating Your Own Exception Classes

Choosing the Exception Type to Throw

When faced with choosing the type of exception to throw, you have two choices:
1. Use one written by someone else. The Java development environment provides a lot of
exception classes that you could use.
2. Write one of your own.

You should go to the trouble of writing your own exception classes if you answer "yes" to any of
the following questions. Otherwise, you can probably get away with using someone else's:
 Do you need an exception type that isn't represented by those in the Java development
environment?
 Would it help your users if they could differentiate your exceptions from those thrown by
classes written by other vendors?
 Does your code throw more than one related exception?

If you use someone else's exceptions, will your users have access to those exceptions? A similar
question is: Should your package be independent and self-contained?

Example

public class DivideByZeroException extends Exception


{
public DivideByZeroException()
{
super("Dividing by Zero!");
}
public DivideByZeroException(String message)
{
super(message);
}
}

197
public class DivisionExample {
public static void main(String args[]) {
try {
int x = Integer.parseInt(args[0]);
int y = Integer.parseInt(args[1]);
if(y == 0) {
throw new DivideByZeroException();
}
else {
System.out.println(x/y);
}
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println(e);
}
catch(DivideByZeroException e) {
System.out.println(e);
}
}
}

Choosing a Superclass

However, the java.lang package provides two Throwable subclasses that further divide the
type of problems that can occur within a Java program: Errors and Exceptions. Most of the
applets and applications that you write will throw objects that are Exceptions. (Errors are
reserved for serious hard errors that occur deep in the system.)

Runtime exceptions don't have to be specified in the throws clause of a method. The bottom
line is that you shouldn't subclass RuntimeException unless your class really is a runtime
exception!

Naming Conventions

It's good practice to append the word "Exception" to the end of all classes that inherit (directly or
indirectly) from the Exception class. Similarly, classes that inherit from the Error class should
end with the string "Error".

8.10 Assertions

Assertions were added to Java with the release of JDK1.4. Assertions are a feature of other
Object Orientated languages and there has been pressure for a while for them to be added to
Java.

Why Assertions exist?

Assertions are a fairly simple concept where you write a statement that should always be true,
but in a form that can be removed from the finally compiled version of the code so they cause no

198
runtime overhead. It would be perfectly possible to write code using the constructs available in
Java prior to JDK1.4 that simulates the functionality of assertions but it would be hard to do so in
such a way that they would be turned off at runtime.

How assertions are used?

Where and how you use assertions is a matter of judgment in a similar way to where and how
you use comments.

Assertions can be considered an extension of comments in that comments are often used to tell a
person reading the code that a particular statement or piece of code should always be true. With
assertions, instead of indicating by a comment that a statement should always be true you can
assert that it should always be true.

If you then run the code with assertions enables you do not have to rely on a close reading of the
code as you would with comments but the running of the code itself will check your assertions
are true, and if they are not an assert error will be thrown.

By default, assert statements are disabled during normal program run.

As the name implies assertions are used to assert something that should always be true. When a
program is running normally assertions are disabled and cause no performance overhead. When a
programmer is investigating an issue assertions can be enabled and if any of the assert statements
are not true an assert exception will be thrown. Assertions are a key part of JDK 1.4 and require
no additional import statements in the source code. However because programmers in the past
have used the word assert in creating their own versions of assertions the compilation process
requires a command line parameter to tell it that it will be using the genuine JDK 1.4 version of
assertions. This takes the form

javac -source1.4 Myprog.java

If you then run the program normally in the form

java Myprog

assertions are disabled and no assert exceptions will be thrown. If you subsequently have an
issue you want to investigate and confirm that all of the assertions of items that should always be
true, really are true you can run the program with assertions enabled as follows.

java -enableassertions Myprog

or

java –ea Myprog

What should you assert to be true?

199
Assertions should be used for anything you believe should always be true. For example it should
always be true that a person has an age greater than zero. If a person has an age less than zero
your program or its input has a significant problem. For another example if you were recording
the date of a persons death you program (or your morality) might have a problem if you had the
date of death in the future, therefore you could assert that the date of death is in the future.

For example if you are falling through a case statement or a set of if/else statements you might
believe that the code should always exit before it reaches the final test. Imagine if you had an
application dealing with media types. Your application might be expecting to deal with jpg, mpg,
avi or gif files. You set up a case statement that branch according to the type of file. Because you
believe that the type will always be one of those file types there is definitely a problem if you get
to the end of the case statement without branching and you can place an assert statement at the
location of the default option.

Where should you use assertions?

Assertions should not be used to enforce the public interface of a program. One of the most
public interfaces of a program is its command line parameters. Thus traditionally a programmer
will inspect the command line passed to a Java program by looking at the value in the String args
array passed from the command line. Typically if this array does not contain the expected type of
values the program will exit and print a message indicating what the correct format of the
command line should be. The introduction of the assert mechanism does not change this. It is not
appropriate to use assert to check the command line parameters of a program because assertions
will not always be enabled.

It is not appropriate to use assertions to check the parameters passed to public methods. Because
your public methods may be used in programs written by other people you cannot be certain that
they will have assertions enabled and thus the normal running of the program may be faulty.
However it is appropriate to use assertions for checking the parameters to private methods as
these will generally only be called by code written by people who have access to the source of
those methods. The same assumption may be made for code in protected or in package protected
methods.

Assert syntax

The assert statement has two formats

The simple
assert somebooleatest

and
assert somebooleantest : someinformatinvemethod

200
In the first simpler version the assert tests that something is true and if it is not an
AssertionError is thrown. For example if you were testing that a persons age was greater
than zero you might create an assert in the form

assert (iAge > 0);

The more complex version might be of the form

assert (iAge > 0) :"age must be greater than zero";

This example is simple in that the right hand side of the expression is a simple string, but this
could be any method call that returns a value, i.e. a method with any return type except void.

public class Foo


{
  public void m1( int value )
  {
    assert 0 <= value;
    System.out.println( "OK" );
  }

  public static void main( String[] args )


  {
    Foo foo = new Foo();
    System.out.print( "foo.m1(  1 ): " );
    foo.m1( 1 );
    System.out.print( "foo.m1( -1 ): " );
    foo.m1( -1 );
  }
}

If the assertions are disabled the output is

foo.m1(1) : OK
foo.m1( -1) : OK

If the assertions are enabled the output is

foo.m1(1) : OK
foo.m1( -1)
(Runtime Exception – AssertionError)

Summary

An exception is an abnormal condition arised during the program execution that disrupts the
normal flow of program and terminates the application. There are built-in api exception classes
in java.lang. You can also define your own exception class. All exception classes are subclasses
of Throwable class. There are two types of exception types: checked and runtime exceptions.

201
Questions

1. class A {A() throws Exception {}} // 1


class B extends A {B() throws Exception {}} // 2
class C extends A {} // 3

Which of the following statements is true?

a.  Compile-time error at 1. c.  Compile-time error at 3.


b.  Compile-time error at 2. d.  None of the above

2. class A {
public static void main (String[] args) {
Error error = new Error();
Exception exception = new Exception();
System.out.print((exception instanceof Throwable) + ",");
System.out.print(error instanceof Throwable);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: false,false d.  Prints: true,true g.  None of the above
b.  Prints: false,true e.  Compile-time error
c.  Prints: true,false f.  Run-time error

3. class Level1Exception extends Exception {}


class Level2Exception extends Level1Exception {}
class Level3Exception extends Level2Exception {}
class Purple {
public static void main(String args[]) {
int a,b,c,d,f,g,x;
a = b = c = d = f = g = 0;
x = 1;
try {
try {
switch (x) {
case 1: throw new Level1Exception();
case 2: throw new Level2Exception();
case 3: throw new Level3Exception();
}
a++;
}
catch (Level2Exception e) {b++;}
finally {c++;}
}
catch (Level1Exception e) { d++;}

202
catch (Exception e) {f++;}
finally {g++;}
System.out.print(a+","+b+","+c+","+d+","+f+","+g);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 0,0,0,1,0,0 d.  Prints: 1,0,1,1,0,1 g.  Run-time error


b.  Prints: 0,0,1,1,0,1 e.  Prints: 1,1,1,1,0,1 h.  None of the above
c.  Prints: 0,1,1,1,0,1 f.  Compile-time error
4. class A {
void m1(int i) {
int j = i % 3;
switch (j) {
case 0: System.out.print("0"); break;
case 1: System.out.print("1"); break;
default:
assert j == 2;
System.out.print(j);
}
}
public static void main (String[] args) {
A a = new A();
for (int i=5; i >= -1; i--) {a.m1(i);}
}
}

Which statements are true?

a.  With assertions enabled it prints 210210-1 followed by an AssertionError message.


b.  With assertions enabled it prints 210210 followed by an AssertionError message.
c.  With assertions enabled it prints only 210210.
d.  With assertions enabled it prints nothing.
e.  With assertions disabled it prints 210210-1
f.  With assertions disabled it prints only 210210
g.  Assertions should not be used within the default case of a switch statement.

203
Chapter 9 : Multithreaded programming
9.1 Multitasking

Multitasking is performing two or more tasks at the same time. Nearly all operating systems are
capable of multitasking by using one of two multitasking techniques: process-based multitasking
and thread-based multitasking.

Process-based multitasking is running two programs concurrently. Programmers refer to a


program as a process. Therefore, you could say that process-based multitasking is program-based
multitasking.

Thread-based multitasking is having a program perform two tasks at the same time. For example,
a word processing program can check the spelling of words in a document while you write the
document. This is thread-based multitasking.

A good way to remember the difference between process-based multitasking and thread-based
multitasking is to think of process-based as working with multiple programs and thread-based as
working with parts of one program.

The objective of multitasking is to utilize the idle time of the CPU. Think of the CPU as the
engine of your car. Your engine keeps running regardless of whether the car is moving. Your
objective is to keep your car moving as much as possible so you can get the most miles from a
gallon of gas. An idling engine wastes gas.

The same concept applies to the CPU in your computer. You want your CPU cycles to be
processing instructions and data rather than waiting for something to process. A CPU cycle is
somewhat similar to your engine running.

Process-based multitasking has a larger overhead than thread-based multitasking. In process-


based multitasking, each process requires its own address space in memory. The operating
system requires a significant amount of CPU time to switch from one process to another process.
Programmers call this context switching, where each process (program) is a context. Additional
resources are needed for each process to communicate with each other.

In comparison, the threads in thread-based multitasking share the same address space in memory
because they share the same program. This also has an impact on context switching, because
switching from one part of the program to another happens within the same address space in
memory. Likewise, communication among parts of the program happens within the same
memory location.

9.2 What Is a Thread?

204
All programmers are familiar with writing sequential programs. You've probably written a
program that displays "Hello World!". This is a sequential program. That is, each has a
beginning, an execution sequence, and an end. At any given time during the runtime of the
program, there is a single point of execution.

A single thread also has a beginning, a sequence, and an end and at any given time during the
runtime of the thread, there is a single point of execution. However, a thread itself is not a
program; it cannot run on its own. Rather, it runs within a program. The following figure shows
this relationship.

Definition: A thread is a single sequential flow of control within a program.

A thread is part of a program that is running. Thread-based multitasking has multiple threads
running at the same time (that is, multiple parts of a program running concurrently). Each thread
is a different path of execution. This is illustrated by the following figure:

The Java run-time environment manages threads, unlike in process-based multitasking where the
operating system manages switching between programs. Threads are processed asynchronously.
This means that one thread can pause while other threads continue to process.

The HotJava Web browser is an example of a multithreaded application. Within the HotJava
browser you can scroll a page while it's downloading an applet or image, play animation and
sound concurrently, print a page in the background while you download a new page, or watch
three sorting algorithms race to the finish. You are used to life operating in a concurrent
fashion...so why not your browser?

Some texts use the name lightweight process instead of thread. A thread is similar to a real
process in that a thread and a running program are both a single sequential flow of control.
However, a thread is considered lightweight because it runs within the context of a full-blown
program and takes advantage of the resources allocated for that program and the program's
environment.

205
As a sequential flow of control, a thread must carve out some of its own resources within a
running program. (It must have its own execution stack and program counter for example.) The
code running within the thread works only within that context. Thus, some other texts use
execution context as a synonym for thread.

Basic support for threads in the Java platform is in the class java.lang.Thread. It provides a
thread API and provides all the generic behavior for threads. (The actual implementation of
concurrent operations is system-specific. For most programming needs, the underlying
implementation doesn’t matter.) These behaviors include starting, sleeping, running, yielding,
and having a priority.

To implement a thread using the Thread class, you need to provide it with a run method that
performs the thread's task.

There are two ways to provide the run method.

 Subclass the Thread class and override the run method.


 Provide a class that implements the Runnable interface and therefore implements the run
method. In this case, a Runnable object provides the run method to the thread.

Daemon threads

A daemon thread is a thread that runs continuously to perform a service, without having any
connection with the overall state of the program. For example, the thread that runs the garbage
collector in Java is a daemon thread. The thread that processes mouse events for a Java program
is also a daemon thread. In general, threads that run application code are not daemon threads, and
threads that run system code are daemon threads. If a thread dies and there are no other threads
except daemon threads alive, the Java virtual machine stops.

A Thread object has a boolean attribute that specifies whether or not a thread is a daemon
thread. The daemon attribute of a thread is set when the Thread object is created, by passing an
argument to the constructor that creates the Thread object. If the daemon attribute is not
explicitly specified, the Thread inherits the daemon attribute of its parent Thread object.

The daemon attribute is queried using the isDaemon() method; it is set using the setDaemon()
method.

Controlling groups of threads

Sometimes it is necessary to control multiple threads at the same time. Java provides the
ThreadGroup class for this purpose. Every Thread object belongs to a ThreadGroup object. By
passing an argument to the constructor that creates the Thread object, the ThreadGroup of a
thread can be set when the Thread object is created. If an explicit ThreadGroup is not specified,
the Thread belongs to the same ThreadGroup as its parent Thread object.

206
9.3 The Thread class

The class java.lang.Thread is used to create and control threads. To create a thread, a new
instance of this class must be created. However, the thread does not start running right away.
Thread.start() must be called to actually make the thread run. When Thread.start() is called, the
thread begins executing in the run() method of the target class. A new Thread class always starts
running the public void run() method of a class.

The Thread class has seven constructors. All of them create a new thread. The thread does not
start running until Thread.start() is called. When Thread.start() is called, the new thread
starts running in the run() method of an object. The constructors are the following:

Thread()
Thread(Runnable)
Thread(ThreadGroup)
Thread(String)
Thread(ThreadGroup,String)
Thread(Runnable,String)
Thread(ThreadGroup,Runnable,String)

The constructors can use three possible parameters:

 String  The name of the new thread is the parameter String. A thread can get its name
by calling Thread.getName().
 ThreadGroup  The new thread will belong to the group specified by the parameter
ThreadGroup. A ThreadGroup can be used to organize a thread.
 Runnable  The Runnable parameter is an object that has implemented the Runnable
interface. The thread will start executing in the run() method of the Runnable parameter
when Thread.start() has been called.

There are many methods in the Thread class.

Some of the methods that control the thread execution are the following:

 start()  This method starts the thread. It starts executing in the run() method of its
Runnable target that was set when the constructor was called. This method can be called
only once.
 suspend()  This method suspends the execution of the thread. It remains suspended until
resume() is called.
 resume()  This method resumes the execution of a suspended thread. It has no effect on
a thread that is not suspended.
 stop()  This method stops and kills a running thread. Currently, the thread does not stop
unless it is running. If it is suspended, it does not die until it starts running again. This is a
deprecated method.
 sleep(int m)/sleep(int m,int n)  The thread sleeps for m milliseconds, plus n
nanoseconds.

207
9.4 Using the main thread

When a Java program starts up, one thread begins running immediately. This is usually called the
main thread of your program, because it is the one that is executed when your program begins.
The main thread is important because :

 It is the thread from which other “child” threads will be spawned.


 Often it must be the last thread to finish execution because it performs various shutdown
actions.

Although the main thread is created automatically when your program is started, it can be
controlled through a Thread object. To do so you must obtain the reference to it by calling the
method currentThread(), which is a public static member of Thread. Its general form is shown
below:

static Thread currentThread()

This method returns a reference to the thread in which it is called. Once, you have a reference to
the main thread, you can control it just like any other thread.

Example,

//controlling the main thread


class CurrentThreadDemo {
public static void main(String args[]) {
Thread t = Thread.currentThread();
System.out.println(“Current thread :“+ t);
// change the name of the thread
t.setName(“My thread”);
System.out.println(“After name change :” +t);
try {
for(int n = 5; n > 0; n -- ) {
System.out.println(n);
Thread.sleep(1000);
}
}
catch(InterruptedException e) {
System.out.println(“Main thread interrupted”);
}
}
}

The output of the program is as follows :

Current thread : Thread[main,5,main]


After name change : Thread[My Thread, 5,main]
5
4
3

208
2
1

When you try to print t, it displays the name of the thread, its priority and the name of its group.
By default, the name of the main thread is main. Its priority is 5, which is the default value, and
main is also the name of the group of threads to which this thread belongs. A thread group is a
data structure that controls the state of a collection of threads as a whole. This process is
managed by particular runtime environment.

The sleep method causes the thread from which it is called to suspend execution for the specific
period of milliseconds. Its general form is

static void sleep(long milliseconds) throws InterruptedException


static void sleep(long milliseconds, int nanoseconds) throws InterruptedException

You can set the name of the thread by using setName(). You can obtain the name of the thread
by calling getName(). The syntax is given below:

final void setName(String threadName)


final String getName()

9.5 Creating a thread

Subclassing Thread and Overriding run

The first way to customize a thread is to subclass Thread (itself a Runnable object) and override
its empty run method so that it does something. Let's look at the SimpleThread class, the first of
two classes in this example, which does just that:

public class SimpleThread extends Thread {


public SimpleThread(String str) {
super(str);
}

public void run() {


for (int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
sleep((long)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}

The first method in the SimpleThread class is a constructor that takes a String as its only
argument. This constructor is implemented by calling a superclass constructor and is interesting
to us only because it sets the Thread's name, which is used later in the program.

209
The next method in the SimpleThread class is the run method. The run method is the heart of any
Thread and where the action of the Thread takes place. The run method of the SimpleThread
class contains a for loop that iterates ten times. In each iteration the method displays the iteration
number and the name of the Thread, then sleeps for a random interval of up to 1 second. After
the loop has finished, the run method prints DONE! along with the name of the thread. That's it
for the SimpleThread class. Let’s put it to use in TwoThreadsTest.

The TwoThreadsTest class provides a main method that creates two SimpleThread threads:
Jamaica and Fiji.

public class TwoThreadsTest {


public static void main (String[] args) {
new SimpleThread("Jamaica").start();
new SimpleThread("Fiji").start();
}
}

The main method starts each thread immediately following its construction by calling the start
method, which in turn calls the run method. Compile and run the program. You should see
output similar to this:

Note how the output from each thread is intermingled with the output from the other. The reason
is that both SimpleThread threads are running concurrently. So both run methods are running,
and both threads are displaying their output at the same time. When the loop completes, the
thread stops running and dies.

Implementing Runnable interface

210
The Runnable interface is a built-in interface in java.lang package and has only one method in it
– that is

public void run()

When you are implementing the Runnable interface you have to override the run method

//Implementing Runnable
public class ThreadedClass implements Runnable
{
    int data;

    public ThreadedClass(){


        data = 0;
    }
    public void run(){
        //this method runs when start() is invoked on the thread
        System.out.println( ++data );
    }

    public Thread getNewThread(){


        Thread t = new Thread( this );
        return t;
    }

    public static void main( String[] args ){


        ThreadedClass threadedClass = new ThreadedClass();
        Thread t1 = threadedClass.getNewThread();
        t1.start();
        Thread t2 = threadedClass.getNewThread();
        t2.start();
    }
}

In the main() method of the code above, only one instance of ThreadedClass is created. This
one instance is used to spawn a multitude of threads (each executing the run() method of the
same object).

9.6 The Java Thread Model

Java uses threads to enable the entire environment to be asynchronous. This helps reduce
inefficiency by preventing the waste of CPU cycles.

Single-threaded systems use an approach called an event loop, with polling. In this model, a
single thread of control runs in an infinite loop, polling a single event queue to decide what to do
next. Once this polling mechanism returns with, say, a signal that a network file is ready to be
read, then the event loop dispatches the control to the appropriate event handler. Until this event
handler returns, nothing else can happen in the system. This wastes CPU time. It can also result

211
in one program dominating the system and preventing any other events from being processed. In
single-threaded environment, when a thread blocks because it is waiting for some resource, the
entire program stops running.

The benefit of Java’s multithreading is that the main loop/polling mechanism is eliminated. One
thread can pause without stopping other parts of your program.

The states of a Thread

A thread can be in one of these states:


 Running   A thread is said to be in running state when it is being executed. This thread
has access to CPU.
 Suspended   Execution is paused and can be resumed where it left off.
 Resumed. A suspended thread is started.
 Blocked   A resource cannot be accessed because it is being used by another thread.
 Terminated or Dead State A thread reaches "dead" state when the run method has
finished execution. This thread cannot be executed now.
 Ready State A thread in this state is ready for execution, but is not being currently
executed. Once a thread in the ready state gets access to the CPU, it gets converted to
running state.

A thread can enter the waiting state by invoking its sleep() method, by blocking on I/O, by
unsuccessfully attempting to acquire an object’s lock, or by invoking an object’s wait() method.
It can also enter the waiting state by invoking its (deprecated) suspend() method.

A CPU intensive operation being executed may not allow other threads to be executed for a
"large" period of time. To prevent this it can allow other threads to execute by invoking the
yield() method. The thread on which yield() is invoked would move from running state to ready
state.

The Life cycle of a thread


The following figure shows the states that a thread can be in during its life and illustrates which
method calls cause a transition to another state. A simple diagram is shown below:

A more detailed diagram follows:

212
Testing Thread State

Release 5.0 introduced the Thread.getState method. When called on a thread, one of the
following Thread.State values is returned:
 NEW
 RUNNABLE
 BLOCKED
 WAITING
 TIMED_WAITING
 TERMINATED

The API for the Thread class also includes a method called isAlive. The isAlive method returns
true if the thread has been started and not stopped. If the isAlive method returns false, you know
that the thread either is a New Thread or is Dead. If the isAlive method returns true, you know
that the thread is either Runnable or Not Runnable.

Prior to release 5.0, you couldn't differentiate between a New Thread or a Dead thread. Nor
could you differentiate between a Runnable thread and a Not Runnable thread.

9.7 Thread priority

A thread's priority is specified with an integer from 1 (the lowest) to 10 (the highest), Constants
Thread.MIN_PRIORITY and Thread.MAX_PRIORITY can also be used. By default, the
setPriority() method sets the thread priority to 5, which is the Thread.NORM_PRIORITY.

Thread aThread = Thread.currentThread();


int currentPriority;
currentPriority = aThread.getPriority();
aThread.setPriority( currentPriority + 1 );

213
Setting priorities may not always have the desired effect because prioritization schemes may be
implemented differently on different platforms. However, if you cannot resist messing with
priorities, use higher priorities for threads that frequently block (sleeping or waiting for I/O). Use
medium to low-priority for CPU-intensive threads to avoid hogging the processor down.

class Clicker implements Runnable {


int click = 0;
Thread t;
private volatile boolean running = true;

public Clicker(int p) {
t = new Thread(this);
t.setPriority(p);
}

public void run () {


while (running) {
click++;
}
}

public void stop() {


running = false;
}

public void start () {


t.start();
}
}

class HiLoPri {
public static void main (String args [ ]) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Clicker hi = new Clicker (Thread.NORM_PRIORITY + 2);
Clicker lo = new Clicker (Thread.NORM_PRIORITY - 2);
lo.start();
hi.start();
try {
Thread.sleep(10000);
}
catch (InterruptedException e) {
System.out.println("Main Thread Interrupted");
}
lo.stop();
hi.stop();
try {
hi.t.join();
lo.t.join();
}
catch (InterruptedException e) {

214
System.out.println("InterruptedException Caught");
}
System.out.println("Low-Priority Thread:" + lo.click);
System.out.println("High-Priority Thread:" + hi.click);
}
 }

The output of this program, shown as follows when run under Windows 2000, indicates that the
threads did context switch even though neither voluntarily yielded the CPU nor blocked for I/O.
The higher priority thread got approx. 90% of the CPU time.

Low-Priority Thread:4408112
High-Priority Thread:589626904

The output depends on the speed of your CPU and the number of other tasks running in the
system.

Volatile ensures that the value of running is examined each time the following loop iterates:

while(running) {
click++;
}

9.8 Using the Thread yield method.

Because of the platform dependent nature of Java threading you cannot be certain if a thread will
ever give up its use of CPU resources to other threads. On some operating systems the threading
algorithm may automatically give different threads a share of the CPU time, on others one thread
might simply hog processor resources. For this reason the Java Thread class has a static method
called yield, which causes the currently running thread to yield its hold on CPU cycles. This
thread returns to the "ready to run" state and the thread scheduling system has a chance to give
other threads the attention of the CPU. If no other threads are in a "ready to run state" the thread
that was executing may restart running again.

Example of using yield() method

public class TestRunner implements Runnable


 {
   public void run()
   {
    System.out.println(Thread.currentThread().getName() +
" In run");
    Thread.yield();
    System.out.println(Thread.currentThread().getName() +
" Leaving run");
   }
 }
 
 public class TestYield

215
 {
  public static void main (String[] args)
  {
   TestRunner r1 = new TestRunner();
   Thread t2 = new Thread(r1);
   t2.setName("BlahBlah");
   Thread t1 = new Thread(r1);
   t1.setName("TestThreadHaah");
   t1.start();
   t2.start();
  }  
 }

9.9 Stopping a Thread

suspend() and stop() methods of Thread provide asynchronous methods of stopping a thread.
However, these methods have been deprecated because they are very unsafe. Using them often
results in deadlocks and incorrect resource cleanup.

Instead of using stop, a thread should arrange for its own death by having a run method that
terminates naturally. For example, the while loop in this run method is a finite loop: It will iterate
100 times and then exit:

public void run() {


int i = 0;
while (i < 100) {
i++;
System.out.println("i = " + i);
}
}

A thread with this run method dies naturally when the loop completes and the run method exits.

If you don’t want to use the deprecated method you can set a variable that the thread checks
occasionally. When the thread detects that the variable is set, it should return from the run()
method.

class MyThread extends Thread {


boolean allDone = false;

// This method is called when the thread runs


public void run() {
try {
for(int i=1; i<= 10;i++) {
sleep(500);
if(!allDone)
System.out.println(i);
else
return;

216
}
}
catch(InterruptedException e) {
System.out.println(e);
}
}
}

class ThreadStopDemo {
public static void main(String args[]) {
// Create and start the thread
MyThread thread = new MyThread();
thread.start();
try {
Thread.sleep(2000);
}
catch(InterruptedException e) {
System.out.println(e);
}
// Stop the thread
thread.allDone = true;
}
}

Why is stop deprecated?

Because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has
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.

9.10 Determining When a Thread Has Finished

Typically, the main thread is the last thread to finish in a program. However, there isn’t any
guarantee that the main thread won’t finish before a child thread finishes.

Programmers use two other techniques to ensure that the main thread is the last thread to
terminate. These techniques involve calling the isAlive() method and the join() method. Both of
these methods are defined in the Thread class.

The isAlive() method determines whether a thread is still running. If it is, the isAlive() method
returns a boolean true value; otherwise, a boolean false is returned. You can use the isAlive()
method to examine whether a child thread continues to run. The join() method works differently
than the isAlive() method. The join() method waits until the child thread terminates and “joins”

217
the main thread. In addition, you can use the join() method to specify the amount of time you
want to wait for a child thread to terminate.

class ThreadDemo {
public static void main(String args[]) {
// Create and start a thread
MyThread thread = new MyThread();
thread.start();

// Check if the thread has finished in a non-blocking way


if (thread.isAlive()) {
System.out.println(“Thread has not finished”);
}
else {
System.out.println(“Finished”);
}

// Wait for the thread to finish


try {
thread.join();
}
catch (InterruptedException e) {
System.out.println(“Thread was interrupted”);
}
if (thread.isAlive()) {
System.out.println(“Thread has not finished”);
}
else {
System.out.println(“Finished”);
}
}
}

9.11 Thread Scheduling

Many computer configurations have a single CPU. Hence, threads run one at a time in such a
way as to provide an illusion of concurrency. Execution of multiple threads on a single CPU in
some order is called scheduling. The Java runtime environment supports a very simple,
deterministic scheduling algorithm called fixed-priority scheduling. This algorithm schedules
threads on the basis of their priority relative to other Runnable threads.

Thread scheduling is implementation dependent and cannot be relied on to act the same way on
every JVM

When a thread is created, it inherits its priority from the thread that created it. At any given time,
when multiple threads are ready to be executed, the runtime system chooses for execution the
Runnable thread that has the highest priority. Only when that thread stops, yields, or becomes
Not Runnable will a lower-priority thread start executing. If two threads of the same priority are

218
waiting for the CPU, the scheduler arbitrarily chooses one of them to run. The chosen thread runs
until one of the following conditions is true:

 A higher priority thread becomes runnable.


 It yields, or its run method exits.
 On systems that support time-slicing, its time allotment has expired.

Then the second thread is given a chance to run, and so on, until the interpreter exits.

The Java runtime system's thread scheduling algorithm is also preemptive. If at any time a thread
with a higher priority than all other Runnable threads becomes Runnable, the runtime system
chooses the new higher-priority thread for execution. The new thread is said to preempt the other
threads.

Rule of thumb:  At any given time, the highest priority thread is running. However, this is not
guaranteed. The thread scheduler may choose to run a lower priority thread to avoid starvation.
For this reason, use thread priority only to affect scheduling policy for efficiency purposes. Do
not rely on it for algorithm correctness.

Time slicing/preemptive

Each thread gets a set amount of CPU time for executing. Once it has used up its time with the
CPU, it is removed from accessing the CPU and any other waiting Threads get a chance at CPU
time. When each thread has had its chance with the CPU the cycle starts again. The beauty of
this approach is that you can be confident that each thread will get at least some time executing.

In a pre-emptive system one program can "pre-empt" another to get its share of CPU time. In a
time sliced system each thread gets a "slice" of the CPU time and then gets moved to the ready
state. This ensures against a single thread getting all of the CPU time. The downside is that you
cannot be certain how long a Thread might execute or even when it will be running. Although
Java defines priorities for threads from the lowest at 1 to the highest at 10, some platforms will
accurately recognise these priorities whereas others will not.

The notify method will wake up one thread waiting to reacquire the monitor for the object. You
cannot be certain which thread gets woken. If you have only one waiting thread then you do not
have a problem. If you have multiple waiting threads then it will be probably the thread that has
been waiting the longest that will wake up. However you cannot be certain, and the priorities of
the threads will influence the result. As a result you are generally advised to use notifyAll instead
of notify, and not to make assumptions about scheduling or priorities. Of course this is not
always possible and you may have to try to test your code on as many platforms as possible.

Non time slicing/Cooperative

A priority system is used to decide which thread will run. A thread with the highest priority gets
time with the CPU. A program under this system needs to be created in such a way that it
"voluntarily" yield access to the CPU.

219
Relinquishing the CPU

As you can imagine, writing CPU-intensive code can have negative repercussions on other
threads running in the same process. In general, try to write well-behaved threads that voluntarily
relinquish the CPU periodically and give other threads an opportunity to run.

A thread can voluntarily yield the CPU by calling the yield method. The yield method gives
other threads of the same priority a chance to run. If no equal-priority threads are Runnable, the
yield is ignored.

9.12 Thread Synchronization

So far the examples in this chapter have contained independent, asynchronous threads. Each
thread contained all the data and methods required for its execution and didn’t require any
outside resources or methods. Also, the threads in those examples ran at their own pace without
concern for the state or activities of any other concurrently running threads.

A method in a Java object is said to be thread safe if it can be safely run in a multithreaded
environment. To achieve this safety, there must be a mechanism by which multiple threads
running the same method can synchronize their operations, such that only one of them is allowed
to proceed when accessing the same object or lines of code. This synchronization requires the
threads to communicate with each other using objects called semaphores.

One specific type of semaphore is called a mutual exclusion semaphore or a mutex. As the name
indicates, ownership of this semaphore object is mutually exclusive, in that only one thread can
own the mutex at any given time. Any other thread that tries to acquire ownership will be
blocked and must wait until the owning thread releases the mutex. If multiple threads are waiting
in line for the same mutex, only one of them will get it when it is released by the current owner;
the others will continue to block.

In the early 1970s, C.A.R. Hoare and others developed a concept known as a monitor. A monitor
is a body of code whose access is guarded by a mutex. Any thread wishing to execute this code
must acquire the associated mutex at the top of the code block and release it at the bottom.
Because only one thread can own a mutex at a given time, this effectively ensures that only the
owing thread can execute a monitor block of code. (The guarded code need not be contiguous --
for example, every object in the Java language has a single monitor associated with it.)

In many interesting situations, separate, concurrently running threads share data and must
consider the state and activities of other threads. In one such set of programming situations,
called producer-consumer scenarios, the producer generates a stream of data that a consumer
uses.

For example, imagine an application in which 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 mouse events in an event queue and the consumer
thread reads the events from the same queue. Both of these examples use concurrent threads that

220
share a common resource: The first shares a file, and the second shares an event queue. Because
the threads share a common resource, they must be synchronized.

The synchronized keyword

The synchronized keyword can be used to mark a statement or block of code so that only one
thread may execute an instance of the code at a time. Entry to the code is protected by a monitor
lock around it. This process is implemented by a system of locks. You may also see the words
monitor, or mutex (mutually exclusive lock) used. A lock is assigned to the object and ensures
only one thread at a time can access the code. Thus when a thread starts to execute a
synchronized block it grabs the lock on it. Any other thread will not be able to execute the code
until the first thread has finished and released the lock. Note that the lock is based on the object
and not on the method.

For a method the synchronized keyword is placed before the method thus

synchronized void amethod() { /* method body */}

For a block of code the synchronized keyword comes before opening and closing brackets thus.

synchronized (Object Reference) { /* Block body */ }

The value in parentheses indicates the object or class whose monitor the code needs to obtain. It
is generally more common to synchronize the whole method rather than a block of code.

 When a synchronized block is executed, its object is locked and it cannot be called by any other
code until the lock is freed.

Example

//This program is not synchronized


class Callme {
void call(String msg) {
System.out.print(“[“ + msg);
try {
Thread.sleep(1000);
}
catch(InterruptedException e) {
System.out.println(“Interrupted”);
}
System.out.println(“]”);
}
}

class Caller implements Runnable {


String msg;
Callme target;
Thread t;

221
public Caller(Callme targ, String s) {
target = targ;
msg = s;
t =new Thread(this);
t.start();
}

public void run() {


target.call(msg);
}
}

class Synch {
public static void main(String args[]) {
Callme target = new Callme();
Caller obj1 = new Caller(target, “Hello”);
Caller obj2 = new Caller(target, “Synchronized”);
try {
obj1.t.join();
obj2.t.join();
}
catch(InterruptedException e) {
System.out.println(“Interrupted”);
}
}
}

Output is :

[Hello[Synchronized
]
]

Same example using synchronization:

In the code above just add the keyword synchronized in front of the call method in the Callme
class.

synchronized void call(String msg)

This prevents other thread from entering call() while another thread is using it. The output of the
program is

[Hello]
[Synchronized]

If the Callme class is a third party class then you cannot change its code. In that case you can use
the synchronized block in the run method as follows:

public void run() {

222
synchronized(target) {
target.call(msg);
}
}

Only the run method is changed. The rest of the code is same.

The Producer/Consumer Example

In this example, the Producer generates an integer between 0 and 9 (inclusive), stores it in a
CubbyHole object. To make the synchronization problem more interesting, the Producer sleeps
for a random amount of time between 0 and 100 milliseconds before repeating the number-
generating cycle:

public class CubbyHole {


private int contents;

public int get() {


return contents;
}

public void put(int value) {


contents = value;
}
}

public class Producer extends Thread {


private CubbyHole cubbyhole;
private int number;

public Producer(CubbyHole c, int number) {


cubbyhole = c;
this.number = number;
}

public void run() {


for (int i = 0; i < 10; i++) {
cubbyhole.put(number, i);
try {
sleep((int)(Math.random() * 100));
}
catch (InterruptedException e) { }
}
}
}

The Consumer consumes all integers from the CubbyHole (the exact same object into which the
Producer put the integers in the first place) as quickly as they become available.

public class Consumer extends Thread {

223
private CubbyHole cubbyhole;
private int number;

public Consumer(CubbyHole c, int number) {


cubbyhole = c;
this.number = number;
}

public void run() {


int value = 0;
for (int i = 0; i < 10; i++) {
value = cubbyhole.get(number);
}
}
}

Producer and Consumer example share data through a common CubbyHole object. Although
Consumer ideally will get each value produced once and only once, neither Producer nor
Consumer makes any effort whatsoever to ensure that happens. The synchronization between
these two threads occurs at a lower level, within the get and put methods of the CubbyHole
object. However, assume for a moment that these two threads make no arrangements for
synchronization, and let’s discuss the potential problems that might arise from this.

One problem arises when the Producer is quicker than the Consumer and generates two numbers
before the Consumer has a chance to consume the first one. In this situation, the Consumer
misses a number. Part of the output might look like this:

Another problem might arise when the Consumer is quicker than the Producer and consumes the
same value twice. In this situation, the Consumer might produce output that looks like this:

Either way, the result is wrong because the Consumer should get each integer produced by the
Producer exactly once. A problem such as this is called a race condition. A race condition is a
situation in which two or more threads or processes are reading or writing some shared data, and
the final result depends on the timing of how the threads are scheduled. Race conditions can lead
to unpredictable results and subtle program bugs. Race conditions in the producer-consumer
example are prevented by having the storage of a new integer into the CubbyHole by the

224
Producer be synchronized with the retrieval of an integer from the CubbyHole by the Consumer.
The activities of the Producer and the Consumer must be synchronized in two ways.

First, the two threads must not simultaneously access the CubbyHole. A thread can prevent this
from happening by locking an object. When an object is locked by one thread and another thread
tries to call a synchronized method on the same object, the second thread will block until the
object is unlocked.

Second, the two threads must do some simple coordination. That is, the Producer must have a
way to indicate to the Consumer that the value is ready, and the Consumer must have a way to
indicate that the value has been retrieved. The Object class provides a collection of methods —
wait, notify, and notifyAll — to help threads wait for a condition and notify other threads when
that condition changes.

Locking an Object

Within a program, the code segments that access the same object from separate, concurrent
threads are called critical sections. A critical section can be a block or a method and is identified
with the synchronized keyword. The Java platform associates a lock with every object and the
lock is acquired upon entering a critical section.

In the producer-consumer example, the put and get methods of CubbyHole.java are the critical
sections. The Consumer should not access the CubbyHole when the Producer is changing it, and
the Producer should not modify it when the Consumer is getting the value. So put and get in the
CubbyHole class should be marked with the synchronized keyword.

Here’s a code skeleton for the CubbyHole class:

public class CubbyHole {


private int contents;
private boolean available = false;

public synchronized int get(int who) {


...
}

public synchronized void put(int who, int value) {


...
}
}

The method declarations for both put and get contain the synchronized keyword. Whenever
control enters a synchronized method, the thread that called the method locks the object whose
method has been called. Other threads cannot call a synchronized method on the same object
until the object is unlocked.

Thus, when it calls CubbyHole's put method, The Producer locks the CubbyHole, thereby
preventing the Consumer from calling the CubbyHole's get method:

225
public synchronized void put(int value) {
//CubbyHole locked by the Producer
...
//CubbyHole unlocked by the Producer
}

When the put method returns, the Producer unlocks the CubbyHole. Similarly, when the
Consumer calls CubbyHole's get method, it locks the CubbyHole, thereby preventing the
Producer from calling put:

public synchronized int get() {


// CubbyHole locked by the Consumer
...
// CubbyHole unlocked by the Consumer
}

The acquisition and release of a lock is done automatically and atomically by the Java run-time
system. This ensures that race conditions cannot occur in the underlying implementation of the
threads, thus ensuring data integrity.

Synchronization isn't the whole story. The two threads must also be able to notify one another
when they've done their job.

Reaquiring a Lock

The same thread can call a synchronized method on an object for which it already holds the lock,
thereby reacquiring the lock. The Java runtime environment allows a thread to reacquire a lock
because the locks are reentrant. Reentrant locks are important because they eliminate the
possibility of a single thread’s waiting for a lock that it already holds.

Consider this class:

public class Reentrant {


public synchronized void a() {
b();
System.out.println("here I am, in a()");
}
public synchronized void b() {
System.out.println("here I am, in b()");
}
}

Reentrant contains two synchronized methods: a and b. The first, a, calls the other, b. When
control enters method a, the current thread acquires the lock for the Reentrant object. Now, a
calls b; because b is also synchronized, the thread attempts to acquire the same lock again.
Because the Java platform supports reentrant locks, this works. In platforms that don’t support
reentrant locks, this sequence of method calls causes deadlock. The current thread can acquire

226
the Reentrant object's lock again, and both a and b execute to conclusion, as is evidenced by the
output:

here I am, in b()


here I am, in a()

9.13 Interthread Communication

The construct of wait/notify plays an important role in the Java language's interthread
communication mechanism. The essential idea is that one thread needs a certain condition that
can be brought about by another thread to become true. It therefore waits for the condition to be
met. Once the condition is true, the causing thread notifies the waiting thread to wake up and
proceed from where it left off.

wait and notify should be placed within synchronized code to ensure that the current code owns
the monitor

Using the notifyAll and wait Methods in the Producer/ Consumer Example

Let's investigate how the code in CubbyHole's put and get methods helps the Producer and the
Consumer coordinate their activities. The CubbyHole stores its value in a private member
variable called contents. CubbyHole has another private member variable, available, that is a
boolean. The available variable is true when the value has been put but not yet gotten and is false
when the value has been gotten but not yet put. Here's one possible implementation for the put
and get methods:

public synchronized int get() { //won't work!


if (available == true) {
available = false;
return contents;
}
}

public synchronized void put(int value) {


//won't work!
if (available == false) {
available = true;
contents = value;
}
}

As implemented, these two methods won't work. Look at the get method. What happens if the
Producer hasn't put anything in the CubbyHole and available isn't true? The get method does
nothing. Similarly, if the Producer calls put before the Consumer got the value, put doesn't do
anything.

227
You really want the Consumer to wait until the Producer puts something in the CubbyHole and
the Producer to notify the Consumer when it's done so. Similarly, the Producer should wait until
the Consumer takes a value (and notifies the Producer of its activities) before replacing it with a
new value. The two threads must coordinate more fully and can use Object's wait and notifyAll
methods to do so.

Here are the new get and put implementations that wait on and notify each other of their
activities:

class CubbyHole {
boolean available;
int contents;

public synchronized int get() {


while (available == false) {
try {
//wait for Producer to put value
wait();
}
catch (InterruptedException e) { }
}
available = false;
//notify Producer that value has been retrieved
notifyAll();
return contents;
}

public synchronized void put(int value) {


while (available == true) {
try {
//wait for Consumer to get value
wait();
}
catch (InterruptedException e) {
}
}
contents = value;
available = true;
//notify Consumer that value has been set
notifyAll();
}
}

The code in the get method loops until the Producer has produced a new value. Each time
through the loop, get calls the wait method. The wait method relinquishes the lock held by the
Consumer on the CubbyHole (thereby allowing the Producer to get the lock and update the
CubbyHole) and then waits for notification from the Producer. When Producer puts something in
the CubbyHole, it notifies Consumer by calling notifyAll. The Consumer then comes out of the
wait state and the get method returns the value in the CubbyHole.

228
The put method works in a similar fashion. It waits for the Consumer thread to consume the
current value before allowing the Producer to produce a new one.

The notifyAll method wakes up all threads waiting on the object in question (in this case, the
CubbyHole). The awakened threads compete for the lock. One thread gets it, and the others go
back to waiting. The Object class also defines the notify method, which arbitrarily wakes up one
of the threads waiting on this object.

There are the three versions of the wait method contained in the Object class:

wait()
Waits indefinitely for notification

wait(long timeout)
Waits for notification or until the timeout period has elapsed. timeout is measured in
milliseconds.

wait(long timeout, int nanos)


Waits for notification or until timeout milliseconds plus nanos nanoseconds have elapsed.

Note:  Besides using these timed wait methods to synchronize threads, you also can use them in
place of sleep. Both wait and sleep delay for the requested amount of time. You can easily
wake up wait with a notify but a sleeping thread cannot be awakened prematurely. This doesn't
matter too much for threads that don't sleep for long, but it could be important for threads that
sleep for minutes at a time.

Running the Producer-Consumer Example

Here’s a small standalone application, called ProducerConsumerTest, that creates a CubbyHole


object, a Producer, and a Consumer and then starts both the Producer and the Consumer:

public class ProducerConsumerTest {


public static void main(String[] args) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);

p1.start();
c1.start();
}
}

Here’s the output of ProducerConsumerTest:

Producer #1 put: 0
Consumer #1 got: 0
Producer #1 put: 1
Consumer #1 got: 1

229
Producer #1 put: 2
Consumer #1 got: 2
Producer #1 put: 3
Consumer #1 got: 3
Producer #1 put: 4
Consumer #1 got: 4
Producer #1 put: 5
Consumer #1 got: 5
Producer #1 put: 6
Consumer #1 got: 6
Producer #1 put: 7
Consumer #1 got: 7
Producer #1 put: 8
Consumer #1 got: 8
Producer #1 put: 9
Consumer #1 got: 9

9.14 Starvation and Deadlock

If you write a program in which several concurrent threads are competing for resources, you
must take precautions to ensure fairness. A system is fair when each thread gets enough access to
limited resources to make reasonable progress. A fair system prevents starvation and deadlock.
Starvation occurs when one or more threads in your program are blocked from gaining access to
a resource and, as a result, cannot make progress. Deadlock, the ultimate form of starvation,
occurs when two or more threads are waiting on a condition that cannot be satisfied. Deadlock
most often occurs when two (or more) threads are each waiting for the other(s) to do something.

Livelocks

A livelock, unlike a deadlock, happens when threads are actually running, but no work gets done.
This usually happens when the two threads are working at cross-purposes, so what is done by the
first thread is undone by another. A simple example is where each thread already holds one
object and needs another that is held by the other thread. Now imagine a situation wherein each
thread puts down the object it possesses and picks up the object put down by the other thread.
Clearly, these two threads can run forever in lock-step, effectively managing to achieve nothing
at all. (A common real world example is when two people approach each other in a narrow
corridor. Each person tries to be polite by moving to one side to let the other one pass, but both
keep moving to the same side at the same time, thereby ensuring that neither can pass. This
continues for some time, with both of them swaying from side to side and no progress being
made.)

9.15 Suspending, Resuming & Stopping Threads

Sometimes suspending execution of a thread is useful. For example, a separate thread can be
used to display the time of the day. If the user doesn’t want a clock, then its thread can be
suspended. Whatever the case, suspending a thread is a simple matter. Once suspended,
restarting the thread is also a simpler matter.

230
An example using the deprecated methods:

//using suspend() and resume()


class NewThread implements Runnable {
String name; //name of thread
Thread t;

NewThread(String threadName) {
name = threadName;
t = new Thread(this, name);
System.out.println(“New Thread :” + t);
t.start(); // start the thread
}

// this is the entry point for Thread


public void run() {
try {
for(int i=15; i > 0;i--) {
System.out.println(name + “:” + i);
Thread.sleep(200);
}
}
catch(InterruptedException e) {
System.out.println(e);
}
System.out.println(name + “exiting”);
}
}

class SuspendResume {
public static void main(String args[]){
NewThread t1 = new NewThread(“One”);
NewThread t2 = new NewThread(“Two”);
try {
Thread.sleep(1000);
t1.t.suspend();
System.out.println(“Suspending thread one”);
Thread.sleep(1000);
t1.t.resume();
System.out.println(“Resuming thread one”);
t1.t.join();
t2.t.join();
}
catch(InterruptedException e) {
System.out.println(“Main thread interrupted”);
}
System.out.println(“Main thread exiting”);
}
}

231
This program creates two threads and suspends one of them. While one thread is suspended the
other runs.

The same example code is written below without using deprecated methods.

class NewThread implements Runnable {


String name; //name of thread
Thread t;
boolean suspendFlag;

NewThread(String threadName) {
name = threadName;
t = new Thread(this, name);
System.out.println(“New Thread :” + t);
suspendFlag = false;
t.start(); // start the thread
}

// this is the entry point for Thread


public void run() {
try {
for(int i=15; i > 0;i--) {
System.out.println(name + “:” + i);
Thread.sleep(200);
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
}
catch(InterruptedException e) {
System.out.println(e);
}
System.out.println(name + “exiting”);
}

void mysuspend() {
suspendFlag = true;
}

synchronized void myresume() {


suspendFlag = false;
notify();
}
}

In the main method of the previous code instead of calling suspend() call mysuspend() method
and instead of resume() call myresume()

232
9.16 ThreadGroup

ThreadGroup creates a group of threads. It defines two constructors:

ThreadGroup(String groupName);
ThreadGroup(ThreadGroup parent, String groupName)

ThreadGroup offers a convenient way to manage groups of threads as a unit. This is valuable in
situations in which you want to suspend and resume a number of related threads.

Example of ThreadGroup:

class NewThread extends Thread {

NewThread(String threadName, ThreadGroup tg) {


super(tg,threadName);
System.out.println(“New Thread :”+ this);
start(); //start the thread
}

//This is the entry point for the thread


public void run() {
try {
for(int i=15; i > 0; i--) {
System.out.println(getName() + “:”+ i);
Thread.sleep(1000);
}
}
catch(Exception e) {
System.out.println(e);
}
System.out.println(getName() + “: exiting”);
}
}

class ThreadGroupDemo {
public static void main(String args[]) {
ThreadGroup gA = new ThreadGroup(“Group A”);
ThreadGroup gB = new ThreadGroup(“Group B”);
NewThread t1 = new NewThread(“One”,gA);
NewThread t2 = new NewThread(“Two”,gA);
NewThread t3 = new NewThread(“Three”,gB);
NewThread t4 = new NewThread(“Four”,gB);
try {
Thread.sleep(5000);
}
catch(Exception e) {
System.out.println(e);
}
gA.suspend();

233
try {
Thread.sleep(5000);
}
catch(Exception e) {
System.out.println(e);
}
gA.resume();
try {
t1.join();
t2.join();
t3.join();
t4.join();
}
catch(Exception e){
System.out.println(e);
}
}
}

Summary

A thread is a logical execution unit that has a single sequential flow. Multitasking can be
achieved by process based multitasking and thread based multitasking. Thread-based
multitasking also called as multithreading is cheaper compared to process based multitasking. In
multithreaded application you can execute multiple threads within a single program.

234
Chapter 10 : String Handling
The Java development environment provides two classes that store and manipulate character
data: String, for immutable strings, and StringBuffer, for mutable strings.

The String class provides for constant strings; you use Strings when you don't want the value of
the string to change. For example, if you pass a string data into a method, and you don't want the
method to modify the string in any way (which is typical), you would use a String.

The StringBuffer class provides for non-constant strings; you use StringBuffers when you know
that the value of the character data will change.

Because they are constants, Strings are typically cheaper than StringBuffers and they can be
shared. So it's important to use Strings when they're appropriate.

Both String and StringBuffer are the classes in java.lang package and they implement the
CharSequence interface.

10.1 The String class

Strings in Java are constants. Once they are initialized and populated the value and memory
allocation is set (they are immutable, meaning they can not be changed.) If the String is changed
in any way a new String object is created in memory for the new value.

In the Java language, you specify literal strings between double quotes

"Hello World!"

You can use literal strings anywhere you would use a String object. For example,
System.out.println() accepts a String argument, so you could use a literal string in place of a
String there.

System.out.println("And might I add that you look lovely today.");

Because the compiler automatically creates a new String object for every literal string it
encounters, you can use a literal string to initialize a String.

String s = "Hola Mundo";

The above construct is equivalent to, but more efficient than, this one

String s = new String("Hola Mundo");

because the compiler ends up creating two Strings instead of one: first when the compiler
encounters "Hola Mundo!", and second when it encounters new String().
Creating a string

235
Strings are created like any other object in Java using the new operator. For example one of the
String constructors allows an array of characters to be taken as input:

char letters[] = {'J','A','V','A'};


String str = new String (letters);
// One constructor accepts an array of chars
System.out.println (str); // will print JAVA

One more constructor of String is


String (String obj)

String s = new String(“Java”);

While creating a String object you can also specify the byte values.

String (byte asciiChars[])


String (byte asciiChars[], int startIndex, int numChars)

Class StringExample {
public static void main(String args[]) {
byte ascii [] = {65, 66, 67, 68, 69, 70};
String s1 = new String(ascii);
System.out.println(s1);

String s2 = new String(ascii, 2, 3);


System.out.println(s2);
}
}

This program prints

ABCDEF
CDE

There are two more constructors of String class

String(StringBuffer)
String(StringBuilder)

The first one creates a string whose value is set from a string buffer. The second creates a string
whose value is set from a string builder.

Comparing Strings

The equals method

Comparing two Strings references to see if they hold identical strings is easily achieved with the
equals method. This method is called on one string object and takes another as an input

236
parameter, if they are equal it returns the boolean value true, otherwise it returns false. For
example:
String str = "hello";
String str2 = "hello";
String str3 = "goodbye";

System.out.println ("str and str2" + str.equals(str2)); // true


System.out.println ("str and str3" + str.equals(str2)); // false

If you try to compare two strings like this:


if (str == str2)
System.out.println ("true");
else
System.out.println ("false");

you are actually checking to see whether the two references str and str2 refer to the same object.
It is possible that two strings are equal without them being the same object. So if you want to
compare the contents of the string use equal, if you want to check if the two references refer to
the same object use ==. Two references which point to the same object will always return true
with the equals method, but two references which refer to different objects, both containing the
same string, with be false with the == operator.

The equalsIgnoreCase method

This method is similar to the equals method instead it performs the case insensitive comparison
of Strings.

boolean equalsIgnoreCase (String str)

The compareTo method

int compareTo(String str)

This method is called in the same way as the equals method but returns an integer result. If the
result is less than 0 then the first string is less than the second, if it is equal to 0 they are equal
and if the result is greater than 0 then the first is greater than the second.

This short example shows how comparisons are made amongst string:

class strCmp
{
public static void main (String args[])
{
String str = "Hello";
String str2 = "Java";

System.out.println (str.equals(str2)); // false

237
System.out.println (str.compareTo(str2));
// a negative number, i.e. str is less than str2
}
}

The compareToIgnoreCase method

This method is similar to the compare method the only difference is it performs the case
insensitive comparison.

int compareToIgnoreCase(String str)

The regionMatches method

boolean regionMatches(int, String, int, int)


boolean regionMatches(boolean, int, String, int, int)

This method tests whether the specified region of this string matches the specified region of the
String argument. The boolean argument indicates whether case should be ignored; if true, the
case is ignored when comparing characters.

The following program, RegionMatchesDemo, uses the regionMatches method to search for a
string within another string:

public class RegionMatchesDemo {


public static void main(String[] args) {
String searchMe = "Green Eggs and Ham";
String findMe = "Eggs";
int len = findMe.length();
boolean foundIt = false;
int i = 0;
while (!searchMe.regionMatches(i, findMe, 0, len))
{
i++;
foundIt = true;
}
if (foundIt) {
System.out.println(searchMe.substring(i, i+len));
}
}
}

The output from this program is Eggs.

The program steps through the string referred to by searchMe one character at a time. For each
character, the program calls the regionMatches method to determine whether the substring
beginning with the current character matches the string for which the program is looking.

The charAt method

238
char charAt (int where)

This method is called on a string object with an integer value as a parameter, it returns a char
which is at the location of the parameter passed in the string.

char ch = “abc”.charAt(1);

assigns ‘b’ to ch

The length method

public int length();

This method is called on a string object with no parameters and returns an integer number which
is the number of characters in the string
class strExample
{
public static void main (String args[])
{
String str = "Hello";
String str2 = "Java";
System.out.println (str.charAt(0));
// H, i.e. char is position 0
System.out.println (str.length() + str2.length());
// 5 + 4 = 9
}
}

Altering Strings

Strings in Java are actually rather like constants, once they have been declared the objects can
not be altered. Hence, they are called immutable objects. However, there are several methods
which appear to need to alter the contents of the string. What they actually do is return a new
String.

The toUpperCase and ToLowerCase method

String toLowerCase()
String toUpperCase()

These two methods are called on a string object and simply convert all letters in the string to the
appropriate case.

//demonstrate toUpperCase and toLowerCase


class ChangeCase {
public static void main(String args[]) {
String s = “ This is a test”;

239
System.out.println(“Original :” + s);

String upper = s.toUpperCase();


String lower = s.toLowerCase();

System.out.println(“Uppercase:”+ upper);
System.out.println(“Lowercase:”+ lower);
}
}

The output produced by the program is shown here:

Original : This is a test.


UpperCase : THIS IS A TEST.
LowerCase : this is a test.

The substring method

String substring (int startIndex)


String substring (int startIndex, int endIndex)

This versatile method is overloaded to have two versions, the first accepts an int and the second
two. The first type leaves the new string with all letters from the old ranging from the first to the
number specified. The second version allows the start of the substring being created to be
specified as well as the end.

The trim method

String trim()

A very simple method called on a string object this simply removes all whitespace from the
string

String s = “ Hello World ”. trim();

Puts “Hello World” into s.

The concat method

String concat(String str)

This method is called on one string object with another as its parameter. The two are
concatenated together with the object on which the method was called holding the new string.

String s1 = “One”;
String s2 = s1.concat(“Two”);

puts “OneTwo” into s2.

240
The replace method

String replace (char original, char replacement)

This method is called on a string object with two char parameters. The string is searched for the
first char parameter, when it is found it is replaced with the second.

String s = “Hello”.replace(‘l’,’w’);

puts the string”Hewwo” into s

The valueOf method

static String valueOf (double num)


static String valueOf (long num)
static String valueOf (Object obj)
static String valueOf (char char[])
static String valueOf (char char[], int startIndex, int numChars)

This method is slightly different to the one mentioned above because it is not called on a string
object. Instead it is a static method which is overloaded to accept all simple Java types and
returns a string.

As a convenience, the String class provides the static method valueOf() which you can use to
convert variables of different types to Strings. For example, to print the value of pi

System.out.println(String.valueOf(Math.PI));

An example of methods which alter Strings

class altStr
{
public static void main (String args[])
{
String str = "Hello";
String str2 = "Java";

str = str.toUpperCase();
str2 = str2.toLowerCase();

System.out.println (str); // HELLO


System.out.println (str2);// java

str = str.concat(str2);
// str now equals "HELLO java"
System.out.println (str);

str = str.trim();
// str now equals "HELLOjava"

241
System.out.println (str);

str = str.substring (5,str.length());


// str = "java"
System.out.println (str);

str = str.replace ('a', 'i'); // str = "jivi"


System.out.println (str);

str = String.valueOf (3.141); // str = "3.141"


System.out.println (str);
}
}

Searching String

The indexOf and lastIndexOf methods

int indexOf (int ch)


int indexOf (String s)
int indexOf(int ch, int startIndex)
int indexOf(String s, int startIndex)

int lastIndexOf(int ch)


int lastIndexOf(String s)
int lastIndexOf(String s, int startIndex)
int lastIndexOf(String s, int startIndex)

These two overloaded methods allow a character or substring to be searched for. These methods
allow for the string to be searched either from the beginning (IndexOf) or from the end
(lastIndexOf). The input parameters for these methods is a char or string which is to be found
and an optional offset from the beginning (or end) of the string, given as an int. The example
below shows possible versions of the two methods.

class indexTest
{
public static void main (String args[])
{
String str = "This string will be searched";
String find = "will";

System.out.println (str.indexOf ('s'));


// find char, no offset
System.out.println (str.lastIndexOf ('s', 4));
// find s, offset by 9

System.out.println (str.indexOf (find));


// find the string find, no offset
System.out.println (str.lastIndexOf(find));
// find the string find in str, no offset

242
}
}

The indexOf() and lastIndexOf() methods are frequently used in conjunction with substring()
which returns a substring of the string. The following class illustrates the use of lastIndexOf()
and substring() to isolate different parts of a filename.

class Filename {
String fullpath;
char pathseparator;

Filename(String str, char sep) {


fullpath = str;
pathseparator = sep;
}

String extension() {
int dot = fullpath.lastIndexOf('.');
return fullpath.substring(dot + 1);
}

String filename() {
int dot = fullpath.lastIndexOf('.');
int sep = fullpath.lastIndexOf(pathseparator);
return fullpath.substring(sep + 1, dot);
}

String path() {
int sep = fullpath.lastIndexOf(pathseparator);
return fullpath.substring(0, sep);
}
}

The extension() method uses lastIndexOf() to locate the last occurrence of the period ('.') in
the filename. Then substring() uses the return value of lastIndexOf() to extract the filename
extension--that is, the substring from the period ('.') to the end of the string. This code assumes
that the filename actually has a period ('.') in it; if the filename does not have a period ('.'), then
lastIndexOf() returns -1, and the substring() method throws a "string index out of range
exception".

Also, notice that extension() uses dot + 1 as the argument to substring(). If the period ('.')
character is the last character of the string, then dot + 1 is equal to the length of the string which
is one larger than the largest index into the string (because indices start at 0). However,
substring() accepts an index equal to (but not greater than) the length of the string and interpret it
to mean "the end of the string".

While the methods in the example above uses only one version of the lastIndexOf() method, the
String class supports four different versions of both the indexOf() and lastIndexOf() methods
which
 returns the index of the first (last) occurrence of the specified character

243
 returns the index of the first (last) occurrence of the specified character, searching forward
(backward) from the specified index
 returns the index of the first (last) occurrence of the specified String.
 returns the index of the first (last) occurrence of the specified String, searching forward
(backward) from the specified index

The getBytes method

byte [] getBytes()

This method converts the String to the byte array where each character in the string is converted
to its ascii equivalent and stored in the array.

The toCharArray() method

If you want to convert the characters in a string to char type and store it in the character array use
this method

char [] toCharArray()

The startsWith and endsWith methods

The startsWith method determines whether a given String begins with a specified string. The
endsWith determines whether the String ends up with a specified String.

boolean startsWith(String str)


boolean startsWith(String str, int startIndex)
boolean endsWith(String str)

For example,

“Foobar”.endsWith(“bar”);
“Foobar”.startsWith(“Foo”);

both return true

“Foobar”.startsWith(“bar”,3)

returns true

The split method

J2SE 1.4 added the split() method to the String class to simplify the task of breaking a string
into substrings, or tokens. This method uses the concept of a regular expression to specify the
delimiters. A regular expression is a remnant from the Unix grep tool ("grep" meaning "general
regular expression parser").

244
In its simplest form, searching for a regular expression consisting of a single character finds a
match of that character. For example, the character 'x' is a match for the regular expression "x".

The split() method takes a parameter giving the regular expression to use as a delimiter and
returns a String array containing the tokens so delimited. Using split(), the first example
above becomes

String str = "This is a string object";


String[] words = str.split (" ");
for (int i=0; i < words.length; i++)
System.out.println (words[i]);
//To use "*" as a delimiter, simply specify "*" as the regular
//expression:
String str = "A*bunch*of*stars";
String[] starwords = str.split ("*");

For most string splitting tasks, the String.split() method is much easier and more natural to
use than the StringTokenizer class. However, StringTokenizer is still useful for some tasks.
For example, an overloaded StringTokenizer constructor allows you to specify that the tokens
to be returned include the delimiter characters themselves.

The + operator

There is another special piece of string syntax using the + operator. This allows strings to be
added together, at the moment it is convenient to know how to use this.

String s = "Hello";
String t = s + "there" + ", how are you" + "today";
// t = "Hello there, how are you today"

The following code will append several values together and output a line of text to the system
console.

String CustName = "John Smith";


String CustOrder = "Java Programming Course";
System.out.println(CustName + " ordered a " + CustOrder + ".");

Example of String concatenation with other data types

int age = 9;
String s = “He is ” + age + “ years old”;
System.out.println(s);

Here int is converted to String

String s = “four :” + 2 + 2;
System.out.println(s);

This code displays

245
four : 22

rather than

four : 4

This is because the String concatenation operator has the higher precedence than the arithmetic +
operator. Hence to get the desired result use

String s = “four :” + (2 + 2);

10.2 The StringBuffer Class

The StringBuffer class is the second of Java's classes which deal with string handling. While the
original String class dealt with strings which were of a fixed length (the length of the number of
characters the string contained) and whose contents could not be altered the StringBuffer class
deals with strings which are not full of characters and whose contents can be changed. This is
useful for a number of operation, such as adding characters into to the end of a string, which is
not possible with a normal String. The plus operator which looks like it allows normal Strings to
be extended actually uses the StringBuffer class and converts back to a string. The reason Java
has too separate classes to deal with strings is simply for performance reasons.

For example : The following code creates String objects and uses the concatenation (+) character
to add more characters to them:

String sample1 = new String(“Builder.com”);


sample1 += “ is “;
sample1 += “the place “;
sample1 += “to be.”;

In the end, the system creates four String objects to handle the alterations. The first is created
with the text Builder.com. A new object is created every time more text is appended.

The problem with this approach is that too many resources are being used for such a simple
procedure. The effects may be minimal in this instance (given the small amount of code), but a
larger application with more operations will likely degrade performance. This is the niche filled
by the StringBuffer class.

Constructors of StringBuffer class

Constructor Description
StringBuffer() Constructs a string buffer with no characters in it and an initial

246
capacity of 16 characters.
StringBuffer(int capacity) Constructs a string buffer with no characters in it and an initial
capacity specified by the length argument.
StringBuffer(String str) Constructs a string buffer so that it represents the same sequence
of characters as the string argument; in other words, the initial
contents of the string buffer is a copy of the argument string.

The StringBuffer class is designed to create and manipulate dynamic string information. The
memory allocated to the object is automatically expanded to accommodate additional text.

StringBuffer sb = new StringBuffer();


StringBuffer sb = new StringBuffer(30);
StringBuffer sb = new StringBuffer(“Builder.com”);

The first line creates an object with no text and the default capacity of 16 characters. The second
instance of the class has no value and a capacity of 30 characters, and the final line creates an
object with the initial value. The StringBuffer class is included in the base java.lang package, so
no special imports statement is needed to take advantage of it.

Creating StringBuffer objects

To create a StringBuffer object use the following:


StringBuffer rb = new StringBuffer();

When a StringBuffer object is created it has a capacity, which is the number of characters that
the StringBuffer will contain if full. If the default constructor is called with no parameters this
capacity is set to 16, otherwise an int may be passed as a parameter to specify the capacity.
Another constructor allows an initial set of characters to be passed as a parameter, in this case the
capacity of the StringBuffer will be the number of characters in the initial string plus a further
16. The following example shows the possible ways of building StringBuffer objects.

StringBuffer strbuf = new StringBuffer (); // capacity = 16


StringBuffer strbuf2 = new StringBuffer (25);
// capacity = 25
StringBuffer strbuf3 = new StringBuffer ("Java");
// capacity = 4 + 16 = 20

The length method

int length()

Returns the length (character count) of this string buffer.

Methods concerned with capacity

The capacity method

247
int capacity()

This method is called on a StringBuffer object and returns the capacity as an int. Note that the
capacity will be different to the length, unless the buffer is full. The following example shows
this:

StringBuffer strbuf = new StringBuffer ("Hello");


System.out.println (strbuf.length()); // prints 5
System.out.println (strbuf.capacity()); // prints 21

The capacity() method differs from length() in that it returns the amount of space currently
allocated for the StringBuffer, rather than the amount of space used.

The ensureCapacity method

void ensureCapacity(int capacity)

Once a StringBuffer object has been created the size of the buffer can be resized using the
ensureCapacity method, called on the StringBuffer object with the new size (int) as the only
parameter. Note that this method ensures a minimum capacity, the actual capacity may be more
than you have specified.

The setLength method

void setLength(int length)

This method allows the length of a StringBuffer object to be set, if the value passed (int) is
greater than the existing length then the remainder will be filled with zeros.

To reset a StringBuffer (to use it somewhere else) set the length to zero using the setLength()
method. This will "clear" out the value in the StringBuffer.

rb.setLength(0);

An example of StringBuffer capacity

class altBuf
{
public static void main (String args[])
{
StringBuffer strbuf = new StringBuffer ("Hello");

System.out.println (strbuf); // Hello

strbuf.append ("_world");
System.out.println (strbuf); // Hello_World

248
strbuf.setCharAt (5, ' ');
System.out.println (strbuf); // Hello World

strbuf.insert (6, "Java ");


System.out.println (strbuf); // Hello Java World
}
}

The charAt and setCharAt methods

char charAt(int index)


void setCharAt(int index, char charValue)

The charAt method works the same as for a String object. The setCharAt method takes two
parameters as input, an int to specify the position in the StringBuffer and a char which the
character at the given position will be changed to.

//demonstrate charAt and setCharAt


class CharAtDemo {
public static void main(String args[]) {
StringBuffer sb = new StringBuffer(“Hello”);
System.out.println(“Buffer before = ” + sb);
System.out.println(“charAt(1) before = ” + sb.charAt(1));
sb.setCharAt(1,’i');
sb.setLength(2);
System.out.println(“Buffer after : ” +sb);
System.out.println(“charAt(1) after = ” + sb.charAt(1));
}
}

Here is the output generated by this program:

Buffer before = Hello


charAt(1) before = e
buffer after = Hi
charAt(1) after = i

The insert method

StringBuffer insert(int index, boolean booleanValue)


Inserts the string representation of the boolean argument into this string buffer.

StringBuffer insert(int index, char charValue)


Inserts the string representation of the char argument into this string buffer.

StringBuffer insert(int index, char[] charArray)


Inserts the string representation of the char array argument into this string buffer.

StringBuffer insert(int index, char[] charArray, int startIndex, int

249
numChars)
Inserts the string representation of a subarray of the str array argument into this string buffer.

StringBuffer insert(int index, double doubleValue)


Inserts the string representation of the double argument into this string buffer.

StringBuffer insert(int index, float floatValue)


Inserts the string representation of the float argument into this string buffer.

StringBuffer insert(int index, int intValue)


Inserts the string representation of the second int argument into this string buffer.

StringBuffer insert(int index, long longValue)


Inserts the string representation of the long argument into this string buffer.

StringBuffer insert(int index, Object obj)


Inserts the string representation of the Object argument into this string buffer.

StringBuffer insert(int index, String str)


Inserts the string into this string buffer.

The insert method is identical to the append method except that the data is added to the string at
a specified position. Again this method is called on a StringBuffer object but it takes two
parameters, the first (int) is the position where the data is to be added, and the second is the data
to be added (of any simple type, or a String).

This example illustrates how you would insert a string into a StringBuffer.

StringBuffer sb = new StringBuffer("Drink Java!");


sb.insert(6, "Hot ");
System.out.println(sb.toString());

This code snippet prints


Drink Hot Java!

With StringBuffer's many insert(), you specify the index before which you want the data
inserted. In the example, "Hot " needed to be inserted before the 'J' in "Java". Indices begin at 0,
so the index for 'J' is 6. To insert data at the beginning of a StringBuffer use an index of 0. To
add data at the end of a StringBuffer use an index equal to the current length of the StringBuffer
or use append().

An example of altering the contents of StringBuffer objects

class AltBuf
{
public static void main
{

250
StringBuffer strbuf = new ("Hello");
System.out.println (strbuf); // Hello

strbuf.append ("_world");
System.out.println (strbuf); // Hello_World

strbuf.setCharAt (6, " ");


System.out.println (strbuf); // Hello World

strbuf.insert (7, "Java ");


System.out.println (strbuf); // Hello Java World
}
}

The toString method

String toString()

Converts to a string representing the data in this string buffer.

To output the StringBuffer value use the toString() method

The append method

StringBuffer append(boolean booleanValue)


Appends the string representation of the boolean argument to the string buffer.

StringBuffer append(char charValue)


Appends the string representation of the char argument to this string buffer.

StringBuffer append(char[] charArray)


Appends the string representation of the char array argument to this string buffer.

StringBuffer append(char[] charArray, int startIndex, int numChars)

Appends the string representation of a subarray of the char array argument to this string buffer.

StringBuffer append(double doubleValue)


Appends the string representation of the double argument to this string buffer.

StringBuffer append(float floatValue)


Appends the string representation of the float argument to this string buffer.

StringBuffer append(int intValue)


Appends the string representation of the int argument to this string buffer.

StringBuffer append(long longValue)


Appends the string representation of the long argument to this string buffer.

251
StringBuffer append(Object obj)
Appends the string representation of the Object argument to this string buffer.

StringBuffer append(String str)


Appends the string to this string buffer.

This method allows data of any of the simple data types to be added to the end of a StringBuffer.
This is achieved by the method being overloaded for all of the simple data types and using the
valueOf method. The append method is called on a StringBuffer object with the data to be added
as an input parameter.

The append method can be used to append values together. The append method can accept any
data type as input and converts the data to a String to be appended to the end of the value in the
StringBuffer.

StringBuffer rb = new StringBuffer();


rb.append("Hello").append(" ").append("World!");

The StringBuffer variable, rb, now holds the value of "Hello World!".

StringBuffer sb = new StringBuffer();


sb.append("B");
sb.append("u");
sb.append("i");
sb.append("l");
sb.append("d");
sb.append("e");
sb.append("r");
sb.append(".com");
System.out.println(sb.toString());

This code creates the string Builder.com and sends it to the standard output, but only one object
is created. The same code using String objects would require more than eight objects. Notice that
the code takes advantage of the toString method of the StringBuffer class. This method converts
the contents to a String object that can be used for output. This allows text to be manipulated
accordingly and used for output or data storage.

StringBuffer b = new StringBuffer();


System.out.println(b.append("Hello”).append("World").toString());

One more example

StringBuffer sb = new StringBuffer();


sb.ensureCapacity(40);
sb.append("Builder.com is awesome!");
System.out.println(sb.toString());
sb.setLength(11);
System.out.println(sb.toString());

252
 
This code sets the capacity and populates the object with a string. The length property is reset so
that the text is truncated. The output follows:
 
Builder.com is awesome!
Builder.com

The delete method

StringBuffer delete(int start, int end)

Removes the characters in a substring of this StringBuffer.

The deleteCharAt method

StringBuffer deleteCharAt(int index)

Removes the character at the specified position in this StringBuffer (shortening the StringBuffer
by one character).

//demonstrate delete and deleteCharAt


class deleteDemo {
public static void main(String args[]) {
StringBuffer sb = new StringBuffer(“This is a test”);
sb.delete(4,7);
System.out.println(“After delete :” + sb);
sb.deleteCharAt(0);
System.out.println(“After deleteCharAt : ” + sb);
}
}
The following output is produced :

After replace : This was a test

The replace method

public StringBuffer replace(int start, int end, String str)


Replaces the characters in a substring of this StringBuffer with characters in the specified String.

The reverse method

StringBuffer reverse()

The character sequence contained in this string buffer is replaced by the reverse of the sequence.

The following code and output show it in action:


 
StringBuffer sb = new StringBuffer();
sb.ensureCapacity(100);

253
sb.append("Builder.com!");
System.out.println(sb.toString());
sb.reverse();
System.out.println(sb.toString());

Output:

Builder.com!
!moc.redliuB

The reverse method is present only in the StringBuffer class. Hence if you want to reverse a
String you can use the StringBuffer for doing so.

Example

class ReverseString {
public static String reverseIt(String source) {
StringBuffer dest = new StringBuffer(source);
dest.reverse();
return dest.toString();
}
}

The reverseIt() method accepts an argument of type String called source which contains the
string data to be reversed. The method creates a StringBuffer, dest, the same size as source,
then loops backwards over all the characters in source and appends them to dest thereby
reversing the string. Finally, the method converts dest, a StringBuffer, to a String.

The getChars method

public void getChars(int srcBegin, int srcEnd, char dst[],


int dstBegin)

Characters are copied from this string buffer into the destination character array dst.

The substring method

String substring(int startIndex)

Returns a new String that contains a subsequence of characters currently contained in this
StringBuffer.The substring begins at the specified index and extends to the end of the
StringBuffer.

String substring(int startIndex, int endIndex)

254
Returns a new String that contains a subsequence of characters currently contained in this
StringBuffer.

10.3 The StringBuilder class

J2SE5.0 added the StringBuilder class, which is a drop-in replacement for StringBuffer in
cases where thread safety is not an issue. Because StringBuilder is not synchronized, it offers
faster performance than StringBuffer.

In general, you should use StringBuilder in preference over StringBuffer. In fact, the J2SE
5.0 javac compiler normally uses StringBuilder instead of StringBuffer whenever you
perform string concatenation as in

System.out.println ("The result is " + result);

All the methods available on StringBuffer are also available on StringBuilder, so it really is
a drop-in replacement. Following is a sample program called StringsDemo, which reverses the
characters of a string. This program uses both a string and a string builder.

public class StringsDemo {


public static void main(String[] args) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
StringBuilder dest = new StringBuilder(len);
for (int i = (len - 1); i >= 0; i--) {
dest.append(palindrome.charAt(i));
}
System.out.println(dest.toString());
}
}

The output from this program is:

doT saw I was toD

Questions

1. class MCZ17 {
public static void main (String[] args) {
String a = "\n"; // 1
String b = "\r"; // 2
String c = "\u000a"; // 3 \u000a = new line
String d = "\u000d"; // 4 \u000d = return
}
}

Compile-time errors are generated at which lines?

255
a.  1 b.  2 c.  3 d.  4

2. class MCZ20 {
public static void main (String[] args) {
// Insert code here.
}
}

Which of the following lines can be inserted at the specified location without generating a compile-time error?

a.  String a = 'a'; d.  String d = '\uabcd';


b.  String b = 'abc'; e.  None of the above
c.  String c = '\u0041';

256
Chapter 11 : I/O
11.1 I/O Streams

To bring in information, a program opens a stream on an information source (a file, memory, a


socket) and reads the information sequentially, as shown here

Similarly, a program can send information to an external destination by opening a stream to a


destination and writing the information out sequentially, like this:

Reading Writing
open a stream open a stream
while more information while more information
read information write information
close the stream close the stream

The java.io package contains a collection of stream classes that support these algorithms for
reading and writing. To use these classes, a program needs to import the java.io package. The
stream classes are divided into two class hierarchies, based on the data type (either characters or
bytes) on which they operate.

257
I/O Stream Classes

This diagram shows most of the members of the java.io package. Rectangles are classes,
parallelograms are abstract classes, and ovals are interfaces

258
Byte Streams

To read and write 8-bit bytes, programs should use the byte streams, descendants of InputStream
and OutputStream. InputStream and OutputStream provide the API and partial implementation
for input streams (streams that read 8-bit bytes) and output streams (streams that write 8-bit
bytes). These streams are typically used to read and write binary data such as images and sounds.
Two of the byte stream classes, ObjectInputStream and ObjectOutputStream, are used for
object serialization.

The InputStream class is an abstract base class that provides a minimal programming interface
and a partial implementation of input streams in Java. The InputStream class defines a methods
for reading bytes or arrays of bytes, marking locations in the stream, skipping bytes of input,
finding out the number of bytes that are available for reading, and resetting the current position
within the stream. An input stream is automatically opened when you create it. You can
explicitly close a stream with the close() method, or let it be closed implicitly when the object is
garbage collected.

The OutputStream class is an abstract base class that provides a minimal programming interface
and a partial implementation of output streams in Java. OutputStream defines methods for
writing bytes or arrays of bytes to the stream and flushing the stream. An output stream is
automatically opened when you create it. You can explicitly close an output stream with the
close() method, or let it be closed implicitly when the object is garbage collected.

Character Streams

Reader and Writer are the abstract superclasses for character streams in java.io. Reader provides
the API and partial implementation for readers--streams that read 16-bit characters--and Writer
provides the API and partial implementation for writers--streams that write 16-bit characters.
Subclasses of Reader and Writer implement specialized streams and are divided into two
categories: those that read from or write to data sinks

Understanding the I/O Superclasses

Reader and InputStream define similar APIs but for different data types. For example, Reader
contains these methods for reading characters and arrays of characters:

int read()
int read(char cbuf[])
int read(char cbuf[], int offset, int length)

InputStream defines the same methods but for reading bytes and arrays of bytes:
int read()
int read(byte cbuf[])
int read(byte cbuf[], int offset, int length)

259
Also, both Reader and InputStream provide methods for marking a location in the stream,
skipping input, and resetting the current position.

Writer and OutputStream are similarly parallel. Writer defines these methods for writing
characters and arrays of characters:

int write(int c)
int write(char cbuf[])
int write(char cbuf[], int offset, int length)

And OutputStream defines the same methods but for bytes:

int write(int c)
int write(byte cbuf[])
int write(byte cbuf[], int offset, int length)
All of the streams--readers, writers, input streams, and output streams--are automatically opened
when created. You can close any stream explicitly by calling its close method. Or the garbage
collector can implicitly close it, which occurs when the object is no longer referenced.

Stream classes
The following table lists java.io's streams and describes what they do. Note that many times,
java.io contains character streams and byte streams that perform the same type of I/O but for
different data types.
Type of I/O Byte Streams Character Streams
Memory ByteArrayInputStream CharArrayReader
ByteArrayOutputStream CharArrayWriter

StringBufferInputStream StringReader
StringWriter

Pipe
PipedInputStream PipedReader
PipedOutputStream PipedWriter

File FileInputStream FileReader


FileOutputStream FileWriter

Concatenation SequenceInputStream N/A

Object ObjectInputStream N/A


ObjectOutputStream
Serialization

Data DataInputStream N/A 


DataOutputStream
Conversion

Counting LineNumberInputStream LineNumberReader

Peeking Ahead PushbackInputStream PushbackReader

260
Printing PrintStream PrintWriter

Buffering BufferedInputStream BufferedReader


BufferedOutputStream BufferedWriter

Filtering FilterInputStream FilterReader


FilterOutputStream FilterWriter

Converting between Bytes and InputStreamReader


OutputStreamWriter
Characters

Use of streams

CharArrayReader, CharArrayWriter, ByteArrayInputStream,


ByteArrayOutputStream

Use these streams to read from and write to memory. You create these streams on an existing
array and then use the read and write methods to read from or write to the array.

StringReader, StringWriter, StringBufferInputStream

Use StringReader to read characters from a String in memory. Use StringWriter to write to a
String. StringWriter collects the characters written to it in a StringBuffer, which can then be
converted to a String.

StringBufferInputStream is similar to StringReader, except that it reads bytes from a


StringBuffer.

PipedReader, PipedWriter, PipedInputStream, PipedOutputStream

Implement the input and output components of a pipe. Pipes are used to channel the output from
one thread into the input of another.

FileReader, FileWriter, FileInputStream, FileOutputStream

Collectively called file streams, these streams are used to read from or write to a file on the
native file system.

SequenceInputStream

Concatenates multiple input streams into one input stream.

ObjectInputStream, ObjectOutputStream

Used to serialize objects.

DataInputStream, DataOutputStream

261
Read or write primitive data types in a machine-independent format.

LineNumberInputStream, LineNumberReader

Keeps track of line numbers while reading.

PushbackReader, PushbackInputStream

These input streams each have a pushback buffer. When reading data from a stream, it is
sometimes useful to peek at the next few bytes or characters in the stream to decide what to do
next.

PrintStream, PrintWriter

Contain convenient printing methods. These are the easiest streams to write to, so you will often
see other writable streams wrapped in one of these.

BufferedReader, BufferedWriter, BufferedInputStream,


BufferedOutputStream

Buffer data while reading or writing, thereby reducing the number of accesses required on the
original data source. Buffered streams are typically more efficient than similar nonbuffered
streams and are often used with other streams.

FilterReader, FilterWriter, FilterInputStream, FilterOutputStream

These abstract classes define the interface for filter streams, which filter data as it's being read or
written.

InputStreamReader, OutputStreamWriter

A reader and writer pair that forms the bridge between byte streams and character streams.

An InputStreamReader reads bytes from an InputStream and converts them to characters,


using the default character encoding or a character encoding specified by name.

An OutputStreamWriter converts characters to bytes, using the default character encoding or a


character encoding specified by name and then writes those bytes to an OutputStream.

You can get the name of the default character encoding by calling

System.getProperty("file.encoding").

262
The predefined Streams

The java.lang defines a class called System, which encapsulates several aspects of the run-time
environment. System also contains three predefined streams variables, in, out and err. These
fields are declared as public static within System.

System.out refers to standard output stream. By default this is the console. System.in refers to the
standard input, which is the keyboard by default. System.err refers to the standard error stream,
which also is the console by default. However, these streams may be redirected to any
compatible I/O device.

System.in is an object of the type InputStream. System.out and System.err are objects of type
PrintStream. These are byte streams, even though they typically are used to read and write
characters from and to the console.

11.2 Reading console input

In Java, console input is accomplished by reading from System.in. To obtain a character-based


stream that is attached to the console, you wrap System.in in a BufferedReader object, to create a
character stream. BufferedReader supports buffered input stream. The constructor of
BufferedReader used is shown below:

BufferedReader (Reader inputReader)

Here inputReader is the stream that is linked to the instance of BufferedReader that is being
created. Reader is an abstract class. InputStreamReader is its concrete sub-class, that converts
bytes to characters. To obtain InputStreamReader object, use the following constructor:

InputStreamReader (InputStream inputStream)

Because System.in refers to an object of type InputStream, it can be used for inputStream.

BufferedReader stdin =new BufferedReader(


new InputStreamReader(System.in));

The readLine() method is a member of BufferedReader class. Its general form is shown here:

String readLine() throws IOException

An example of reading an entire line of input from console

import java.io.*;

public class ConsoleInputDemo {


public static void main(String[] args) {
try {
BufferedReader stdin =new BufferedReader(

263
new InputStreamReader(System.in));
System.out.print("Enter a line:");
System.out.println(stdin.readLine());
}
catch(IOException e) {
System.out.println(e);
}
}
}

One example that reads from the console and prints the same string and terminates when an
empty string is entered.

import java.io.*;

public class Echo {


public static void main(String[] args) {
DataInputStream in = new DataInputStream(
new BufferedInputStream(System.in));
String s = null;
try {
while((s = in.readLine()).length() != 0) {
System.out.println(s);
}
// An empty line terminates the program
}
catch(IOException e) {
e.printStackTrace();
}
}
}

An example of reading characters

import java.io.*;
class BRRead {
public static void main(String args[]) throws IOException{
char c;
BufferedReader br = new BufferedReader (
new InputStreamReader(System.in));
System.out.println(“Enter characters , ‘q’ to quit:”);
//read characters
do {
c = (char) br.read();
System.out.print(c);
}
while( c != ‘q’);
}
}

264
11.3 Writing console output

This example prints a single character on the console. In this example we simply wrap the 16-bit
encoded OutputStreamWriter class around the usual System.out stream. The
OutputStreamWriter class only has a few basic write() methods. We can obtain many print() and
println() overloaded methods with the PrintWriter class.

import java.io.*;

public class SingleCharConsole16bit {


  public static void main(String f[]) {
    char c;
String s = “Hello”;
    // Wrap the System.out 8-bit stream with the 16-bit
    // output stream.
    OutputStreamWriter osw = new
                        OutputStreamWriter(System.out); 
    try {
      for( int i = 0; i< s.length(); i++) {
        c  = s.charAt(i);
        osw.write(c);
}
      osw.flush();
    }
catch (IOException ioe) {
        System.out.println( "IO error:" + ioe );
    }
  }
}

Another example that prints a String on the console using PrintWriter class. We take advantage
of the autoflushing switch in one of the PrintWriter constructors so that we do not have to
flush the buffers explicitly ourselves after every print.

import java.io.*;

public class StringOutput {


  public static void main(String f[]) {
   PrintWriter pw = new PrintWriter(System.out,true);
String s = “Hello”;
try {
      pw.println(s);
}
catch (IOException ioe) {
        System.out.println( "IO error:" + ioe );
}

265
}
}

11.4 System.out.printf()

The java.text.Format subclasses offer limited formatting capabilities and are rather clumsy
compared to the C language printf() function, which provides a wide range of formatting
options combined with output operation.

To satisfy the demands of programmers for such a facility and to facilitate the porting of C
programs to Java, J2SE 5.0 comes with the class java.util.Formatter, which can both format
numerical output into a string and send the string to a file or other destination

Numerical values are formatted according to format specifiers like those for the printf()
function in C.

Furthermore, J2SE 5.0 added a printf() method to the PrintStream class. So now you can use
System.out.printf() to send formatted numerical output to the console. It uses a
java.util.Formatter object internally.

The simplest of the overloaded versions of the method goes as

  printf (String format, Object... args)

The "..." indicates the varargs functionality. It allows a method to accept a variable number of
arguments. The arguments can be primitives as well as object references, e.g. the wrappers for
the primitives.

The format argument is a string in which you embed specifier substrings that indicate how the
arguments appear in the output. For example,

  double pi = Math.PI;
  System.out.printf ("pi = %5.3f%n", pi);

results in the console output

  pi = 3.142

The format string includes the specifier "%5.3f" that is applied to the argument. The ' %' sign
signals a specifier. The width value 5 requires at least five characters for the number, the
precision value 3 requires three places in the fraction, and the conversion symbol 'f' indicates a
decimal representation of a floating-point number.

A specifier needs at least the conversion character, of which there are several besides 'f'. Some of
the other conversions include

266
'd' - decimal integer
'o' - octal integer
'e' - floating-point in scientific notation

There are also special conversions for dates and times. The general form of the specifier includes
several optional terms:

  %[argument_index$][flags][width][.precision]conversion

The argument_index indicates to which argument the specifier applies. For example, %2$
indicates the second argument in the list. A flag indicates an option for the format. For example,
'+' requires that a sign be included and '0' requires padding with zeros. The width indicates the
minimum number of characters and the precision is the number of places for the fraction.

There is also one specifier that doesn't correspond to an argument. It is " %n" which outputs a line
break. A "\n" can also be used in some cases, but since "%n" always outputs the correct platform-
specific line separator, it is portable across platforms whereas"\n" is not.

The following program provides several examples of printf().

public class PrintfDemo


{
  /** Illustrate several output formats with printf() **/
  public static void main (String args[]) {

    double q = 1.0/3.0;
    // Print the number with 3 decimal places.

    System.out.printf ("1.0/3.0 = %5.3f %n", q);

    // Increase the number of decimal places


    System.out.printf ("1.0/3.0 = %7.5f %n", q);

    // Pad with zeros.


    q = 1.0/2.0;
    System.out.printf ("1.0/2.0 = %09.3f %n", q);

    // Scientific notation


    q = 1000.0/3.0;
    System.out.printf ("1000/3.0 = %7.2e %n", q);

    // More scientific notation


    q = 3.0/4567.0;
    System.out.printf ("3.0/4567.0 = %7.2e %n", q);

    // Negative infinity


    q = -1.0/0.0;
    System.out.printf ("-1.0/0.0 = %7.2e %n", q);

    q = 0.0/0.0;
    // NaN
    System.out.printf ("0.0/0.0 = %5.2e %n", q);

267
    // Multiple arguments
    System.out.printf ("pi = %5.3f, e = %5.4f %n", Math.PI, Math.E);

    double r = 1.1;
    // User the argument index to put the argument values into
    // different locations within th string.
    System.out.printf ("C = 2 * %1$5.5f * %2$4.1f, "+
                       "A = %2$4.1f * %2$4.1f * %1$5.5f %n",
                         Math.PI, r);
  }
} // class PrintfDemo

Output of this program:

1.0/3.0 = 0.333
1.0/3.0 = 0.33333
1.0/2.0 = 00000.500
1000/3.0 = 3.33e+02
3.0/4567.0 = 6.57e-04
-1.0/0.0 = -Infinity
0.0/0.0 = NaN
pi = 3.142, e = 2.7183
C = 2 * 3.14159 * 1.1, A = 1.1 * 1.1 * 3.14159

11.5 File class

A File class present in java.io can be used to obtain or manipulate the information associated
with a disk file, such as permissions, time, date and directory path, and to navigate subdirectory
hierarchies. A File object can represent either the name of a particular file or the names of a set
of files in a directory. We create an instance of the class by giving the name of the file (or
directory). There are several constructors:

The File class has the following constructors

File(String pathname);
// pathname could be file or a directory name
File(String dirPathname, String filename);
File(File directory, String filename);

The simplest is this (using Windows file-syntax):

File f = new File


("c:\\server\\classes\\hansen\\playground\\MyFile.class");

Or

File f = new File


("c:/server/classes/Hansen/playground/MyFile.class");

268
You may also use a relative file name like this:
File f = new File("hansen\\playground\\MyFile.class");

To use this format you'll have to know the "current user directory", which most often is where
the Java Virtual Machine is invoked. If you are in doubt you can get the name of the current user
directory like this:

String userdir = System.getProperty("user.dir");

Several methods are available for inspecting an instance of the File class. Some of the important
ones are:

Method Purpose
boolean exists() does the file exist?
boolean isFile() is it a file?
boolean isDirectory() … or a directory?
String[] list() return the names of all files and directories in a directory
String getName() get the file or directory's name
String getPath() get the file or directory's path

These methods are actually all we need in order to find all files and directories in a given
directory--all the way down to the last leaves in the directory tree

The File class is more than just a representation for an existing directory path, file, or group of
files. You can also use a File object to create a new directory or an entire directory path. You can
also look at the characteristics of files (size, last modification date, read/write), see whether a
File object represents a file or a directory, and delete a file. If the file mentioned is not found the
program simply exits.

import java.io.*;

public class FileExample {


public static void main(String[] args) {
File f = new File(args[0]);
if(f.exists()) {
System.out.println(f + " exists");
}
else {
return;
}
System.out.println(
"Absolute path: " + f.getAbsolutePath() +
"\n Can read: " + f.canRead() +
"\n Can write: " + f.canWrite() +
"\n getName: " + f.getName() +
"\n getParent: " + f.getParent() +
"\n getPath: " + f.getPath() +

269
"\n file size: " + f.length() +
"\n lastModified: " + f.lastModified());
if(f.isFile())
System.out.println("it's a file");
else if(f.isDirectory())
System.out.println("it's a directory");
File rname = new File(args[1]);
f.renameTo(rname);
File another = new File(args[2]);
System.out.println("deleting..." + another);
another.delete();
File makedir = new File(args[3]);
makedir.mkdir();
}
}

This program takes a filename as the first argument checks whether it exists. If yes then prints
the characteristics of the file else exits the program. Next it also checks whether the file object is
a file or directory. Then it renames the file as the second argument. The third argument specifies
the file to be deleted. The fourth argument is the name of the new directory that gets created.

The following program prints the list of all filenames and names of sub directories into the
current directory.

// Displays directory listing


import java.io.*;

public class DirList {


public static void main(String[] args) {
try {
File path = new File("."); // current directory
String[] list = path.list();
for(int i = 0; i < list.length; i++)
System.out.println(list[i]);
}
catch(Exception e) {
e.printStackTrace();
}
}
}

The following program prints the list of only .java files in the current directory

import java.io.*;

public class DirList {


public static void main(String[] args) {
try {
File path = new File("."); // current directory
String[] list = path.list(new DirFilter(“.java”));
for(int i = 0; i < list.length; i++)

270
System.out.println(list[i]);
}
catch(Exception e) {
e.printStackTrace();
}
}
}

class DirFilter implements FilenameFilter {


String afn;
DirFilter(String afn) { this.afn = afn; }
public boolean accept(File dir, String name) {
// Strip path information:
String f = new File(name).getName();
return f.indexOf(afn) != -1;
}
}

The interface FilenameFilter has only one method


boolean accept(File dir, String name);

It says that all this type of object does is provide a method called accept( ). The whole reason
behind the creation of this class is to provide the accept( ) method to the list( ) method so that
list( ) can call back accept( ) to determine which file names should be included in the list. Thus,
this technique is often referred to as a callback or sometimes a functor (that is, DirFilter is a
functor because its only job is to hold a method). Because list( ) takes a FilenameFilter object as
its argument, it means that you can pass an object of any class that implements FilenameFilter to
choose (even at run-time) how the list( ) method will behave. The purpose of a callback is to
provide flexibility in the behavior of code.

DirFilter shows that just because an interface contains only a set of methods, you’re not
restricted to writing only those methods. In this case, the DirFilter constructor is also created.

The accept( ) method must accept a File object representing the directory that a particular file is
found in, and a String containing the name of that file. You might choose to use or ignore either
of these arguments, but you will probably at least use the file name. Remember that the list( )
method is calling accept( ) for each of the file names in the directory object to see which one
should be included – this is indicated by the boolean result returned by accept( ).

To make sure that what you’re working with is only the name and contains no path information,
all you have to do is take the String object and create a File object out of it, then call getName( )
which strips away all the path information (in a platform-independent way). Then accept( ) uses
the String class indexOf( ) method to see if the search string afn appears anywhere in the name of
the file. If afn is found within the string, the return value is the starting index of afn, but if it’s not
found the return value is -1. Keep in mind that this is a simple string search and does not have
regular expression “wildcard” matching.

271
11.6 Using File Streams

File streams are perhaps the easiest streams to understand. The file streams-- FileReader,
FileWriter, FileInputStream, and FileOutputStream--each read or write from a file on the
native file system. You can create a file stream from a file name in the form of a string, a File
object, or a FileDescriptor object.

An Example of reading from a file using FileReader and printing the file contents on the console.
The filename is passed as a command line argument.

The FileReader class below accepts the filename as the argument and opens it for reading. If the
file is not found an exception of type FileNotFoundException is thrown. FileNotFoundException
is a checked exception and is a subclass of IOException. The readLine method of the
BufferedReader reads a String till the end of the line. It throws the checked IOException. Hence
both the exeptions are handled explicitly by using catch blocks.

import java.io.*;

public class FileReadDemo {


public static void main(String[] args) {
try {
BufferedReader in =new BufferedReader(new
FileReader(args[0]));
String s = new String();
String s2=””;
while((s = in.readLine())!= null)
s2 += s + "\n";
in.close();
}
catch(FileNotFoundException e) {
System.out.println(e);
}
catch(IOException e){
System.out.println(e);
}
}
}

The following program uses FileReader and FileWriter to copy the contents of a file named
farrago.txt into a file called outagain.txt:

import java.io.*;

public class Copy {


public static void main(String[] args) throws IOException {
File inputFile = new File("farrago.txt");
File outputFile = new File("outagain.txt");

FileReader in = new FileReader(inputFile);

272
FileWriter out = new FileWriter(outputFile);
int c;

while ((c = in.read()) != -1)


out.write(c);

in.close();
out.close();
}
}

This program is very simple. It opens a FileReader on farrago.txt and opens a FileWriter
on outagain.txt. The program reads characters from the reader as long as there's more input in
the input file and writes those characters to the writer. When the input runs out, the program
closes both the reader and the writer.

Here is the code that the Copy program uses to create a file reader:

File inputFile = new File("farrago.txt");


FileReader in = new FileReader(inputFile);

This code creates a File object that represents the named file on the native file system. File is a
utility class provided by java.io. The Copy program uses this object only to construct a file
reader on a file. However, the program could use inputFile to get information, such as its full
path name, about the file.

After you've run the program, you should find an exact copy of farrago.txt in a file named
outagain.txt in the same directory.

Remember that FileReader and FileWriter read and write 16-bit characters. However, most
native file systems are based on 8-bit bytes. These streams encode the characters as they operate
according to the default character-encoding scheme. You can find out the default character-
encoding by using System.getProperty("file.encoding"). To specify an encoding other
than the default, you should construct an OutputStreamWriter on a FileOutputStream and
specify the encoding.

A program that prints the line in a file myfile.txt

import java.io.*;

class FileOutputDemo
{
public static void main(String args[])
{
FileOutputStream out;
// declare a file output object
PrintStream p; // declare a print stream object
try
{

273
// Create a new file output stream
// connected to "myfile.txt"
out = new FileOutputStream("myfile.txt");
// Connect print stream to the output stream
p = new PrintStream( out , true);
p.println ("This is written to a file");
p.close();
}
catch (Exception e)
{
System.err.println ("Error writing to file");
}
}
}

Here is another version of the program, CopyBytes, which uses FileInputStream and
FileOutputStream instead of FileReader and FileWriter.

import java.io.*;
public class CopyBytes {
public static void main(String[] args) throws IOException {
File inputFile = new File("farrago.txt");
File outputFile = new File("outagain.txt");

FileInputStream in = new FileInputStream(inputFile);


FileOutputStream out = new FileOutputStream(outputFile);
int c;

while ((c = in.read()) != -1)


out.write(c);

in.close();
out.close();
}
}

An example to read from a file and print it on screen and also print the line numbers in front of
each line

import java.io.*;

class ReadFileDemo {
public static void main(String args[]) {
try {
FileReader fin = new FileReader(“file1.txt”);
LineNumberReader li =new LineNumberReader(fin);
BufferedReader in4 = new BufferedReader(li);
PrintWriter out1 = new PrintWriter(System.out,
true);
String s=null;
while((s = in4.readLine()) != null ) {

274
out1.println("Line " + li.getLineNumber() + s);
}
out1.close();
}
catch(EOFException e) {
System.out.println("End of stream");
}
}
}

An example of storing some content in a file and recovering it.

import java.io.*;

public class FileStore {


public static void main(String[] args) {
try {
DataOutputStream out2 = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("Data.txt")));
out2.writeDouble(3.14159);
out2.writeBytes("That was pi");
out2.close();

DataInputStream in5 = new DataInputStream(


new BufferedInputStream(
new FileInputStream("Data.txt")));
BufferedReader in5br = new BufferedReader(
new InputStreamReader(in5));
System.out.println(in5.readDouble());
System.out.println(in5br.readLine());
}
catch(EOFException e) {
System.out.println("End of stream");
}
}
}

Another program that reads from a file using FileInputStream one byte at a time but checks
whether the information is available before reading.

import java.io.*;

public class TestEOF {


public static void main(String[] args) {
try {
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("TestEof.java")));
while(in.available() != 0) {
System.out.print((char)in.readByte());

275
}
}
catch (IOException e) {
System.err.println("IOException");
}
}
}

Concatenating Files

The SequenceInputStream creates a single input stream from multiple input sources. This
example program, Concatenate, uses SequenceInputStream to implement a concatenation
utility that sequentially concatenates files file1.txt and file2.txt together.

This is the controlling class of the Concatenate utility:

import java.io.*;

public class Concatenate {


public static void main(String[] args) throws IOException {
FileInputStream fin1 = new FileInputStream(“file1.txt”);
FileInputStream fin2 = new FileInputStream(“file2.txt”);
SequenceInputStream s =
new SequenceInputStream(fin1,fin2);
int c;
while ((c = s.read()) != -1)
System.out.write(c);
s.close();
}
}

11.7 Scanning text with java.util.Scanner

J2SE 5.0 adds classes and methods that can make every day tasks easier to perform. You will see
how the newly added java.util.Scanner class makes it easier to read and parse strings and
primitive types using regular expressions.

Before the J2SE 5.0 release, you probably would have written code such as the following
TextReader class to read text from a file:

import java.io.*;

public class TextReader {


public static void main(String[] args) {
try {
File file = new File(“TextSample.txt”);
FileReader reader = new FileReader(file);
BufferedReader in = new
BufferedReader(reader);

276
String string = null;
while ((string = in.readLine()) != null) {
System.out.println(string);
}
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}

The basic approach in classes like this is to create a File object that corresponds to the actual file
on the hard drive. The class then creates a FileReader associated with the file and then a
BufferedReader from the FileReader. It then uses the BufferedFile reader to read the file one line
at a time.

To view the TextReader class in action, you need to create a document for the class to read and
parse. To create the document, save the following two lines of text in a file named
TextSample.txt in the same directory as TextReader:

Here is a small text file that you will


use to test java.util.scanner.

You should see the original file echoed back to you in standard output.

You can simplify the code in TextReader by using java.util.Scanner, a class that parses primitive
types and strings:

import java.io.*;
import java.util.Scanner;

public class TextScanner {


public static void main (String args[]) {
try {
File file = new File(“TextSample.txt”);
Scanner scanner = new Scanner(file);
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
scanner.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}

You should get the following output:

277
Here
is
a
small
text
file
that
you
will
use
to
test
java.util.scanner.

TextScanner creates a Scanner object from the File. The Scanner breaks the contents of the File
into tokens using a delimiter pattern, By default the delimiter pattern is whitespace. TextScanner
then calls the hasNext() method in Scanner. This method returns true if another token exists in
the Scanner's input, which is the case until it reaches the end of the file. The next() method
returns a String that represents the next token. So until it reaches the end of the file, TextScanner
prints the String returned by next() on a separate line.

You can change the delimiter that is used to tokenize the input, through the useDelimiter method
of Scanner. You can pass in a String or a java.util.regex.Pattern to the method. For example, you
can read the input one line at a time by using the newline character (\n) as a delimiter. Here is the
revised code for TextScanner that uses a newline character as the delimiter:

try {
Scanner scanner = new Scanner(new File(fileName));
scanner.useDelimiter
(System.getProperty("line.separator"));
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
scanner.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}

One more example of using Scanner


public class ScannerTest {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter int, double, word, line: ");
int a = input.nextInt();
double x = input.nextDouble();
String word = input.next();
// returns a String up to next whitespace
String line = input.nextLine();
// returns rest of line & eats the '\n'

278
System.out.println(a + ":" + x + ":" + word + ":" + line);
}
}

Sample output:
Enter int, double, word, line: -12 34.56 Great time had by all!
-12:34.56:Great: time had by all!

11.8 Redirecting Standard I/O

The methods in System class allow you to redirect the standard input, output, and error IO
streams using simple static method calls:

setIn(InputStream)
setOut(PrintStream)
setErr(PrintStream)

Redirecting output is especially useful if you suddenly start creating a large amount of output on
your screen and it’s scrolling past faster than you can read it. Redirecting input is valuable for a
command-line program in which you want to test a particular user-input sequence repeatedly.
Here’s a simple example that shows the use of these methods:

import java.io.*;

class Redirecting {
public static void main(String[] args) {
try {
BufferedInputStream in = new BufferedInputStream(
new FileInputStream("Redirecting.java"));
PrintStream out = new PrintStream(new BufferedOutputStream(
new FileOutputStream("test.out"),true));
System.setIn(in);
System.setOut(out);
System.setErr(out);
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
//reads from the file
String s;
while((s = br.readLine()) != null) {
System.out.println(s); // write it to another file
}
out.close(); // close file output stream
}
catch(IOException e) {
e.printStackTrace();
}
}
}

279
This program attaches standard input to a file, and redirects standard output and standard error to
another file.

11.9 Working with Random Access Files

The input and output streams in this lesson so far have been sequential access streams--streams
whose contents must be read or written sequentially. Although such streams are incredibly
useful, they are a consequence of a sequential medium, such as paper and magnetic tape. A
random access file, on the other hand, permits nonsequential, or random, access to a file's
contents. The RandomAccessFile class in the java.io package implements a random access
file.

The RandomAccessFile class implements both the DataInput and DataOutput interfaces and
therefore can be used for both reading and writing. RandomAccessFile is similar to
FileInputStream and FileOutputStream in that you specify a file on the native file system to
open when you create it. You can do this with a file name or a File object. When you create a
RandomAccessFile, you must indicate whether you will be just reading the file or also writing to
it. (You have to be able to read a file in order to write it.) The following code creates a
RandomAccessFile to read the file named farrago.txt:

new RandomAccessFile("farrago.txt", "r");

And this one opens the same file for both reading and writing:
new RandomAccessFile("farrago.txt", "rw");

After the file has been opened, you can use the common read or write methods defined in the
DataInput and DataOutput interfaces to perform I/O on the file.

RandomAccessFile supports the notion of a file pointer. The file pointer indicates the current
location in the file. When the file is first created, the file pointer is set to 0, indicating the
beginning of the file. Calls to the read and write methods adjust the file pointer by the number of
bytes read or written.

In addition to the normal file I/O methods that implicitly move the file pointer when the
operation occurs, RandomAccessFile contains three methods for explicitly manipulating the file
pointer.
 int skipBytes(int)--Moves the file pointer forward the specified number of bytes
 void seek(long)--Positions the file pointer just before the specified byte
 long getFilePointer()--Returns the current byte location of the file pointer

280
An example of using RandomAccessFile
 
import java.io.*;

class files03{
  public static void main(String[] args)
  {
    File junkFile = new File("junk.txt");
   System.out.println("Now open and read the file for random
access“);
    try{
   RandomAccessFile inData = 
new RandomAccessFile(junkFile,"rw");
      int temp;
System.out.println("Display the entire file as
characters.");
     while( (temp = inData.read()) != -1) {
         System.out.print((char)temp);
}
System.out.println("Now display four bytes interior to
the file.");
//Get current location of the file pointer.
      long filePointer = inData.getFilePointer();
  
      //Set the file pointer to a location interior to 
      // the file.
      inData.seek(filePointer-8);
         //Now read and display four bytes.
      for(int cnt = 0; cnt < 4; cnt++)
         System.out.print( (char)inData.read() );
        System.out.println(“\nNow write four bytes interior to
the file.");
filePointer = inData.getFilePointer();
   inData.seek(filePointer-4);
     for(int cnt = 0; cnt < 4; cnt++)
         inData.write('W'+cnt);
     System.out.println("Now display the entire file
again.");
      System.out.println("Note that four bytes have been
overwritten.");
//Note that it is necessary to reposition the file 
     // pointer to the beginning of the file.
    inData.seek(0);
    while( (temp = inData.read()) != -1)
        System.out.print((char)temp);
        inData.close();
    }
catch(IOException e){}
    System.out.println("\nEnd of program");
  }// end main
}//end class files03 definition

281
11.10 Filter Streams

The java.io package provides a set of abstract classes that define and partially implement filter
streams. A filter stream filters data as it's being read from or written to the stream. The filter
streams are FilterInputStream or FilterOutputStream, FilterInputStream, and
FilterOutputStream. A filter stream is constructed on another stream (the underlying stream).
The read method in a readable filter stream reads input from the underlying stream, filters it, and
passes on the filtered data to the caller. The write method in a writable filter stream filters the
data and then writes it to the underlying stream. The filtering done by the streams depends on the
stream. Some streams buffer the data, some count data as it goes by, and others convert data to
another form.

Most filter streams provided by the java.io package are subclasses of FilterInputStream and
FilterOutputStream and are listed here:
 DataInputStream and DataOutputStream
 BufferedInputStream and BufferedOutputStream
 LineNumberInputStream
 PushbackInputStream
 PrintStream (This is an output stream.)

The java.io package contains only one subclass of FilterReader: PushbackReader.

Using Filter Streams

To use a filter input or output stream, attach the filter stream to another input or output stream
when you create it. For example, you can attach a filter stream to the standard input stream, as in
the following code:

BufferedReader d = new BufferedReader(new DataInputStream(System.in));


String input;

while ((input = d.readLine()) != null) {


... //do something interesting here
}

Note that the readLine method has been deprecated in the DataInputStream; therefore we've
wrapped it in a BufferedReader.

How to Use DataInputStream and DataOutputStream

This page shows you how to use the java.io DataInputStream and DataOutputStream
classes. It features an example, DataIODemo, that reads and writes tabular data (invoices for
merchandise). The tabular data is formatted in columns separated by tabs. The columns contain
the sales price, the number of units ordered, and a description of the item. Conceptually, the data
looks like this, although it is read and written in binary form and is non-ASCII:

19.99 12 Java T-shirt

282
9.99 8 Java Mug

DataOutputStream, like other filtered output streams, must be attached to another


OutputStream. In this case, it's attached to a FileOutputStream that is set up to write to a file
named invoice1.txt:

DataOutputStream out = new DataOutputStream(


new FileOutputStream("invoice1.txt"));

Next, DataIODemo uses DataOutputStream's specialized write methods to write the invoice
data contained within arrays in the program according to the type of data being written:

for (int i = 0; i < prices.length; i ++) {


out.writeDouble(prices[i]);
out.writeChar('\t');
out.writeInt(units[i]);
out.writeChar('\t');
out.writeChars(descs[i]);
out.writeChar('\n');
}
out.close();

Next, DataIODemo opens a DataInputStream on the file just written:

DataInputStream in = new DataInputStream(


new FileInputStream("invoice1.txt"));

DataInputStream also must be attached to another InputStream; in this case, a


FileInputStream set up to read the file just written, invoice1.txt. Then DataIODemo just
reads the data back in using DataInputStream's specialized read methods.

try {
while (true) {
price = in.readDouble();
in.readChar(); //throws out the tab
unit = in.readInt();
in.readChar(); //throws out the tab
char chr;
desc = new StringBuffer(20);
char lineSep =
System.getProperty("line.separator").charAt(0);

while ((chr = in.readChar() != lineSep) {


desc.append(chr);
}

System.out.println("You've ordered " + unit +" units of "


+ desc + " at $" + price);
total = total + unit * price;
}

283
}
catch (EOFException e) { }
System.out.println("For a TOTAL of: $" + total);
in.close();

When all of the data has been read, DataIODemo displays a statement summarizing the order and
the total amount owed and then closes the stream.

Note the loop that DataIODemo uses to read the data from the DataInputStream. Normally, when
data is read, you see loops like this:

while ((input = in.read()) != null) {


. . .
}

The read method returns a value, null, which indicates that the end of the file has been reached.
Many of the DataInputStream read methods can't do this, because any value that could be
returned to indicate the end of file may also be a legitimate value read from the stream. For
example, suppose that you want to use -1 to indicate end of file. Well, you can't, because -1 is a
legitimate value that can be read from the input stream, using readDouble, readInt, or one of
the other methods that reads numbers. So DataInputStreams read methods throw an
EOFException instead. When the EOFException occurs, the while (true) terminates.

import java.io.*;

public class DataIODemo {


public static void main(String[] args) throws IOException {
// write the data out
DataOutputStream out = new DataOutputStream(new
FileOutputStream("invoice1.txt"));
double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };
int[] units = { 12, 8, 13, 29, 50 };
String[] descs = { "Java T-shirt",
"Java Mug",
"Duke Juggling Dolls",
"Java Pin",
"Java Key Chain" };

for (int i = 0; i < prices.length; i ++) {


out.writeDouble(prices[i]);
out.writeChar('\t');
out.writeInt(units[i]);
out.writeChar('\t');
out.writeChars(descs[i]);
out.writeChar('\n');
}
out.close();

// read it in again
DataInputStream in = new DataInputStream(new

284
FileInputStream("invoice1.txt"));

double price;
int unit;
StringBuffer desc;
double total = 0.0;

try {
while (true) {
price = in.readDouble();
in.readChar(); // throws out the tab
unit = in.readInt();
in.readChar(); // throws out the tab
char chr;
desc = new StringBuffer(20);
char lineSep =
System.getProperty("line.separator").charAt(0);
while ((chr = in.readChar()) != lineSep)
desc.append(chr);
System.out.println("You've ordered " +
unit + " units of " +desc + " at $" + price);
total = total + unit * price;
}
}
catch (EOFException e) {
}
System.out.println ("For a TOTAL of: $" + total);
in.close();
}
}

When you run the DataIODemo program you should see the following output:
You've ordered 12 units of Java T-shirt at $19.99
You've ordered 8 units of Java Mug at $9.99
You've ordered 13 units of Duke Juggling Dolls at $15.99
You've ordered 29 units of Java Pin at $3.99
You've ordered 50 units of Java Key Chain at $4.99
For a TOTAL of: $892.8800000000001

11.11 Object Serialization

Two streams in java.io-- ObjectInputStream and ObjectOutputStream-- are byte streams


and work like the other input and output streams. However, they are special in that they can read
and write objects.

The key to writing an object is to represent its state in a serialized form sufficient to reconstruct
the object as it is read. Thus reading and writing objects is a process called object serialization.
Object serialization is essential to building all but the most transient applications. You can use
object serialization in the following ways:

285
 Remote Method Invocation (RMI)--communication between objects via sockets
 Lightweight persistence--the archival of an object for use in a later invocation of the same
program.

You need to know about object serialization from two points of view. First, you need to know
how to serialize objects by writing them to an ObjectOutputStream and reading them in again
using an ObjectInputStream.

Serializing Objects

Reconstructing an object from a stream requires that the object first be written to a stream.

How to Write to an ObjectOutputStream

Writing objects to a stream is a straightforward process. For example, the following gets the
current time in milliseconds by constructing a Date object and then serializes that object:

FileOutputStream out = new FileOutputStream("theTime");


ObjectOutputStream s = new ObjectOutputStream(out);
s.writeObject("Today");
s.writeObject(new Date());
s.flush();

ObjectOutputStream must be constructed on another stream. This code constructs an


ObjectOutputStream on a FileOutputStream, thereby serializing the object to a file named
theTime. Next, the string Today and a Date object are written to the stream with the
writeObject method of ObjectOutputStream.

Thus, the writeObject method serializes the specified object, traverses its references to other
objects recursively, and writes them all. In this way, relationships between objects are
maintained.

ObjectOutputStream implements the DataOutput interface that defines many methods for writing
primitive data types, such as writeInt, writeFloat, or writeUTF. You can use these methods to
write primitive data types to an ObjectOutputStream.

The writeObject method throws a NotSerializableException if it's given an object that is not
serializable. An object is serializable only if its class implements the Serializable interface.

How to Read from an ObjectInputStream

Once you've written objects and primitive data types to a stream, you'll likely want to read them
out again and reconstruct the objects. This is also straightforward. Here's code that reads in the
String and the Date objects that were written to the file named theTime in the previous
example:

FileInputStream in = new FileInputStream("theTime");

286
ObjectInputStream s = new ObjectInputStream(in);
String today = (String)s.readObject();
Date date = (Date)s.readObject();

Like ObjectOutputStream, ObjectInputStream must be constructed on another stream. In this


example, the objects were archived in a file, so the code constructs an ObjectInputStream on a
FileInputStream. Next, the code uses ObjectInputStream's readObject method to read the
String and the Date objects from the file. The objects must be read from the stream in the same
order in which they were written. Note that the return value from readObject is an object that is
cast to and assigned to a specific type.

The readObject method deserializes the next object in the stream and traverses its references to
other objects recursively to deserialize all objects that are reachable from it. In this way, it
maintains the relationships between the objects.

ObjectInputStream stream implements the DataInput interface that defines methods for reading
primitive data types. The methods in DataInput parallel those defined in DataOutput for writing
primitive data types. They include methods such as readInt, readFloat, and readUTF. Use these
methods to read primitive data types from an ObjectInputStream.

Providing Object Serialization for Your Classes

An object is serializable only if its class implements the Serializable interface. Thus, if you
want to serialize the instances of one of your classes, the class must implement the
Serializable interface. The good news is that Serializable is an empty interface. That is, it
doesn't contain any method declarations; its purpose is simply to identify classes whose objects
are serializable.

Implementing the Serializable Interface

Here's the complete definition of the Serializable interface:


package java.io;
public interface Serializable {
// there's nothing in here!
};

Making instances of your classes serializable is easy. You just add the implements
Serializable clause to your class declaration like this:

public class MySerializableClass implements Serializable {


...
}

You don't have to write any methods. The serialization of instances of this class are handled by
the defaultWriteObject method of ObjectOutputStream. This method automatically writes
out everything required to reconstruct an instance of the class, including the following:
 Class of the object

287
 Class signature
 Values of all non-transient and non-static members, including members that refer to
other objects

You can deserialize any instance of the class with the defaultReadObject method in
ObjectInputStream.

Protecting Sensitive Information

When developing a class that provides controlled access to resources, you must take care to
protect sensitive information and functions. During deserialization, the private state of the object
is restored. For example, a file descriptor contains a handle that provides access to an operating
system resource. Being able to forge a file descriptor would allow some forms of illegal access,
since restoring state is done from a stream. Therefore the serializing runtime must take the
conservative approach and not trust the stream to contain only valid representations of objects.
To avoid compromising a class, you must provide either that the sensitive state of an object must
not be restored from the stream or that it must be reverified by the class.

Several techniques are available to protect sensitive data in classes. The easiest is to mark fields
that contain sensitive data as private transient. transient and static fields are not serialized or
deserialized. Marking the field will prevent the state from appearing in the stream and from
being restored during deserialization. Since writing and reading (of private fields) cannot be
superseded outside of the class, the class's transient fields are safe.

Particularly sensitive classes should not be serialized. To accomplish this, the object should not
implement either the Serializable interface.

Some classes may find it beneficial to allow writing and reading but to specifically handle and
revalidate the state as it is deserialized. The class should implement writeObject and readObject
methods to save and restore only the appropriate state. If access should be denied, throwing a
NotSerializableException will prevent further access.

An example of Serialization :

import java.io.*;

class MyClass implements Serializable {


String s;
int i;
double d;

public MyClass(String s, int i, double d) {


this.s = s; this.i = i; this.d = d;
}

public String toString() {


return “s =” + s + “ , i =” + i + “, d =” + d;
}

288
}

public class SerializationDemo {


try {
FileOutputStream fout = new
FileOutputStream(“serial”);
ObjectOutputStream os = new ObjectOutputStream(fout);
os.writeObject(“Hello”);
os.writeObject(new java.util.Date());
os.writeObject(new MyClass());
os.flush();
os.close();
}
catch(Exception e) {
System.out.println(e);
}
//object deserialization
try {
FileInputStream fin = new FileInputStream(“serial”);
ObjectInputStream is = new ObjectInputStream(fin);
String z = (String) is.readObject();
java.util.Date date = (java.util.Date)
is.readObject();
MyClass obj = (MyClass) is.readObject();
is.close();
System.out.println(s);
System.out.println(date);
System.out.println(obj);
}
catch(Exception e) {
System.out.println(e);
}
}

Summary

The System class provides three built in streams in java – in, out and err. All the api classes for
performing input/output in java are a part of java.io package. There are two category of I/O
classes – Byte stream and Character stream classes. There are separate classes that can be used
for reading and writing into files. The File class can be used to get the properties of the file.

289
Chapter 12 : API classes in java.lang package
By default, each Java application/applet has access to the java.lang package. Inside java.lang are
classes that represent primitive data types (such as int & char), as well as more complex classes.
It contains classes pertaining to strings, string buffers, threads, and even the System class from
which we obtain input and output streams.

12.1 Wrapper classes

Wrappers are used to enclose a simple datatype or a primitive object into an object. This is
sometimes necessary because:
 Simple datatypes are not part of the object hierarchy.
 Simple datatypes are passed by value and not by reference.
 Two methods can't refer to the same instance of a simple type.
 Some classes can only use members of another class and not a simple type.
 You can store a value of primitive type in a type-wrapper object whenever an object is
required.

There are eight wrapper classes – one for each primitive data type.

Primitive Wrapper
boolean   java.lang.Boolean
byte   java.lang.Byte
char   java.lang.Character
double   java.lang.Double
float   java.lang.Float
int   java.lang.Integer
long   java.lang.Long
short   java.lang.Short

All numeric wrapper classes are subclasses of the abstract class Number.

The following figure shows the class hierarchy for the Number classes provided by the
Java platform

290
BigInteger and BigDecimal extend the primitive data types to allow for arbitrary-precision
numbers (numbers that might not fit into any of the primitive data types). Note that whereas the
other classes are in the java.lang package, BigDecimal and BigInteger are in the java.math
package.

The Number class provides these methods

byte byteValue();
short shortValue();
int intValue();
long longValue();
float floatValue();
double doubleValue();

The classes define useful variables, such as MIN_VALUE and MAX_VALUE, that provide minimum
and maximum value in the range of the data type.

All wrapper objects are immutable. Once an object is created, the wrapped primitive value
cannot be changed. Wrapper classes are final and hence cannot be sub classed.

The Boolean class wrapper allows passing Boolean values (true and false) by reference. It
contains the constants TRUE and FALSE, which define true and false Boolean objects.

All the wrapper classes except Character have two constructors -- one that takes the primitive
value and another that takes the String representation of the value. For instance:

Integer i1 = new Integer(50);


Integer i2 = new Integer("50");

double d = 5.0;
     Double aD = new Double(d);

All wrapper classes have parseType methods eg parseInt(), parseShort, etc that take a String and
parse it into the appropriate type. The six parser methods are parseInt, parseDouble, parseFloat,
parseLong, parseByte, and parseShort. They take a String as the argument and convert it to the
corresponding primitive. They throw a NumberFormatException if the String is not properly
formed. For example,

double d = Double.parseDouble("4.23");

It can also take a radix(base) as the second argument:

int i = Integer.parseInt("10011110",2);

All wrapper classes (except Character) define a static method called valueOf(), which returns the
wrapper object corresponding to the primitive value represented by the String argument. For
example,

291
Integer I = Integer.valueOf("10011110",2);
Float f1 = Float.valueOf("1.5f");

Integer, Short, Byte and Long

The Integer and Long classes also have the static methods toBinaryString(), toOctalString() and
toHexString() which take an integer value and convert it to the appropriate String representation.

The toHexString returns a string which is a hex string version of the number. It has a natural
partner in the toBinaryString method which returns a string that represents the number in its
binary version. The following example code will output the strings 100 followed by 10.

public class NumberFormats{


public static void main(String argv[]){
System.out.println(Integer.toBinaryString(4));
System.out.println(Integer.toHexString(16));
}
}

Integer, and the longer form, Long, represent whole number values. Integers and Longs can be
interchanged through the longValue() and intValue() methods, and can also be converted to
floats and doubles using the floatValue() and doubleValue().

Integer my_integer = new Integer(256);


Long my_long = my_integer.longValue();

One more example of converting a wrapper object value to primitive data type

Integer i = new Integer(20);


byte b = i.byteValue();

Float and Double

The constructors for Float and Double are shown below:

Float (double num)


Float (float num)
Float (String s) throws NumberFormatException
Double (double num)
Double (String s) throws NumberFormatException

Apart from the constants MIN_VALUE and MAX_VALUE these classes also have other
constants like POSITIVE_INFINITY, NEGATIVE_INFINITY, and NaN and the following
methods to test a value

public boolean isNaN()


public static boolean isNaN(type value)
public boolean isInfinite()
public static boolean isInfinite(type value)

292
An example to show the use of isInfinite() and isNaN()

class InfNaN {
public static void main(String args[]) {
Double d1 = new Double(1/0.);
Double d2 = new Double(0/0.);
System.out.println(d1 + “ : ”+ d1.isInfinite() +
“,” + d1.isNaN());
System.out.println(d2 + “ : ”+ d2.isInfinite() +
“,” + d2.isNaN());
}
}

This program generates the following output:

Infinity : true, false


NaN : false, true

Both classes have methods to convert a value into a bit pattern or vice versa

public static int floatToIntBits(float value)


public static float intBitsToFloat(int bits)
public static long doubleToLongBits(double value)
public static double longBitsToDouble(long bits)

Floating point values, and the longer form, double, represent decimal (fractional) values. Floats
and doubles can be interchanged through the doubleValue() and floatValue() methods, and can
also be converted to integers and longs using the longValue() and intValue() methods. Its
important to remember, however, that there will be a loss of precision, as integers and longs
cannot retain the fractional component.

Float my_float = new Float(3.14);


Double my_double = new Double (my_float.doubleValue());

// Print out double (3.14)


System.out.println( "Double : " + my_double);

// Print out integer (3)


System.out.println( "Integer: " + my_double.intValue() );

Here's an example, called NumberDemo, that creates two Float objects and one Double object
and then uses compareTo and equals to compare them:.

public class NumberDemo {


public static void main(String args[]) {
Float floatOne = new Float(14.78f - 13.78f);
Float floatTwo = Float.valueOf("1.0");
Double doubleOne = new Double(1.0);
int difference = floatOne.compareTo(floatTwo);

293
if (difference == 0) {
System.out.println("floatOne is equal to floatTwo.");
}
else if (difference < 0) {
System.out.println("floatOne is less than floatTwo.");
}
else if (difference > 0) {
System.out.println("floatOne is greater than floatTwo.");
}
System.out.println("floatOne is " +
((floatOne.equals(doubleOne)) ? "equal" :
"not equal") + " to doubleOne.");
}
}

The output from this program might surprise you a little:

floatOne is equal to oneAgain.


floatOne is not equal to doubleOne.

Even though the values contained in floatOne and doubleOne are both numerically equal to 1,
they are considered unequal because the objects are of different types. The numeric type-wrapper
classes ( Byte, Integer, Double, Float, Long, and Short) each provide a class method named
valueOf that converts a string to an object of that type.

Character

The Character class constructor takes a char type element as an argument:


Character c = new Character('A');

To obtain the char value contained in a Character object, call charValue() shown here,

char charValue()

The Character class contains a large set of character comparison routines, in the form of static
methods.

static boolean isDigit( char c );


static boolean isLetter( char c );
static boolean isLetterOrDigit( char c );
static boolean isLowerCase( char c );
static boolean isUpperCase( char c );

static char toUpperCase( char c );


static char toLowerCase( char c );

A program is given below:

class IsDemo {

294
public static void main(String args[]) {
char a [] = {‘a’, ‘b’, ‘5’, ‘7’, ‘A’, ‘ ’};
for ( int i = 0; i < a.length ; i++) {
if(Character.isDigit(a[i]))
System.out.println(a[i]+ “is a digit”);
if(Character.isLetter(a[i]))
System.out.println(a[i]+ “is a letter”);
if(Character.isWhitespace(a[i]))
System.out.println(a[i]+ “is whitespace”);
if(Character.isUpperCase(a[i]))
System.out.println(a[i]+ “is uppercase”);
if(Character.isLowerCase(a[i]))
System.out.println(a[i]+ “is lowercase”);
}
}
}

Character contains two methods for returning the numeric value of a character in the various
number systems.

public static int digit(char ch, int radix)


public static int getNumber(char ch)

and one method to return the character value of a number

public static char forDigit(int digit, int radix)

12.2 Autoboxing/Unboxing of Wrappers

In the previous section on wrapper classes for primitive type values, we discussed how to create
an instance of a wrapper from a primitive value and conversely, how to obtain the primitive
value held by the wrapper. This involves a a certain amount of clumsy code.

For example, creating a Float object from a float primitive is straightforward:

  float primitive_float = 3.0f;


  Float wrapper_float = new Float (primitive_float);

Going the other direction, however, requires explicitly calling the floatValue() method on the
Float object:

  float primitive_float = wrapper_float.floatValue();

If you are dealing with a lot of instances of wrappers and conversions, you will thus need to deal
with a lot of method invocations. In J2SE 5.0, however, the code to create the wrapper object
allows for this much simpler form:

  Float wrapper_float = primitive_float;

295
Here, the "wrapping" is done automatically! There is no need to explicitly call the Float
constructor. This "wrapping" is called "autoboxing" in the sense that the primitive value is
automatically "boxed up" into the wrapper object. Autoboxing is available for all the
primitive/wrapper types.

Going the other way, from object type to primitive, is just as simple:

  Integer wrapper_integer = 5;
// primitive 5 autoboxed into an Integer
  int primitive_int = wrapper_integer;
// automatic unboxing Integer into int

These shortcuts simplify coding and reduce errors in J2SE 5.0. For example, they can even be
used in loop control and incrementing and decrementing operations.

int MAX = 100;       // a primitive int type


    Integer counter = 1; // an Integer type
    Integer sum = 0;     // ditto
    while (true) {
      sum += counter;
      if (counter == MAX) break;
      counter++;
    }
    System.out.println ("counter is now " + counter);
    System.out.println ("sum is now " + sum);

There is a lot of hidden autoboxing and unboxing going on in this simple-looking code. First, the
Integer types counter and sum are autoboxed from the primitive values 1 and 0. Then, in the
loop, they are unboxed to primitive values so the += operation can be applied and then reboxed
to their "native" Integer types.

To do the == comparison counter is unboxed so it can be compared with the int type MAX. If the
break does not apply, then counter is unboxed, operated on with ++, and then reboxed.

Autoboxing and unboxing work in a for loop as well:

  Integer sum = 0;
  for  (Integer counter=1; counter < MAX; counter++) {
        sum += counter;
  }

Note that both of these loops are likely to perform very slowly with all these autoboxing and
unboxing operations. An optimizing compiler might be able to avoid some of the autoboxing and
unboxing operations, but in general you should do long looping operations with primitive types
unless there is a very good reason to use a wrapper type.
Autoboxing and unboxing also work with Boolean and boolean types. For example,

296
  boolean one = true; // nothing new here
  Boolean two = true;
// autoboxing of primitive 'true' to Boolean type
  if (one && two) // auto unboxing do_something ();

Before 5.0, the if, while, and do-while statements all expected boolean expressions. Through the
use of unboxing, those flow control statements now also accept expressions that evaluate to
Boolean types. Similarly, the old switch statement expects a byte, short, int, or char type in Java
1.4 and below. With the addition of autoboxing in 5.0, switch now also accepts Byte, Short,
Integer, and Character types.

297
Autoboxing and Overloading

Autoboxing and unboxing can make method overloading interesting. Consider the two
overloaded methods shown here

  long method1 (long l) { return l+1; }


  long method1 (Integer i) { return i+2; }

If you call method1() with a primitive long parameter, then the first method1() is used. If you
call method1() with an Integer object parameter, then the second method1() is used. There is
nothing new there. But what happens if you call method1() with an int parameter? In J2SE 1.4
and below, the int is promoted to a long and the first method1() is used. With autoboxing, it is
conceivable that the int could be boxed into an Integer type and the second method1() used. That
might even be what you want to happen - it might make more sense to convert an int to an
Integer than to promote it to a long. While arguably reasonable, that is not what happens. The
general rule is, for compatibility reasons, the same behavior that applied in pre-5.0 versions must
continue to hold. The reason is that existing code cannot suddenly start behaving differently
when compiled and run under 5.0.

12.3 Math class

The Math class provides the important mathematical constants E and PI which are of type
double. All methods are of Math class are static. The Math class cannot be instantiated as it has a
private constructor. It cannot be subclassed as it is a final class. The Math class also provides
many useful math functions as methods.

Group Methods
Transcendental acos(x), asin(x), atan(x), atan2(x,y), cos(x), sin(x), tan(x)
Exponential exp(x), log(x), pow(x,y), sqrt(x)
Rounding abs(x), ceil(x), floor(x), max(x,y), min(x,y), rint(x), round(x)
Miscellaneous IEEEremainder(x,y), random(), toDegrees(x), toRadians(x)

Methods of java.lang.Math class

abs

It strips off the sign of a number and returns it simply as a number. Thus the following will
simply print out 99. If the number is not negative you just get back the same number.

System.out.println(Math.abs(-99));

Math.abs(1234.59): 1234.59
Math.abs(-0.0): 0.0
Math.abs(Float.NEGATIVE_INFINITY): Infinity
Math.abs(Float.NaN): NaN

298
If the value is equal to Integer.MIN_VALUE, in which case, it returns the value as a negative

Math.abs(Integer.MIN_VALUE): -2147483648

ceil

This method returns the next whole number up that is an integer. Thus if you pass

ceil(1.1)

it will return a value of 2.0. If you change that to

ceil(-1.1)

the result will be -1.0;

If the argument is NaN or infinity, returns the argument

Math.ceil( 9.01): 10.0


// counts up (away from zero)
Math.ceil(-9.01): -9.0 // counts up (towards zero)
Math.ceil(10): 10.0
Math.ceil(-0.03): -0.0
Math.ceil(Double.NaN): NaN

floor

This method returns the largest (closest to positive infinity) double value that is not greater than
the argument and is equal to a mathematical integer.

Here is a short program and its output

public class MyMat{


public static void main(String[] argv){
System.out.println(Math.floor(-99.1));
System.out.println(Math.floor(-99));
System.out.println(Math.floor(99));
System.out.println(Math.floor(-.01));
System.out.println(Math.floor(0.1));
}
}

And the output is

-100.0
-99.0
99.0
-1.0
0.0

299
If the argument is an integer, returns the argument. If the argument is NaN, infinity, negative or
positive zero, returns the argument.

max and min

min() returns the smallest of two values. max() returns the largest of two values.

Math.min(-1.5, 1.5): -1.5


Math.max(-1.5, 1.5): 1.5
Math.min(0.0, -0.0): -0.0
// zeros are not equivalent
Math.min(Float.NaN,Float.POSITIVE_INFINITY) : NaN

The following code illustrates how these methods work

public class MaxMin{


public static void main(String argv[]){
System.out.println(Math.max(-1,-10));
System.out.println(Math.max(1,2));
System.out.println(Math.min(1,1));
System.out.println(Math.min(-1,-10));
System.out.println(Math.min(1,2));
}
}

Here is the output

-1
2
1
-10
1

round

public static long round(double a)


public static int round(float a)

Rounds to the nearest integer. So, if the value is more than half way towards the higher integer,
the value is rounded up to the next integer. If the number is less than this the next lowest integer
is returned. So for example if the input to round is x then :

2.0 <= x < 2.5. then Math.round(x)==2.0


2.5 <= x < 3.0 the Math.round(x)==3.0

If the argument is not a number, returns zero. if the argument is a negative infinity or less than
the MIN_VALUE for the type, returns the MIN_VALUE. If the argument is a positive infinity or
greater than the MAX_VALUE for the type, returns the MAX_VALUE. If the value is
Float.MAX_VALUE the round method returns Integer.MAX_VALUE

300
Math.round( 1.5): 2
Math.round(-1.5): -1
Math.round(Float.NaN): 0
Math.round(Float.NEGATIVE_INFINITY): -2147483648
Math.round(Double.POSITIVE_INFINITY): 9223372036854775807
Math.round(Float.MAX_VALUE): 2147483647
(Float.MAX_VALUE is 3.4028235E38)

Here are some samples with output

System.out.println(Math.round(1.01));
System.out.println(Math.round(-2.1));
System.out.println(Math.round(20));

Output:

1
-2
20

rint

It rounds to the closest integer. If integers are equidistant, favours the even integer.

Math.rint( 5.5): 6.0


Math.rint(-5.5): -6.0
Math.rint( 5.49): 5.0
Math.rint(-5.49): -5.0

random

Returns a random number between 0.0 and 1.0.

Unlike some random number system Java does not appear to offer the ability to pass a seed
number to increase the randomness. Often a program will want to produce a random number
between say 0 and 10 or 0 and 100. The following code combines math code to produce a
random number between 0 and 100.

System.out.println(Math.round(Math.random()*100));

sqrt

This method returns the positive square root of a number. It returns NaN if argument is negative

Math.sqrt(45): 6.708203932499369
Math.sqrt(-45): NaN

301
IEEEremainder

This method calculates the remainder as defined by IEEE-754. The remainder operator, %,
makes values symmetric around zero ie negative and positive values return corresponding
remainders

7 % 2.5 : 2.0
-7 % 2.5 : -2.0

Math.IEEEremainder keeps resulting values y units apart

Math.IEEEremainder( 7, 2.5): -0.5


Math.IEEEremainder(-7, 2.5): 0.5

pow

This method returns the first argument raised to the power of the second argument.

Math.pow(2,2) 4.0

log

log() returns the natural logarithm of the argument. If the argument is less than zero, returns
NaN. If the argument is positive infinity, returns positive infinity. If the argument is -0.0 or 0.0,
returns negative infinity.

Math.log(10): 2.302585092994046
Math.log(-10): NaN
Math.log(0.0): -Infinity

exp

exp() returns e to the power of the argument. If the argument is NaN, returns NaN. If the
argument is positive infinity, returns positive infinity. If the argument is negative infinity, returns
positive zero.

Math.exp(5): 148.4131591025766
Math.exp(Float.NaN): NaN
Math.exp(Float.POSITIVE_INFINITY): Infinity
Math.exp(Float.NEGATIVE_INFINITY): 0.0

An example program using Math class:

public class ExponentialDemo {


public static void main(String[] args) {
double x = 11.635;
double y = 2.76;
System.out.println("The value of e is " + Math.E);

302
System.out.println("exp(" + x + ") is " + Math.exp(x));
System.out.println("log(" + x + ") is " + Math.log(x));
System.out.println("pow(" + x + ", " + y + ") is " +
Math.pow(x, y));
System.out.println("sqrt(" + x + ") is " + Math.sqrt(x));
}
}

Here's the output you'll see when you run ExponentialDemo:

The value of e is 2.71828


exp(11.635) is 112984
log(11.635) is 2.45402
pow(11.635, 2.76) is 874.008
sqrt(11.635) is 3.41101

The trigonometric methods

All results are returned in radians.

Method Description
Returns the sine of the specified double value. If the result is
NaN or infinity, returns NaN. if the result is negative zero,
double sin(double) returns -0.0

Math.sin(90) 0.8939966636005579
Returns the cosine of the specified double value. If the result is
double cos(double) NaN or infinity, returns NaN.

Math.cos(90) -0.4480736161291701
double tan(double) Returns the tangent of the specified double value. If the result
is NaN or infinity, returns NaN. If the result is negative zero,
returns -0.0

303
Math.tan(90) -1.995200412208242
Returns the arc sine of the specified double value. It returns a
value between -PI/2 and PI/2. If the result is NaN or absolute
double asin(double) value is greater than 1, returns NaN. If the result is negative
zero, returns -0.0.

Math.asin(-0) 0.0
Returns the arc cosine of the specified double value. It returns
double acos(double) a value between 0.0 and PI. If the result is NaN or absolute
value is greater than 1, returns NaN.
Math.acos(-0) 1.5707963267948966
Returns the arc tangent of the specified double value. It returns
a value between -PI/2 and PI/2. If the result is NaN, returns
double atan(double) NaN. If the result is negative zero, returns -0.0
Math.atan(90) 1.5596856728972892

double atan2(double)
Converts rectangular coordinates (b, a) to polar (r, theta).

Converts the argument to degrees or radians as indicated by the


double toDegrees(double)
method name.
double toRadians(double) Math.toRadians(90) 1.5707963267948966
Math.toDegrees(Math.PI/2) 90.0

An example of using trigonometric functions

public class TrigonometricDemo {


public static void main(String[] args) {
double degrees = 45.0;
double radians = Math.toRadians(degrees);
System.out.println("The value of pi is " + Math.PI);
System.out.println("The sine of " + degrees + " is " +
Math.sin(radians));
System.out.println("The cosine of " + degrees + " is " +
Math.cos(radians));
System.out.println("The tangent of " + degrees + " is " +
Math.tan(radians));
System.out.println("The arc sine of " +
Math.asin(radians) + " is " +
Math.toDegrees(Math.asin(Math.sin(radians))) +
“degrees");
System.out.println("The arc cosine of " +
Math.cos(radians)+ " is " +
Math.toDegrees(Math.acos(Math.cos(radians))) + “degrees");
System.out.println("The arc tangent of” +Math.tan(radians)
+ " is " + Math.toDegrees(Math.atan(Math.tan(radians))) +

304
" degrees");
}
}

The output of this program is as follows:

The value of pi is 3.141592653589793


The sine of 45.0 is 0.8060754911159176
The cosine of 45.0 is -0.5918127259718502
The tangent of 45.0 is -1.3620448762608377
The arc sine of 45.0 is NaN
The arc cosine of 45.0 is NaN
The arc tangent of 45.0 is 1.570408475869457

12.4 System class

The System class provides access to the native operating system's environment through the use of
static methods. As an example System.currentTimeMillis() retrieves the system clock setting (as
a long, in milliseconds counted from January 1, 1970). Some of the available methods are:

currentTime()
freeMemory()
totalMemory()
exit(int status)
exec(String cmd)
getOSName()
arraycopy(src[], srcpos, dest[], destpos, len)

The System class maintains a set of properties, key/value pairs, that define traits or attributes of
the current working environment. When the runtime system first starts up, the system properties
are initialized to contain information about the runtime environment. including information about
the current user, the current version of the Java runtime, and even the character used to separate
components of a filename.

Here is a complete list of the system properties you get when the runtime system first starts up
and what they mean:

Key Meaning
"file.separator" File separator (for example, "/")

"java.class.path" Java classpath


"java.class.version" Java class version number
"java.home" Java installation directory
"java.vendor" Java vendor-specific string
"java.vendor.url" Java vendor URL
"java.version" Java version number

305
"line.separator" Line separator

"os.arch" Operating system architecture


"os.name" Operating system name
"os.version" Operating system version

"path.separator" Path separator (for example, ":")

"user.dir" User's current working directory


"user.home" User home directory
"user.name" User account name

Your Java programs can read or write system properties through several methods in the System
class. You can use a key to look up one property in the properties list, or you can get the whole
set of properties all at once. You can also change the set of system properties completely. For
example, you can use the method

System.getProperty(“file.separator”);

to get the file separator character of the OS.

An example to get the user name :

class UserNameTest {
public static void main(String[] args) {
String name;
name = System.getProperty("user.name");
System.out.println(name);
}
}

The System class also provides very basic io streams for console read, write and error operations.
System.in.read() reads a keystroke and returns an integer value. System.out.println(string)
displays a string to the current output device.

Use of some methods of System class

To terminate an application

// No errors
int errorCode = 0;

// An error occurred
errorCode = -1;

306
// Terminate
System.exit(errorCode);

To compute elapsed time

// Get current time


long start = System.currentTimeMillis();

// Do something ...

// Get elapsed time in milliseconds


long elapsedTimeMillis = System.currentTimeMillis()-start;

// Get elapsed time in seconds


float elapsedTimeSec = elapsedTimeMillis/1000F;

// Get elapsed time in minutes


float elapsedTimeMin = elapsedTimeMillis/(60*1000F);

// Get elapsed time in hours


float elapsedTimeHour = elapsedTimeMillis/(60*60*1000F);

// Get elapsed time in days


float elapsedTimeDay = elapsedTimeMillis/(24*60*60*1000F);

12.5 Runtime class

The Runtime class encapsulates the runtime environment. You cannot instantiate a Runtime
object. You can get the reference of the current Runtime object by calling the getRuntime()
method. Once you obtain the reference to the current runtime you can call several methods that
control the state and behavior of JVM.

Runtime can be used to get the size of the heap. The heap is the area in memory in which objects
are created.

// Get current size of heap in bytes


long heapSize = Runtime.getRuntime().totalMemory();

// Get maximum size of heap in bytes.


//The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Get amount of free memory within the heap in bytes.


//This size will increase
// after garbage collection and decrease as new objects
//are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();

307
To execute an application, you can use the exec method of the Runtime object

class ExecDemo {
public static void main(String args[]) {
Runtime r = Runtime.getRuntime();
Process p = null;
try {
p = r.exec(“notepad”);
}
catch(Exception e) {
System.out.println(e);
}
}
}

The abstract class Process encapsulates a process- that is a program in execution. You can kill
the subprocess created by the exec() method by destroy() method. The waitFor() method causes
your program to wait until the subprocess finishes. The exitValue() returns the value returned by
the subprocess when it is finished. This is typically 0 if no problems occur.

class ExecDemoFini {
public static void main(String args[]) {
Runtime r = Runtime.getRuntime();
Process p = null;
try {
p = r.exec(“notepad”);
p.waitFor();
}
catch(Exception e) {
System.out.println(e);
}
System.out.println(“Notepad returned :”
+p.exitValue());
}
}

12.6 Class class

Class encapsulates the run-time state of an object or interface. Objects of type Class are created
automatically, when classes are loaded. You cannot explicitly declare a Class object. Generally,
you obtain a Class object by calling the getClass() method defined by Object.

The methods defined by Class are often useful in situations where runtime type information
about an object is required. An example of using Class is as follows:

class X {
int a;
float b;

308
}

class Y extends X {
double c;
}

class RTTI {
public static void main(String args[]) {
X x = new X();
Y y = new Y();
Class clObj = x.getClass(); //get class reference
System.out.println(“x is the object of type:”+
clObj.getName());
clObj = y.getClass();
System.out.println(“y is the object of type:”
+clObj.getName());
clObj = clObj.getSuperclass();
System.out.println(“y’s superclass is :”+
clObj.getName());
}
}

The output of the program is as follows:

x is object of type : X
y is obtect of type : Y
y’s superclass is X

Summary

You use an instance of one of the Number classes—Byte, Double, Float, Integer, Long, and
Short—to contain a number of primitive type.

The Number classes include class methods and constants, which are useful in a variety of ways.
The MIN_VALUE and MAX_VALUE constants contain the smallest and largest values that can be
contained by an object of that type. The byteValue, shortValue, and similar methods convert
one numeric type to another. The valueOf method converts a string to a number, and the
toString method converts a number to a string.

The Math class contains a variety of class methods for performing mathematical functions. This
class includes the trigonometric functions, such as computing sine, cosine, and so on. Math also
includes functions for logarithm calculations, as well as basic arithmetic functions, such as
rounding. Finally, Math contains a method, random, for generating random numbers.

Questions

1. class JJF1 {

309
public static void main (String args[]) {
System.out.print(Byte.MIN_VALUE+",");
System.out.print(Byte.MAX_VALUE);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 0,255 d.  Prints: -128,127 g.  None of the above
b.  Prints: 0,256 e.  Compile-time error
c.  Prints: -127,128 f.  Run-time error

2. class JJF2 {
public static void main (String args[]) {
System.out.print(Short.MIN_VALUE+",");
System.out.print(Short.MAX_VALUE);
}
}

What is the result of attempting to compile and run the program?

a.  Prints: -32767,32768 d.  Prints: 0,65536 g.  None of the above
b.  Prints: -32768,32767 e.  Compile-time error
c.  Prints: 0,65535 f.  Run-time error

3. class JJF3 {
public static void main(String args[]) {
System.out.print(Integer.toBinaryString(Byte.MAX_VALUE)+",");
System.out.print(Integer.toOctalString(Byte.MAX_VALUE)+",");
System.out.print(Integer.toString(Byte.MAX_VALUE)+",");
System.out.print(Integer.toHexString(Byte.MAX_VALUE));
}
}

What is the result of attempting to compile and run the program?

a.  Prints: 1111111,177,127,7f d.  Run-time error


b.  Prints: 11111111,377,256,ff e.  None of the above
c.  Compile-time error

4. class JJF4 {
public static void main(String args[]) {
System.out.print(Long.toHexString(Byte.MAX_VALUE)+",");
System.out.print(Long.toHexString(Character.MAX_VALUE)+",");
System.out.print(Long.toHexString(Short.MAX_VALUE));
} }

310
What is the result of attempting to compile and run the program?

a.  Prints: f,ff,7f d.  Prints: ff,ffff,ffff g.  Compile-time error


b.  Prints: f,ff,ff e.  Prints: 7fff,ffffff,7fffff h.  Run-time error
c.  Prints: 7f,ffff,7fff f.  Prints: ffff,ffffff,ffffff i.  None of the above

5. class JJF5 {
public static void main(String args[]) {
System.out.print(Integer.toHexString(Integer.MIN_VALUE)+",");
System.out.print(Integer.toHexString(Integer.MAX_VALUE));
}}

What is the result of attempting to compile and run the program?

a.  Prints: 0000,ffff d.  Prints: 8000,7fff g.  Compile-time error


b.  Prints: 00000000,ffffffff e.  Prints: 7fffffff,80000000 h.  Run-time error
c.  Prints: 7fff,8000 f.  Prints: 80000000,7fffffff i.  None of the above

6. class Green {
public static void main (String args[]) {
int[] i = null; // 1
Cloneable c = i; // 2
i = (int [])c; // 3
}
}

What is the result of attempting to compile and run the program?

a.  Compile-time error at line 1. e.  Compile-time error at line 3.


b.  Run-time error at line 1. f.  Run-time error at line 3.
c.  Compile-time error at line 2. g.  None of the above
d.  Run-time error at line 2.

7. class EBH011 {
public static void main (String[] args) {
float a = Float.POSITIVE_INFINITY;
double b = Double.POSITIVE_INFINITY;
double c = Double.NaN;
System.out.print((a == b)+","+(c == c)+","+(c != c));
}
}

What is the result of attempting to compile and run the program?

a.  Prints: false,false,false c.  Prints: false,true,false e.  Prints: true,false,false


b.  Prints: false,false,true d.  Prints: false,true,true f.  Prints: true,false,true

311
g.  Prints: true,true,false
h.  Prints: true,true,true
i.  Run-time error
j.  Compile-time error
k.  None of the above

312
313
Chapter 13 : Utility & Legacy classes
These classes are a part of java.util package. There are five legacy classes in Java – Vector,
Stack, Properties, Hashtable and Dictionary. There is one legacy interface called Enumeration.

13.1 Enumeration interface

An object that implements the Enumeration interface generates a series of elements, one at a
time. Successive calls to the nextElement method return successive elements of the series.

Methods are provided to enumerate through the elements of a vector, the keys of a hashtable, and
the values in a hashtable. Enumerations are also used to specify the input streams to a
SequenceInputStream.

Methods of Enumeration interface

public abstract boolean hasMoreElements()

Tests if this enumeration contains more elements. Returns true if this enumeration contains
more elements; false otherwise.

public abstract Object nextElement()

Returns the next element of this enumeration. Throws NoSuchElementException if no more


element exists.

13.2 Vector class

The Vector class provides the capability to implement a growable array of objects. It is similar to
the ArrayList in the Collection Framework, but with two differences: Vector is synchronized and
it contains many legacy methods that are not part of the collections framework. Vector extends
AbstractList and implements the List interface of the Collections Framework. Here are Vector
constructors:

Vector()
Vector(int size)
Vector(int size, int incr)
Vector(Collection c)

The first form creates a default vector, which has an initial size of 10. The second form creates a
vector whose initial capacity is specified by size. The third form creates a vector whose initial
capacity is specified by size and whose increment is specified by incr. The increment specifies
the number of elements to allocate each time that a vector is resized upward. The fourth form
creates a vector that contains the elements of Collection c.

314
All vectors start with an initial capacity. After the initial capacity is reached the next time that
you attempt to store an object in the vector, the vector automatically allocates space for that
object plus extra room for additional objects. By allocating more than just the required memory,
the vector reduces the number of allocations that must take place. This reduction is important,
because allocations are costly in terms of time. The amount of extra space allocated during each
reallocation is determined by the increment that you specify when you create the vector. If you
don’t specify an increment, the vector’s size is doubled by each allocation cycle.

Vector defines these protected data members:

int capacityIncrement;
int elementCount;
Object elementData[];

The increment value is stored in capacityIncrement. The number of elements currently in the
vector is stored in elementCount. The array that holds the vector is stored in elementData.

You can add an element to the Vector by calling addElement(). To obtain the element at a
specific location call elementAt(). To obtain the first element in the vector call firstElement(). To
retrieve the last element, call lastElement(). You can obtain the index of an element using
indexOf() and lastIndexOf(). To remove an element, call removeElementAt(). The following
program uses a Vector to store various types of numeric objects. It demonstrates several of the
legacy methods defined by Vector. It also demonstrates the Enumeration interface.

import java.util.*;
class VectorDemo {
public static void main(String args[]) {
//initial size is 3, increment is 2
Vector v = new Vector();
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 4 additions :” +
v.capacity());
v.addElement(new Double(5.45));
System.out.println(“Current capacity:”+v.capapcity());
v.addElement(new Double(6.08));
v.addElement(new Integer(7));
System.out.println(“Current capacity:”+v.capapcity());
v.addElement(new Double(9.4));
v.addElement(new Integer(10));
System.out.println(“Current capacity:”+v.capapcity());
v.addElement(new Integer(11));
v.addElement(new Integer(12));
System.out.println(“First element:”+
(Integer)v.firstElement());

315
System.out.println(“Last element:”+
(Integer)v.lastElement());
if(v.contains(new Integer(3)) {
System.out.println(“Vector contains 3”);
}
//enumerate the elements in the vector
Enumeration vEnum = v.elements();
System.out.println(“\nElements in vector:”);
while(vEnum.hasMoreElements()) {
System.out.print(vEnum.nextElement() + “ ”);
}
System.out.println();
}
}

The output of this program is shown here:

Initial size: 0
Initial capacity : 0
Capacity after 4 additions: 5
Current Capacity: 5
Current Capacity: 7
Current Capacity: 9
First element: 1
Last element: 12
Vector contains: 3

Elements in vector:
1 2 3 4 5.45 6.08 7 9.4 10 11 12

13.3 Stack class

Java's Stack class extends the Vector class. A Stack represents a Collection of objects that are in
LIFO (Last In First Out Order). The Stack class provides operations that allow testing for zero
elements, inspection of it's top most element, removal of it's top most element, and the addition
of elements. Some of the methods of Stack are shown below:

boolean empty()
Tests if this stack is empty.
Object peek()
Looks at the object at the top of this stack without removing it from the stack.
Object pop()
Removes the object at the top of this stack and returns that object as the value of this
function.
Object push(Object item)
Pushes an item onto the top of this stack.

316
int search(Object o)
Returns the 1-based position where an object is on this stack.

An example of using Stack

import java.util.*;
class StackDemo {
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, 42);
showpush(st, 66);
showpush(st, 99);
showpop(st);
showpop(st);
showpop(st);
try {
showpop(st);
}
catch(EmptyStackException e) {
System.out.println(“Empty Stack”);
}
}
}

The following the output produced by the program

stack : [ ]
push (42)
stack : [42]
push (66)
stack : [42, 66]
push (99)
stack : [42, 66, 99]
pop -> 99
stack : [42, 66]
pop -> 66
stack : [42]

317
pop -> 42
stack : [ ]
pop -> empty stack

13.4 Dictionary class

The Dictionary class is an abstract class, which maps keys to values. Any object can be used as a
key and/or value. Given a key and value, you can store the value in a Dictionary object. Once the
value is stored, you can retrieve it by using its key. Dictionary is classified as obsolete, because it
is superceded by Map in the Collections Framework.

The Dictionary class defines some abstract methods. To add a key and a value, the put() method
is used. Use get() to retrieve the value of a given key. The keys and values can each be returned
as an Enumeration by the keys() and elements() methods, respectively. The size() method returns
the number of key/value pairs stored in a dictionary and isEmpty() returns true when the
dictionary is empty. You can use the remove() method to delete a key/value pair.

13.5 Hashtable class

A hash table is conceptually a contiguous section of memory with a number of addressable


elements, in which data can be quickly inserted, deleted and found. Hash tables represent a
sacrifice of memory for the sake of speed - they are certainly not the most memory efficient
means of storing data, but they provide very fast lookup times. Hash tables are a common means
of organising data, so the designers of the Java programming language have provided a number
of classes for easily creating and manipulating instances of hash tables.

Hashtable is the class which provides hash tables in Java. Hashtable inherits directly from
Dictionary and implements the Map, Cloneable and Serializable interfaces.

A hash table can only store objects that override the hashCode() and equals() methods that are
defined by the Object.

The Hashtable constructors are shown below:

Hashtable()
Hashtable(int size)
Hashtable(int size, float fillRatio)
Hashtable(Map m)
The first version is the default constructor. The second version creates a hash table that has an
initial space specified by size. The third version creates a hash table that has an initial size
specified by size and a fill ratio specified by fillRatio. This ratio must be between 0.0 and 1.0,
and it determines how full the hash table can be before it is resized upward. Specifically, when
the number of elements is greater than the capacity of hashtable multiplied by its fill ratio, the
hash table is expanded. If you do not specify a fill ratio, then 0.75 is used. Finally, the fourth
version creates a hash table that is initialized with elements in m. The capacity of the hash table
is set to twice the number of elements in m. The default load factor of 0.75 is used.

318
If you want to allocate more space for your hash table before the load factor reaches the specified
value then use the rehash() method like this:

ht.rehash();

An example of using Hashtable

import java.util.*;

class HTDemo {
public static void main(String args[]){
Hashtable balance = new Hashtable();
String str;
double bal;

balance.put(“John Doe”, new Double(3434.34));


balance.put(“Tom Smith”, new Double(123.22));
balance.put(“Jane Baker”, new Double(1378.00));
balance.put(“Todd Hall”, new Double(99.22));
balance.put(“Ralph Smith”, new Double(-19.08));

//Show all balances in hash table


Enumeration names = balance.keys();
while(names.hasMoreElements()) {
str = (String)names.nextElement();
System.out.println(str + “ : ” +
balance.get(str));
}
System.out.println();
//Deposit 1,000 into Jane Doe’s account
bal = (Double)balance.get(“John Doe”)
balance.put(“John Doe”,new Double(bal + 1000));
System.out.println(“John Doe’s new balance :” +
balance.get(“John Doe”));
}
}

13.6 Properties class

Properties is a subclass of Hashtable. It is used to maintain lists of values in which the key is a
String and the value is also a String. The Properties class is used by many other Java classes. For
example, it is the type of object returned by System.getProperties() when obtaining
environmental values.

Properties defines the following instance variables:

Properties default;

319
This variable holds a default property list associated with a Properties object. Properties defines
these constructors

Properties ()
Properties (Properties propDefault)

The first version creates a Properties object that has no default values. The second creates an
object that uses propDefault for its default values. In both cases the property list is empty.

One useful capability of Properties class is that you can specify a default property that will be
returned if no value is associated with a certain key. For example, a default value can be
specified along with the key in the getProperty() method – such as getProperty(“name”, “default
value”). If the “name” value is not found, then “default value” is returned. When you construct a
Properties object, you can pass another instance of Properties to be used as the default properties
for the new instance. In this case, if you call getProperty(“foo”) on a given Properties object, and
“foo”, does not exist, Java looks for “foo” in the default Properties object. This allows for
arbitrary nesting of levels of default properties.

Methods

Object setProperty(String key, String value)


String getProperty(String key)
String getProperty(String key, String defaultValue)
Enumeration propertyNames()

void load(InputStream in)


void store(OutputStream out, String header)

To create and put values in a Properties table

This example creates a new Properties table and assigns a string value to four different keys.

Properties props = new Properties();


props.setProperty("recursiveSearch", "true");
props.setProperty("noCopyPattern", "*.$$$");
props.setProperty("maxLevel", "7");
props.setProperty("fileName", "C:\temp\work.html");

To store a Properties table in a file

Use the Properties store(OutputStream, String) method. It will write the properties to the output
stream, with a header line from the String parameter. Assuming you have variables and an
OutputStream like:

OutputStream propOut = new FileOutputStream(


new File("props.stat"));
props.store(propOut, "Macro Processor Properties");

320
To load Properties from a file

Use the Properties load(InputStream); method.

You will probably want to get each property value and assign it to an internal variable and
perhaps show it in the user interface. For example,

props.load(propsIn);

Here propsIn is the input stream.

boolean recursiveSearch =
Boolean.getBoolean(props.getProperty("recursiveSearch"));
String noCopyPattern = props.getProperty("noCopyPattern");
int maxLevel = Integer.parseInt(props.getProperty("maxLevel");

To use default properties

Create a Properties table with all of the default key/value pairs. For example,

Properties defaultProps = new Properties();


defaultProps.setProperty("sourceFile", "");
defaultProps.serProperty("enableScrolling", "false");

Use this default table in the constructor for your regular properties table:

Properties props = new Properties(defaultProps);

13.7 Formatter class

Java 1.5 introduces a new class named java.util.Formatter that allows you to do string formatting
similar to the printf function in C. It depends heavily on the varargs feature being introduced in
1.5. The java.util.Formatter class includes the method

  format (String format, Object... args)

The args parameters will be displayed in the output according to the specifiers in the format
string in the first parameter.

The java.util.Formatter class provides several constructors, each of which includes a


parameter for the destination of the formatted output. Destinations include OutputStream, an
instance of File, and any class that implements the new Appendable interface.

The program FormatWriteApp shows how we can use Formatter to send formatted numerical
values to the console rather than using the printf() method.

321
import java.io.*;
import java.util.*;

/**
  * Demonstrate the java.util.Formatter capabilities for
  * formatting primitive types.
**/

public class FormatWriteApp


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

    // Send formatted output to the System.out stream.


   Formatter formatter  =
new Formatter ((OutputStream)System.out);

    formatter.format ("Text output with Formatter. %n");


    formatter.format ("Primitives converted to strings: %n");

    boolean a_boolean =  false;


    byte    a_byte    =  114;
    short   a_short   =  1211;
    int     an_int    =  1234567;
    long    a_long    =  987654321;
    float   a_float   =  983.6f;
    double  a_double  = -4.297e-15;

    formatter.format ("boolean = %9b %n",   a_boolean);


    formatter.format ("byte    = %9d %n",   a_byte);
    formatter.format ("short   = %9d %n",   a_short);
    formatter.format ("int     = %9d %n",   an_int);
    formatter.format ("long    = %9d %n",   a_long);
    formatter.format ("float   = %9.3f %n", a_float);
    formatter.format ("double  = %9.2e %n", a_double);

    // Need to flush the data out of the buffer.


    formatter.flush ();
    formatter.close ();
  } // main
} // class FormatWriteApp

The output of this program look like:

Text output with Formatter.


Primitives converted to strings:
boolean =     false
byte    =       114
short   =      1211
int     =   1234567
long    = 987654321

322
float   =   983.600
double  = -4.30e-15

In the Formatter constructor, the System.out argument, which references an instance of


PrintStream, must be cast to OutputStream because otherwise there is an ambiguity over
which constructor to use.

You can directly obtain the formatted string created by the Formatter by invoking the
toString() method. Also, if you simply want a formatted string, such as for a graphical text
component, and don't want to send it to an output destination, you can create a Formatter with
the no-argument constructor. The Formatter uses internally a StringBuilder, and you can
access the string that it creates via the toString() method.

13.8 Date class

The Date class encapsulates the current date and time. Date class has two constructors

Date()
Date(long milliseconds)

The first constructor initializes the object with the current date and time. The second constructor
accepts one argument that equals the number of milliseconds that have elapsed since midnight,
January 1, 1970. Date do not allow you to obtain the individual components of date or time.

Let’s look at a simple example of creating a date using the system clock’s current date and time
and returning a long value. This is often referred to as the system time of the host environment of
the Java Virtual Machine (JVM).

import java.util.Date;
 
public class DateExample1 {
    public static void main(String[] args) {
        // Get the system date/time
        Date date = new Date();
 
        System.out.println(date.getTime());
    }
}

To create a Date object for a specific time, pass the number of milliseconds since midnight,
January 1, 1970, Greenwich Meantime to the constructor, like this:

Date midnight_jan2_1970 = new Date(24L*60L*60L*1000L);

You can return the number of milliseconds in the Date as a long, using the getTime() method.
For example, to time a block of code, you might do this

Date d1 = new Date();

323
// timed code goes here
Date d2 = new Date();
long elapsed_time = d2.getTime() - d1.getTime();
System.out.println("That took " + elapsed_time + milliseconds");

You can change a Date by passing the new date as a number of milliseconds since midnight,
January 1, 1970, GMT, to the setTime() method, like this:

Date midnight_jan2_1970 = new Date();


midnight_jan2_1970.setTime(24L*60L*60L*1000L);

The before() method returns true if this Date is before the Date argument, false if it's not. For
example

if (midnight_jan2_1970.before(new Date())) {

The after() method returns true if this Date is after the Date argument, false if it's not. For
example

if (midnight_jan2_1970.after(new Date())) {

13.9 Calendar class

The abstract class Calendar converts a time in milliseconds since midnight, January 1, 1970,
Greenwich Mean Time, (that is a Date object), into days, minutes, hours, and seconds according
to the local calendar.

The Calendar class represents a point in time (a "Date"), interpreted appropriately for some
locale and time zone. Each Calendar instance wraps a long variable containing the number of
milliseconds since the epoch for the represented point in time.

The Calendar class follows an unusual idiom for allowing access to the individual fields of the
interpreted date instance. Rather than offering a number of dedicated property getters and setters
(such as getMonth()), it offers only one, which takes an identifier for the requested field as
argument:

int get( Calendar.MONTH )

The identifiers for the fields are defined in the Calendar class as public static final
variables. (These identifiers are raw integers, not wrapped into an enumeration abstraction.)

Besides the identifiers (or keys) for the fields, the Calendar class defines a number of additional
public static final variables holding the values for the fields. So, to test whether a certain
date (represented by the Calendar instance calendar) falls into the first month of the year, one
would write code like this:

if( calendar.get( Calendar.MONTH ) == Calendar.JANUARY ) {...}

324
Note that the months are called JANUARY, FEBRUARY, etc., irrespective of location (as
opposed to more neutral names such as MONTH_1, MONTH_2, and so on). There is also a field
UNDECIMBER, representing the 13th month of the year, which is required by some (non-
Gregorian) calendars.

An example using Calendar class

import java.util.*;
class CalendarDemo {
public static void main(String args[ ]) {
//Create a calendar initialized with the current date
// and time in the default locale and timezone
Calendar c = Calendar.getInstance();
System.out.print(“Date :”);
System.out.println(c.get(Calendar.DATE)+”/”+
(c.get(Calendar.MONTH)+1)+”/”+
c.get(Calendar.YEAR));
System.out.print(“Time:”);
System.out.println(c.get(Calendar.HOUR)+”/”+
c.get(Calendar.MINUTE)+”/”+
c.get(Calendar.SECOND));
//set the time and print it
c.set(Calendar.HOUR,10);
c.set(Calendar.MINUTE,00);
c.set(Calendar.SECOND,00);
System.out.print(“Updated Time:”);
System.out.println(c.get(Calendar.HOUR)+”/”+
c.get(Calendar.MINUTE)+”/”+
c.get(Calendar.SECOND));
}
}

13.10 GregorianCalendar class

The class GregorianCalendar is the only commonly available subclass of Calendar. It


provides an implementation of the basic Calendar abstraction suitable for the interpretation of
dates according to the conventions used commonly in the West. It adds a number of public
constructors, as well as some functions specific to Gregorian Calendars, such as isLeapYear().

boolean isLeapYear(int year)

The getInstance() method of Calendar returns a GregorianCalendar object. There are several
constructors of GregorianCalendar class. The default, initializes the object with the current date
and time in the default locale and timezone. Also there are some more like

GregorianCalendar (int year, int month, int dayOfMonth)


GregorianCalendar (int year, int month, int dayOfMonth,
int hours, int minutes)
GregorianCalendar (int year, int month, int dayOfMonth,

325
int hours, int minutes, int seconds)

All three versions set the day, month and year. Here year specifies the number of years that have
elapsed since 1900. The month is specified by month, with zero indicating January. The first
version sets the time of midnight. The second version also sets the hours and the minutes. The
third version adds seconds.

You can also construct a GregorianCalendar object by specifying either the locale and/or
timezone. The following constructors create objects initialized with the current date and time
using the specified time zone and/or locale.

GregorianCalendar (Locale locale)


GregorianCalendar (TimeZone timezone)
GregorianCalendar (TimeZone timezone, Locale locale)

Example

import java.util.*;
class GregorianCalendarDemo {
public static void main(String args[]){
GregorianCalendar gc = new GregorianCalendar();
System.out.print(“Date :”);
System.out.println(gc.get(Calendar.DATE)+”/”+
gc.get(Calendar.MONTH)+ ”/”+ gc.get(Calendar.YEAR));
System.out.print(“Time:”);
System.out.println(gc.get(Calendar.HOUR)+”/”+
gc.get(Calendar.MINUTE)+”/”+
gc.get(Calendar.SECOND));
if(gc.isLeapYear(gc.get(Calendar.YEAR))) {
System.out.println(“Current year is Leap year”);
}
else {
System.out.println(“Current year is not a Leap year”);
}
}
}

13.11 TimeZone and SimpleTimeZone classes

The TimeZone class and its subclasses are auxiliary classes, required by Calendar to interpret
dates according to the selected time zone. Semantically, a time zone specifies a certain offset to
be added to Greenwich Mean Time (GMT) also referred to as Coordinated Universal Time
(UTC) to reach the local time. Clearly, this offset changes when daylight saving time (DST) is in
effect. The TimeZone abstraction therefore needs to keep track not only of the additional offset to
be applied if DST is in effect, but also of the rules that determine when DST is in effect, in order
to calculate the local time for any given date and time.

The abstract base class TimeZone provides basic methods to handle "raw" (without taking DST
into account) and actual offsets (in milliseconds!), but implementation of any functionality

326
related to DST rules is left to subclasses, such as SimpleTimeZone. The latter class provides
several ways to specify rules controlling the beginning and ending of DST, such as a giving an
explicit day in a month or a certain weekday following a given date. Each TimeZone also has a
human-readable, locale-dependent display name. Display names come in two styles: LONG and
SHORT.

Time zones are unambiguously determined by an identifier string. The base class provides the
static method String[] getAvailableIDs() to obtain all installed "well-known" standard time
zones. Also provided are static factory methods, to obtain TimeZone instances — either for a
specific ID or the default for the current location. SimpleTimeZone also provides some public
constructors and, surprisingly for an abstract class, so does TimeZone.

An example of using TimeZone

// Get the current time in Hong Kong


Calendar cal = new
GregorianCalendar(TimeZone.getTimeZone("Hongkong"));

int hour12 = cal.get(Calendar.HOUR); // 0..11


int minutes = cal.get(Calendar.MINUTE); // 0..59
int seconds = cal.get(Calendar.SECOND); // 0..59
boolean am = cal.get(Calendar.AM_PM) == Calendar.AM;

// Get the current hour-of-day at GMT


cal.setTimeZone(TimeZone.getTimeZone("GMT"));
int hour24 = cal.get(Calendar.HOUR_OF_DAY); // 0..23

// Get the current local hour-of-day


cal.setTimeZone(TimeZone.getDefault());
hour24 = cal.get(Calendar.HOUR_OF_DAY); // 0..23

An example to list all timezones

Date today = new Date();


// Get all time zone ids
String[] zoneIds = TimeZone.getAvailableIDs();

// View every time zone


for (int i=0; i<zoneIds.length; i++) {
// Get time zone by time zone id
TimeZone tz = TimeZone.getTimeZone(zoneIds[i]);

// Get the display name


String shortName =
tz.getDisplayName(tz.inDaylightTime(today),
TimeZone.SHORT);
String longName =
tz.getDisplayName(tz.inDaylightTime(today),
TimeZone.LONG);

327
// Get the number of hours from GMT
int rawOffset = tz.getRawOffset();
int hour = rawOffset / (60*60*1000);
int min = Math.abs(rawOffset / (60*1000)) % 60;

// Does the time zone have a daylight savings time


//period?
boolean hasDST = tz.useDaylightTime();

// Is the time zone currently in a daylight savings time?


boolean inDST = tz.inDaylightTime(today);
}

13.12 Locale class

In Java, a locale is simply an identifier for a particular combination of language and region. It is
not a collection of locale-specific attributes. Instead, each locale-sensitive class maintains its own
locale-specific information. With this design, there is no difference in how user and system
objects maintain their locale-specific resources. Both use the standard localization mechanism.

Java programs are not assigned a single global locale. All locale-sensitive operations may be
explicitly given a locale as an argument. This greatly simplifies multilingual programs. While a
global locale is not enforced, a system wide default locale is available for programs that do not
wish to manage locales explicitly. A default locale also makes it possible to affect the behavior
of the entire presentation with a single choice.

Java locales act as requests for certain behavior from another object. For example, a French
Canadian locale passed to a Calendar object asks that the Calendar behave correctly for the
customs of Quebec. It is up to the object accepting the locale to do the right thing. If the object
has not been localized for a particular locale, it will try to find a "close" match with a locale for
which it has been localized. Thus if a Calendar object was not localized for French Canada, but
was localized for the French language in general, it would use the French localization instead.

Locale objects are generally created from a language name and a county name as follows:

// A locale for Great Britain


Locale greatBritain = new Locale("en","GB");

// A locale for the French language


Locale french = new Locale("fr", "");

In the second case above, an empty country string is given to the Locale constructor to signify a
locale for the entire French language. Language names are two letter ISO-639 language codes
and country names are two letter ISO-3166 country codes. This naming scheme is not enforced
by class Locale but is rather a convention used by all Java's International classes.

328
In addition, the Locale class contains a number of handy constants for creating Locale objects for
commonly used languages and countries. For example, the following specifies the Locale object
for Great Britain and can be used in place of new Locale("en","GB"):

Locale.UK

A Locale may also be created with an optional variant name. This allows multiple locales to be
created for a single language and country combination. As an example, this feature could be used
to create an "FR_FR_HOST" locale which would match the host's behavior for France rather
than Java's portable behavior for France.

Locale contains a static getter and setter method for accessing the system's default locale. At
start-up time, the default locale is automatically set by the Java runtime to match the host's
current locale. If this is not possible, the en_US locale is used.

Locale supports a number of methods to provide user readable names for the locale and its
country, language and variant fields. These names can also be localized:

Locale.setDefault( new Locale("en", "US") );


Locale japan = new Locale("ja", "JP");
String nameUS = japan.getDisplayLanguage();
String nameFR = japan.getDisplayLanguage(new Locale("fr","FR"));

In the above example, the first call to getDisplayLanguage() returns the language of the locale
japan, localized for the default locale. Thus nameUS would be "Japanese." The second call to
getDisplayLanguage() returns the language of the locale japan, localized for the given locale.
Thus nameFR would be "japonais."

13.13 StringTokenizer class

When working with any general-purpose programming language, it's often necessary to break a
large string into smaller components. java.util.StringTokenizer is used to break Java String's into
smaller components, called tokens.

You can create a StringTokenizer by using any one of the following three constructors:

StringTokenizer(String sInput) - Breaks on white space (" ", "\t", "\n").

StringTokenizer(String sInput, String sDelimiter) - Breaks on sDelimiter.

StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens) - Breaks on


sDelimiter, but if bReturnTokens is set to true, then the delimiter is also returned as a token.

The first constructor doesn't check whether the input string contains substrings. When the string
"hello. Today \"I am \" going to my home town" is tokenized on white space, the result is in
tokens hello., Today, "I, am, ", going, instead of hello., Today, "I am ", going.

329
The second constructor doesn't check the consecutive appearance of delimiters. When the string
"book, author, publication,,,date published" is tokenized on ",", the StringTokenizer returns four
tokens with values book, author, publication, and date published instead of the six values book,
author, publication, "", "", and date published, where "" means string of length 0. To get six, you
must set the StringTokenizer's bReturnTokens parameter to true.

The feature of setting the parameter to true is important as it gives an idea about the presence of
consecutive delimiters.

The third constructor won't work if a token itself is equal (in length and value) to the delimiter
and is in a substring. When the string "book, author, publication,\",\",date published" is tokenized
(this string contains , as a token, which is the same as its delimiter) on string ,, the result is book,
author, publication, ", ", date published (with six tokens) instead of book, author, publication, ,
(the comma character), date published (with five tokens).

One of the most famous sentences in American history begins with the words "Four score and
seven years ago".  For our purposes, suppose this sentence is stored in a variable named speech,
like this:

String speech = "Four score and seven years ago";

A simple snippet of code to break that sentence into individual words using Java's
StringTokenizer class would look like this:

String speech = "Four score and seven years ago";


StringTokenizer st = new StringTokenizer(speech);
while (st.hasMoreTokens()) {
   println(st.nextToken());
}
 
In this example, the variable speech is passed into the StringTokenizer constructor method. 
Because StringTokenizer is not given a field separator value as an input parameter, it uses it's
default field separator, and assumes that fields within the string are separated by whitespace
characters (spaces, tabs, and carriage-return characters).  Therefore, each time through the while
loop a word is printed on a separate line, and the resulting output from this snippet of code looks
like this:

Four
score
and
seven
years
ago

The while loop test checks to see if there are any tokens left in the st object.  As long as there
are, the println statement is executed.  Once there are no tokens remaining, the println
statement is skipped and the while loop is exited.

330
In this example a text file is used. It shows how to break a record (separated by colon characters)
into tokens typically called "fields".

The following two records are from a hypothetical customer file named customer.txt.  Each
record contains information about a customer, including their first name, last name, and the city
and state of their address.  Within a record, each field is separated by a colon character.

Homer:Simpson:Springfield:???
Hank:Hill:Arlen:Texas

Because we know that the fields of each record are separated by the colon character, we specify
that the colon character should be the field delimiter (or field separator) when we call the
StringTokenizer constructor, like this:

StringTokenizer st = new StringTokenizer(dbRecord, ":");

After that, it's a simple matter to break the record into it's four fields using the nextToken()
method of the StringTokenizer class.
import java.io.*;
import java.util.*;

class TokenTest { 
public static void main (String[] args) {
      TokenTest tt = new TokenTest();
        tt.dbTest();
     }

    void dbTest() { 


        DataInputStream dis = null;
        String dbRecord = null;
        try { 
           File f = new File("customer.txt");
           FileInputStream fis = new FileInputStream(f); 
           BufferedInputStream bis =
new BufferedInputStream(fis); 
dis = new DataInputStream(bis);
           // read the first record of the database
           while ( (dbRecord = dis.readLine()) != null) {
             StringTokenizer st = new StringTokenizer(dbRecord,
":");
String fname = st.nextToken();
      String lname = st.nextToken();
      String city  = st.nextToken();
      String state = st.nextToken();
            System.out.println("First Name:  " + fname);
            System.out.println("Last Name:   " + lname);
            System.out.println("City:        " + city);
            System.out.println("State:       " + state + "\n");
           }
        }

331
catch (IOException e) { 
           // catch io errors from FileInputStream or readLine() 
           System.out.println("Uh oh, got an IOException error: "
+ e.getMessage()); 
        }
finally { 
           // if the file opened okay, make sure we close it 
           if (dis != null) {
              try {
                 dis.close();
              }
catch (IOException ioe) {
                 System.out.println("IOException error trying to
close the file: " + e.getMessage());
}
           } // end if
        } // end finally
     } // end dbTest
  } // end class

The simple method we've shown here is a powerful way of breaking a String into tokens.  If you
need a more powerful tokenizer, you might look at the StreamTokenizer class instead.  The
StreamTokenizer class can recognize various comment styles of programming languages, and
offers a number of control flags that can be set to various states.

13.14 StreamTokenizer class

As the name of the class suggests, a StreamTokenizer object expects its input to come from an
InputStream class. Like the StringTokenizer, this class converts the input stream into chunks that
your parsing code can interpret, but that is where the similarity ends.

StreamTokenizer is a table-driven lexical analyzer. This means that every possible input
character is assigned a significance, and the scanner uses the significance of the current character
to decide what to do. In the implementation of this class, characters are assigned one of three
categories. These are:

 Whitespace characters -- their lexical significance is limited to separating words


 Word characters -- they should be aggregated when they are adjacent to another word
character
 Ordinary characters -- they should be returned immediately to the parser

Having created an instance of the class streamTokenizer we can use the nextToken method to
read tokens from the input stream. Note also that we do not need to know how big the file is in
advance in this case, we simply test the current token's type agaist the class integer constant
TT_EOF (this has a value of -1). There a four possible predefined types of token: TT_EOF,
TT_EOL, TT_Number and Word.

import java.io.*;

332
import java.util.*;

class TokenizerExample5
{
public static void main(String[] args) throws IOException
{
FileReader file = new FileReader("HelloWorld.java");
StreamTokenizer inputStream = new StreamTokenizer(file);
int tokenType = 0;
int numberOfTokens = -1;

// Process the file and output the number of tokens in the file

do {
tokenType = inputStream.nextToken();
outputTtype(tokenType,inputStream);
numberOfTokens++;
} while (tokenType != StreamTokenizer.TT_EOF);

// Output result and close file

System.out.println("Number of tokens = " +


numberOfTokens);
}

/* OUTPUT TTYPE: Method to output the ttype of a stream token and


its value. */

private static void outputTtype(int ttype, StreamTokenizer


inStream) {
switch (ttype) {
case StreamTokenizer.TT_EOF:
System.out.println("TT_EOF");
break;

case StreamTokenizer.TT_EOL:
System.out.println("TT_EOL");
break;

case StreamTokenizer.TT_NUMBER:
System.out.println("TT_NUMBER: nval = " +
inStream.nval);
break;

case StreamTokenizer.TT_WORD:
System.out.println("TT_WORD: sval = " +
inStream.sval);
break;

default:
System.out.println("Unknown: nval = " +
inStream.nval +" sval = " + inStream.sval);

333
break;
}
}
}

13.15 Random class

Java provides two mechanisms for creating random numbers – Math.random() method and
Random class. To use the Random class create an object of this class (giving a seed to the
constructor if you wish), then call one of the methods below to get a new random number.

Random constructors

Random r = new Random(); //Default seed comes from system time.


Random r = new Random(long seed); // For reproducible testing

Random methods

The most common methods are those which return a random number. These methods return a
uniform distribution of values, except nextGaussian(). In these examples, x is a Random object.

int i = r.nextInt(int n) Returns random int >= 0 and < n


int i = r.nextInt() Returns random int (full range)
long l = r.nextLong() Returns random long (full range)
float f = r.nextFloat() Returns random float >= 0.0 and < 1.0
double d = r.nextDouble() Returns random double >=0.0 and < 1.0
boolean b = r.nextBoolean() Returns random double (true or false)
double d = r.nextGaussian() Returns random number with mean 0.0 and
standard deviation 1.0

Example: Generating a number from 1 to 6

Because nextInt(6) returns a number from 0-5, it's necessary to add 1 to scale the number into the
range 1-6,

static Random randGen = new Random();


int spots = randGen.nextInt(6) + 1;

A program to generate a random double random

import java.util.Random;

public class RandomNumber


{
public static void main(String[] args)
{
Random generator = new Random();
double num1 = generator.nextDouble();

334
System.out.println("A random double number: " + num1);

}
}

13.16 BitSet class

A BitSet class creates a special type of array that holds bit values. The BitSet class represents a
set of bits, which is also known as a bitfield. The BitSet class implements a bit-vector of an
arbitrary size. It automatically grows dynamically. This example demonstrates how to create and
use a BitSet.

// Create the bitset


BitSet bits = new BitSet();

// Set a bit on
bits.set(2); // 100 = decimal 4

// Retrieving the value of a bit


boolean b = bits.get(0); // false
b = bits.get(2); // true

// Clear a bit
bits.clear(1);

// Setting a range of bits


BitSet bits2 = new BitSet();
bits2.set(1, 4); // 1110

// And'ing two bitsets


bits.and(bits2); // 0100

// Xor'ing two bitsets


bits.xor(bits2); // 1010

// Flip all bits in the bitset


bits.flip(0, bits.length()); // 0101

// Andnot'ing two bitsets


bits.andNot(bits2); // 0001

// Or'ing two bitsets


bits.or(bits2); // 1111

13.17 Timer and TimerTask classes

The Timer class in the java.util package schedules instances of a class called TimerTask.
TimerTask implements the Runnable interface; thus it can be used to create a thread of
execution.

335
import java.util.*;

/**
* Simple demo that uses java.util.Timer to schedule a task
to execute once 5 seconds have passed.
*/

public class Reminder {


Timer timer;

public Reminder(int seconds) {


timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}

class RemindTask extends TimerTask {


public void run() {
System.out.println("Time's up!");
timer.cancel(); //Terminate the timer thread
}
}

public static void main(String args[]) {


new Reminder(5);
System.out.println("Task scheduled.");
}
}

When you run the example, you first see this:

Task scheduled.

Five seconds later, you see this:


Time's up!

This simple program illustrates the basic parts of implementing and scheduling a task to be
executed by a timer thread.
 Implement a custom subclass of TimerTask. The run method contains the code that performs
the task. In this example, the subclass is named RemindTask.
 Create a thread by instantiating the Timer class.
 Instantiate the timer task object (new RemindTask()).
 Schedule the timer task for execution. This example uses the schedule method, with the
timer task as the first argument and the delay in milliseconds ( 5000) as the second argument.
Another way of scheduling a task is to specify the time when the task should execute. For
example, the following code schedules a task for execution at 11:01 p.m.:

//Get the Date corresponding to 11:01:00 pm today.


Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 23);

336
calendar.set(Calendar.MINUTE, 1);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer = new Timer();
timer.schedule(new RemindTask(), time);

Stopping Timer Threads

By default, a program keeps running as long as its timer threads are running. You can terminate a
timer thread in four ways.

 Invoke cancel on the timer. You can do this from anywhere in the program, such as from a
timer task's run method.
 Make the timer's thread a "daemon" by creating the timer like this: new Timer(true). If the
only threads left in the program are daemon threads, the program exits.
 After all the timer's scheduled tasks have finished executing, remove all references to the
Timer object. Eventually, the timer's thread will terminate.
 Invoke the System.exit method, which makes the entire program (and all its threads) exit.

The Reminder example uses the first scheme, invoking the cancel method from the timer task's
run method. Making the timer thread a daemon wouldn't work, because the program needs to
keep running until the timer's task executes.

Performing a task repeatedly

Here are all the Timer methods you can use to schedule repeated executions of tasks:

schedule(TimerTask task, long delay, long period)


schedule(TimerTask task, Date time, long period)
scheduleAtFixedRate(TimerTask task, long delay, long period)
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

When scheduling a task for repeated execution, you should use one of the schedule methods
when smoothness is important and a scheduleAtFixedRate method when time synchronization is
more important.

13.18 Observable class

The Observable class is used to create subclasses that other parts of your program can observe.
When an object of such a subclass undergoes a change, observing classes are notified. Observing
classes must implement the Observer interface which defines the update() method. The update()
method is called when an observer is notified of a change in an observed object.

An object that is being observed must follow two simple rules. First, if it has changed, it must
call setChanged(). Secondly, when it is ready to notify observers of this change, it must call
notifyObservers(). This causes the update() method in the observing object(s) to be called. If the
object calls notifyObservers without having previously called setChanged, no action will take

337
place. The observed object must call both setChanged() and notifyObservers() before update()
will be called.

Notice that notifyObserevers() has two forms: one that takes an argument and one does not. If
you call the notifyObservers() with an argument, this object is passed to Observer’s update()
method as its second parameter. Otherwise null is passed to update(). You can use the second
parameter for passing any type of object that is appropriate for your application.

The Observer Interface

To observe an observable object, you must implement the Observer interface. This interface
defines only the one method shown here:

void update (Observable observOb, Object arg)

Here, observOb is the object being observed, and arg is the value passed by notifyObservers().
The update() method is called when a change in the observed object takes place. There can be
more than one observers.

An example of using Observer. Here Watcher implements Observer. This class is being
monitored by BeingWatched. When the value in the Watcher is changed the notifyObserver
passes the changed value to the BeingWatched Object.

import java.util.*;

class Watcher implements Observer {


public void update (Observable obj, Object arg) {
System.out.println(“update() called, value is:”+
(String)arg);
}
}

// This is the class being observed


class BeingWatched extends Observable {
String value;

void changeValue(String value) {


this.value = value;
setChanged();
notifyObservers(value);
}
}

class ObserverDemo {
public static void main(String args []) {
BeingWatched observed = new BeingWatched();
Watcher observing = new Watcher();
/** Add the observing to the list of observers for
observed object. */

338
observed.addObserver(observing);
observed.changeValue(args[0]);
}
}

13.19 Currency class

Java 2 version 1.4 has added the Currency class. This class encapsulates information about a
currency. It defines no constructors. The following program demonstrates the use of Currency:

import java.util.*;

class CurDemo {
public static void main (String args []) {
Currency c = Currency.getInstance(Locale.US);
System.out.println(“Symbol :” + c.getSymbol());
System.out.println(“Default fractional digits :”+
c.getDefaultFractionDigits());
}
}

The output is shown here.

Symbol : $
Default fractional digits : 2

339
Chapter 14 : Regular Expression Processing
Using regular expressions and the java.util.regex package, you can easily describe, locate and
manipulate complex patterns of text.

14.1 What is a Regular Expression?

A regular expression is a series of metacharacters and literals that allow you to describe
substrings in text using a pattern. These metacharacters actually form a miniature language in
their own right. Consider the following sentence:

My name is Will and I live in williamstown.

How could we find all occurrences of the text 'Will', regardless of whether or not an upper or
lowercase 'w' was used? With regular expressions you can describe this requirement by
composing a pattern made from a series of metacharacters and literals. Here is such a pattern:

[Ww]ill

This one's pretty straightforward. The interesting part is the [Ww] grouping -- it indicates that
any one of the letters enclosed within the brackets (in this case, either an uppercase 'W' or a
lowercase 'w') is acceptable. So, this regular expression will match text that begins with an
uppercase or lowercase w, and is followed by the literals i, then l, and then another l.

Let's step it up a notch. The above regular expression will actually match 2 occurrences of will --
the name Will and the first 4 characters of text in williamstown. We may only have wanted to
search for will and Will, and not for words that simply contain these 4 characters in sequence.
Here's an improved version:

\b[Ww]ill\b

The \b is how we describe a word boundary. A word boundary will match the likes of spaces,
tabs, and the beginning and end points of a line. This effectively rules out williamstown as a
match because the second l in williamtown is not followed by a word boundary -- it's followed
by an i.

Let's examine one more regular expression

 (\w+)@(\w+\.)(\w+)(\.\w+)?

The (\w+) grouping (it appears twice -- examine the one at the start) looks for word characters, as
denoted by the \w. The + indicates that one or more word characters must appear (not necessarily
the same one). This must be followed by a literal @ character. The parentheses are not actually
required here, but they do divide the expression into groupings.

340
Based on this first portion of our example regex, the (\w+)@ portion, here are a few examples
that meet the requirements so far:

 billy@
 joe@
 francisfordcoppola@

The (\w+\.) grouping is similar, but expects a period to follow in order to make a match. The
period has been escaped using a backslash because the period character is itself a regex meta-
character (a wildcard that matches any character). You must always escape metacharacters in this
way if you want to match on their literal meaning.

Let's take a look at a few examples that would meet the requirements so far:

 billy@webworld.
 joe@optus.
 francisfordcoppola@myisp.

The (\w+) grouping is identical to the first grouping -- it looks for one or more word characters.
So, as you've no doubt realised already, our regular expression is intended to match email
addresses.

A few examples that meet the requirements so far:

 billy@webworld.com
 joe@optus.net
 francisfordcoppola@myisp.com

The (\.\w+)* grouping should mostly make sense at this point -- we're looking for a period
followed by one or more word characters. But what's with the * after the closing parentheses? In
the world of regular expressions, we use * to denote that the preceding metacharacter, literal or
group can occur zero or more times. As an example, \w\d* would match a word character
followed by zero or more digits. In our example, we use parentheses to group together a series of
metacharacters, so the * applies to the whole group. So, you can interpret (\.\w+)* as 'match a
period followed by one or more word characters, and match that combination zero or more
times'.

A few examples that meet the requirements of the complete regular expression:
 fred@vianet.com
 barney@comcorp.net.au
 wilma@mjinteractive.iinet.net.au

Java Safe Regular Expressions

341
Any backslash delimited metacharacters in java will need to be escaped. This is because the
backslash character has its own special meaning in Java. So, our example email address regex
would have to be rewritten as follows:
 String emailRegEx = "(\\w+)@(\\w+\\.)(\\w+)(\\.\\w+)*";

14.2 Pattern class


This class lets you compile your regular expression -- this effectively optimises it for efficiency
and use by multiple target strings (strings which you want to test the compiled regular expression
against). Consider the following example:
String emailRegEx = "(\\w+)@(\\w+\\.)(\\w+)(\\.\\w+)*";
// Compile and get a reference to a Pattern object.
Pattern pattern = Pattern.compile(emailRegEx);

Take note that the Pattern object was retrieved via the Pattern class's static compile method --
you cannot instantiate a Pattern object using new. Once you have a Pattern object you can use it
to get a reference to a Matcher object.

The Pattern class has a number of flags that you can use as a second argument to its compile()
method. For example, you can use Pattern.CASE_INSENSITIVE to tell the regex engine to
match ASCII characters regardless of case.

Pattern.MULTILINE is another useful one. You will sometimes want to tell the regex engine that
your target string is not a single line of code; rather, it contains several lines that have their own
termination characters.

If you need to, you can combine multiple flags by using the java | (vertical bar) operator. For
instance, if you wanted to compile a regex with multiline and case insensitivity support, you
could do the following:
Pattern.compile(myRegEx, Pattern.CASE_INSENSITIVE |
Pattern.MULTILINE );

14.3 Matcher class

Once you have created a Pattern object, you will use it to create a Matcher. This is done by
calling the matcher() factory method defined by Pattern as shown here
Matcher matcher(CharSequence str)

Here str is the character sequence that the pattern will be matched against. This is called the input
sequence.

The simplest pattern matching method is matches(), which simply determines whether the
character sequence matches the pattern, and not just a subsequence of it.
boolean matches()

342
To determine if a subsequence of the input sequence matches the pattern use find(). Each call to
find() begins where the previous one left off.

You can obtain a string containing the last matching sequence by calling group(). You can obtain
the index within the input sequence of the current match by calling start(). The index one past the
end of the current match is obtained by calling end().

The above example is continued below:


String targetString = "You can email me at g_andy@example.com or
andy@example.net to get more info";
// Get a Matcher based on the target string.
Matcher matcher = pattern.matcher(targetString);

   // Find all the matches.


   while (matcher.find()) {
     System.out.println("Found a match: " + matcher.group());
     System.out.println("Start position: " + matcher.start());
     System.out.println("End position: " + matcher.end());
   }

First up, notice that we used the Pattern class's matcher() method to obtain a Matcher object. The
while loop runs conditionally based on the results of the Matcher class's find() method. This
method will parse just enough of our target string to make a match, at which point it will return
true. Be careful: any attempts to use the matcher before calling find() will result in the unchecked
IllegalStateException being thrown at runtime.

In the body of our while loop we retrieved the matched substring using the Matcher class's
group() method. Our while loop executes twice: once for each email address in our target string.
On each occasion, it prints the matched email address, returned by the group() method, and the
substring location information. Take a look at the output:
Found a match: g_andy@example.com
Start position: 20
End position: 38
Found a match: andy@example.net
Start position: 42
End position: 58

As you can see, it was simply a matter of using the Matcher's start() and end() methods to find
out where the matched substrings occurred in the target string.

Understanding Groups

Matcher.group() will retrieve a complete match from the target string. But what if you were also
interested in subsections, or 'subgroups' of the matched text? In our email example, it may have
been desirable to extract the host name portion of the email address and the username portion.
Have a look at a revised version of our Matcher driven while loop:

343
while (matcher.find()) {
     System.out.println("Found a match: " + matcher.group(0) +      
". The Username is " + matcher.group(1) +
" and the ISP is " + matcher.group(2));
}

As you may recall, groups are represented as a set of parentheses wrapped around a subsection of
your pattern. The first group, located using Matcher.group() or, as in the example, the more
specific Matcher.group(0), represents the entire match. Further groups can be found using the
same group(int index) method. Here is the output for the above example:
Found a match: g_andy@example.com.. The Username is g_andy and the ISP
is example.
Found a match: andy@example.net.. The Username is andy and the ISP is
example.

As you can see, group(1) retrieves the username portion of the email address and group(2)
retrieves the ISP portion. When crafting your own regular expressions it is, of course, up to you
how you logically subgroup your patterns. A minor oversight in this example is that the period
itself is captured as part of the subgroup returned by group(2)!

Keep in mind that subgroups are indexed from left to right based on the order of their opening
parentheses. This is particularly important when you are working with groups that are nested
within other groups.

The Matcher class has a number of interesting methods: String replaceAll(String


replacementString) and String replaceFirst(String replacementString), in particular, are worth a
mention here.

The replaceAll() method takes a replacement string and replaces all matches with it. The
replaceFirst() method is very similar but will replace only the first occurrence of a match. Have a
look at the following code:
   // Matches 'BBC' words that end with a digit.
   String thePattern = "bbc\\d";
   // Compile regex and switch off case sensitivity.
   Pattern pattern = Pattern.compile(thePattern,
Pattern.CASE_INSENSITIVE);
   // The target string.
   String target = "I like to watch bBC1 and BbC2 - I suppose MTV
is okay too";
   // Get the Matcher for the target string.
   Matcher matcher = pattern.matcher(target);
   // Blot out all references to the BBC.
   System.out.println(matcher.replaceAll("xxxx") );

Here' the output:


I like to watch xxxx and xxxx - I suppose MTV is okay too

BackReferences

344
Backreferences allow you to access captured subgroups while the regex engine is executing.
Basically, this means that you can refer to a subgroup from an earlier part of a match later on in
the pattern. Imagine that you needed to inspect a target string for 3-letter words that started and
ended with the same letter -- wow, sos, mum, that kind of thing. Here's a pattern that will do the
job:
(\w)(\w)(\1)

In this case, the (\1) group contains a backreference to the first match made in the pattern.
Basically, the third parenthesised group will only match when the character at this position is the
same as the character in the first parenthesised group. Of course, you would simply substitute \1
with \2 if you wanted to backreference the second group. It's simple, but in many cases,
tremendously useful.

The Matcher object's replacement methods (and the String class's counterparts) also support a
notation for doing backreferences in the replacement string. It works in the same way, but uses a
dollar sign instead of a backslash. So, matcher.replaceAll("$2") would replace all matches in a
target string with the value matched by the second subgroup of the regular expression.

14.4 String Class RegEx Methods


The Java String class has been updated to take advantage of regular expressions. There are 5
such methods available.

You can use the boolean matches(String regex) method to quickly determine if a string exactly
matches a particular pattern. The appropriately named String replaceFirst(String regex, String
replacement) and String replaceAll(String regex, String replacement) methods allow you to do
quick and dirty text replacements. And finally, the String[] split(String regEx) and String[]
split(String regEx, int limit) methods let you split a string into substrings based on a regular
expression. These last two methods are, in concept, similar to the java.util.StringTokenizer, only
much more powerful.

345
Chapter 15 : API classes in java.text
15.1 DateFormat class

While Calendar and related classes handle the locale-specific interpretation of dates, the
DateFormat classes assist with the transformation of dates to and from human-readable strings.
When representing points in time, an additional localization issue arises: not only the language,
but also the date format is locale-dependent (U.S.: Month/Day/Year, Germany: Day.Month.Year,
etc.). The DateFormat utility tries to manage these differences for the application programmer.

The abstract base class DateFormat does not require (and does not permit) the definition of
arbitrary, programmer-defined date formats. Instead, it defines four different format styles:
SHORT, MEDIUM, LONG, and FULL (in increasing order of verbosity). Given a locale and a
style, the programmer can rely on the class to use an appropriate date format.

The abstract base class DateFormat does not define static methods for formatting (date to text) or
parsing (text to date). Instead, it defines several static factory methods to obtain instances (of
concrete subclasses) initialized for a given locale and a chosen style. Since the standard formats
always include both date and time, additional factory methods are available to obtain instances
treating only the time or date part.

static final DateFormat getDateInstance()


static final DateFormat getDateInstance(int style)
static final DateFormat getDateInstance(int style, Locale locale)

The String format(Date) and Date parse(String) methods then perform the transformation. Note
that concrete subclasses may choose to break this idiom.

The commands

DateFormat df = DateFormat.getDateTimeInstance();
String now = df.format( new Date() );
System.out.println(now);

print the current date and time (as returned by "new Date()"), formatted according the
conventions of the default locale. The output will look different in different countries.

The Calendar object used internally to interpret dates is accessible and can be modified, as are
the employed TimeZone and NumberFormat objects. However, the locale and style can no
longer be changed once the DateFormat has been instantiated.

Also available are (abstract) methods for piece-wise parsing or formatting, taking an additional
ParsePosition or FieldPosition argument, respectively. There are two versions for each of these
methods. One takes or returns a Date instance and the other takes or returns a general Object, to
allow handling of alternatives to Date in subclasses. The class defines several public static

346
variables with names ending in _FIELD to identify the various possible fields for use with
FieldPosition

In the following example the getTime() method of GregorianCalendar returns a Date


corresponding to the GregorianCalendar object. You can put the whole process of creating a
GregorianCalendar object, converting it to a Date, and getting and outputting the corresponding
String in the following program:

import java.util.*;
import java.text.*;

public class Flight {


   public static void main(String[] args) {
     GregorianCalendar firstFlight = new GregorianCalendar
(1903, Calendar.DECEMBER, 17);    
Date d = firstFlight.getTime();
DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
String s = df.format(d);
System.out.println("First flight was " + s);
}
}

One more example that specifies the date style and locale

import java.text.*;
import java.util.*;

public class DateFormatDemo {


public static void main (String args[]) {
Date date = new Date();
DateFormat df =
DateFormat.getDateInstance(DateFormat.SHORT,
Locale.JAPAN);
System.out.println(“Japan :”+df.format(date));

df = DateFormat.getDateInstance(DateFormat.MEDIUM,
Locale.KOREA);
System.out.println(“Korea :”+df.format(date));

df = DateFormat.getDateInstance(DateFormat.LONG,
Locale.UK);
System.out.println(“UK :”+ df.format(date));

df = DateFormat.getDateInstance(DateFormat.FULL,
Locale.US);
System.out.println(“US :”+ df.format(date));
}
}

Sample output is shown below:

347
Japan : 02/05/08
Korea: 2002-05-08
UK: 08 May 2002
US: Wednesday, May 8, 2002

The getTimeInstance() method returns an instance of DateFormat that can format time
information. It is available in these versions:

static final DateFormat getTimeInstance()


static final DateFormat getTimeInstance(int style)
static final DateFormat getTimeInstance(int style, Locale locale)

The style argument is one of the following values: DEFAULT, SHORT, MEDIUM, LONG or
FULL. These are int constants which cause different details about the time to be presented. The
argument locale is one of the static references of Locale. If the style and/or locale is not specified
defaults are used. An example of using it is shown below:

import java.util.*;
import java.text.*;

public class TimeFormatDemo {


public static void main(String args[]) {
Date date = new Date();
DateFormat df = DateFormat.getTimeInstance(
DateFormat.SHORT,Locale.JAPAN);
System.out.println(“Japan :”+df.format(date));
df = DateFormat.getTimeInstance(DateFormat.LONG,Locale.UK);
System.out.println(“UK :”+df.format(date));
df = DateFormat.getTimeInstance(DateFormat.FULL,
Locale.CANADA);
System.out.println(“Canada :”+df.format(date));
}
}

Sample output from the program is shown here:

Japan : 20:25
UK : 20:25:14 CDT
Canada : 8:25:14 o’clock PM CDT

The DateFormat class also has a getDateTimeInstance() method that can format both date and
time information.

15.2 SimpleDateFormat class

The only commonly available concrete subclass of DateFormat is SimpleDateFormat. It provides


all of the aforementioned functionality, additionally allowing the definition of arbitrary date-
formatting patterns. The pattern can be specified as an argument to the constructors of this class
or set explicitly.

348
The constructor normally takes a formatting string made from the following symbols:

Char Meaning Char Meaning


a AM or PM D Day of year
d Day of month E Day of week
h Hour (1-12) F Day of week in month
k Hour (1-24) G Era (AD or BC)
m Minute H Hour in Day (0-23)
s Second K Hour in Day (0-11)
w Week of year M Month
y Year S Millisecond
z Timezone W Week of month
: Separator / Escape character
SimpleDateFormat(String formatString)

In most cases, the number of times a symbol is repeated determines how that data is presented.
Text information is displayed in an abbreviated form if the pattern letter is repeated less than four
times. Otherwise unabbreviated form is used. For numbers, the number of times a pattern letter is
repeated determines how many digits are presented. M or MM causes the month to be displayed
as one or two digits. Three or more repetitions of M cause the month to be displayed as a text
string.

One example of using SimpleDateFormat

import java.text.*;
import java.util.*;

public class test


{
public static void main (String args[])
{
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM dd
hh:mm");
String rptDate = sdf.format(date);
System.out.println(rptDate+"\n");
}
}

One more example to format and parse it back.

// Create a formatter with the following pattern:


//Hour(0-23):Minute:Second

SimpleDateFormat formatter = new SimpleDateFormat( "HH:mm:ss" );


Date now = new Date();
String logEntry = formatter.format(now);

349
// To read the string back in
try {
Date sometime = formatter.parse( logEntry );
}
catch ( ParseException exc ) {
exc.printStackTrace();
}

Note the ParseException that needs to be caught. It is thrown when the beginning of the input
string cannot be parsed.

15.3 DateFormatSymbols class

The format method of the SimpleDateFormat class returns a String composed of digits and
symbols. For example, in the String "Friday, April 10, 1998," the symbols are "Friday" and
"April." If the symbols encapsulated in SimpleDateFormat don't meet your needs, you can
change them with the DateFormatSymbols. You can change symbols that represent names for
months, days of the week, and time zones, among others. The following table lists the
DateFormatSymbols methods that allow you to modify the symbols:

DateFormatSymbol Methods
Setter Method Example of a Symbol the Method Modifies
setAmPmStrings PM
setEras AD
setMonths December
setShortMonths Dec
setShortWeekdays Tue
setWeekdays Tuesday
setZoneStrings PST

The following example invokes setShortWeekdays to change the short names of the days of the
week from lowercase to uppercase characters. The full source code for this example is in
DateFormatSymbolsDemo. The first element in the array argument of setShortWeekdays is a
null String. Therefore the array is one-based rather than zero-based. The SimpleDateFormat
constructor accepts the modified DateFormatSymbols object as an argument. Here is the source
code:

DateFormatSymbols symbols = new DateFormatSymbols(


new Locale("en","US"));
String [] defaultDays = symbols.getShortWeekdays();

for (int i = 0; i < defaultDays.length; i++) {


System.out.print(defaultDays[i] + " ");
}
System.out.println();

350
String[] capitalDays = {“", "SUN", "MON", "TUE", "WED", "THU",
"FRI", "SAT"};
symbols.setShortWeekdays(capitalDays);

String [] modifiedDays = symbols.getShortWeekdays();


for (int i = 0; i < modifiedDays.length; i++) {
System.out.print(modifiedDays[i] + " ");
}
System.out.println();

SimpleDateFormat formatter = new SimpleDateFormat("E", symbols);


Date today = new Date();
String result = formatter.format(today);
System.out.println(result);

The preceding code generates this output:

Sun Mon Tue Wed Thu Fri Sat


SUN MON TUE WED THU FRI SAT
WED

15.4 NumberFormat class

Using Java's NumberFormat class, you can automatically format numbers according to the local
conventions in use where your application is run. If your application is run in Germany, for
instance, your number will automatically use the comma as the decimal separator and the period
as the grouping separator--just the opposite of the custom in the US.

The first step is to create a NumberFormat object. You have your choice of three built-in
formatting styles: a generic number formatter, a currency formatter, and a percentage formatter.

You don't use the new operator to construct your NumberFormat objects; instead you use very
specific methods called factory methods.

The three factory methods you use to create built-in format objects are the getNumberInstance(),
getCurrencyInstance(), and getPercentInstance(). Here's an example:

NumberFormat nf, cf, pf; 

nf = NumberFormat.getNumberInstance();
cf = NumberFormat.getCurrencyInstance();
pf = NumberFormat.getPercentInstance();

To use your NumberFormat object, you simply call its format() method, passing either a double
primitive value or a Double object. For example,

NumberFormat fmt = NumberFormat.getCurrencyInstance();


System.out.println (“Total amount: "+fmt.format(amount));

351
You can use the NumberFormat methods to format primitive-type numbers, such as double, and
their corresponding wrapper objects, such as Double.

The following code example formats a Double according to Locale. Invoking the
getNumberInstance method returns a locale-specific instance of NumberFormat. The format
method accepts the Double as an argument and returns the formatted number in a String.

Double amount = new Double(345987.246);


NumberFormat numberFormatter =
NumberFormat.getNumberInstance(currentLocale);
String amountOut = numberFormatter.format(amount);
System.out.println(amountOut + " " + currentLocale.toString());

The output from this example shows how the format of the same number varies with Locale:

345 987,246 fr_FR


345.987,246 de_DE
345,987.246 en_US

If you're writing business applications, you'll probably need to format and to display currencies.
You format currencies in the same manner as numbers, except that you call
getCurrencyInstance to create a formatter. When you invoke the format method, it returns a
String that includes the formatted number and the appropriate currency sign.

This code example shows how to format currency in a locale-specific manner:

Double currency = new Double(9876543.21);


NumberFormat currencyFormatter =
NumberFormat.getCurrencyInstance(currentLocale);
String currencyOut = currencyFormatter.format(currency);
System.out.println(currencyOut + " " + currentLocale.toString());

The output generated by the preceding lines of code is as follows:

9 876 543,21 F fr_FR


9.876.543,21 DM de_DE
$9,876,543.21 en_US

At first glance this output may look wrong to you, because the numeric values are all the same.
Of course, 9 876 543,21 F is not equivalent to 9.876.543,21 DM. However, bear in mind that the
NumberFormat class is unaware of exchange rates. The methods belonging to the NumberFormat
class format currencies but do not convert them.

You can also use the methods of the NumberFormat class to format percentages. To get the
locale-specific formatter, invoke the getPercentInstance method. With this formatter, a
decimal fraction such as 0.75 is displayed as 75%. The following code sample shows how to
format a percentage.

352
Double percent = new Double(0.75);
NumberFormat percentFormatter =
NumberFormat.getPercentInstance(currentLocale);
String percentOut = percentFormatter.format(percent);

15.5 DecimalFormat class

You can use the DecimalFormat class to format decimal numbers into locale-specific strings.
This class allows you to control the display of leading and trailing zeros, prefixes and suffixes,
grouping (thousands) separators, and the decimal separator. If you want to change formatting
symbols, such as the decimal separator, you can use the DecimalFormatSymbols in conjunction
with the DecimalFormat class. These classes offer a great deal of flexibility in the formatting of
numbers, but they can make your code more complex.

Applications that require highly customized number formatting and parsing may create custom
DecimalFormat class objects by passing a suitable pattern to the DecimalFormat() constructor
method. The applyPattern() method can be used to change this pattern. A
DecimalFormatSymbols object can be optionally specified when creating a DecimalFormat
object. If one is not specified, a DecimalFormatSymbols object suitable for the default locale is
used. Decimal format patterns consists of a string of characters from the following table. For
example: "$#,##0.00;($#,##0.00)"

Char Interpretation
0 A digit // leading zeros show as 0
# A digit // leading zeros show as absent
. The locale-specific decimal separator
, The locale-specific grouping separator (comma)
- The locale-specific negative prefix
% Shows value as a percentage
; Separates a positive number format (on left) from
an optional negative number format (on right)
' Escapes a reserved character so it appears literally in the output

You specify the formatting properties of DecimalFormat with a pattern String. The pattern
determines what the formatted number looks like.

The example that follows creates a formatter by passing a pattern String to the DecimalFormat
constructor. The format method accepts a double value as an argument and returns the formatted
number in a String:

DecimalFormat myFormatter = new DecimalFormat(pattern);


String output = myFormatter.format(value);
System.out.println(value + " " + pattern + " " + output);

353
The output for the preceding lines of code is described in the following table. The value is the
number, a double , that is to be formatted. The pattern is the String that specifies the
formatting properties. The output, which is a String, represents the formatted number.

Output from DecimalFormatDemo Program

value pattern output Explanation


123456.789 ###,###.### 123,456.789 The pound sign (#) denotes a digit, the
comma is a placeholder for the
grouping separator, and the period is a
placeholder for the decimal separator.
123456.789 ###.## 123456.79 The value has three digits to the right
of the decimal point, but the pattern
has only two. The format method
handles this by rounding up.
123.78 000000.000 000123.780 The pattern specifies leading and
trailing zeros, because the 0 character
is used instead of the pound sign (#).
12345.67 $###,###.### $12,345.67 The first character in the pattern is
the dollar sign ($). Note that it
immediately precedes the leftmost
digit in the formatted output.
12345.67 \u00A5###,###.### ¥12,345.67 The pattern specifies the currency
sign for Japanese yen (¥) with the
Unicode value 00A5.

Here is an example of how DecimalFormat can be used:


import java.text.*;
public class test
{
public static void main (String args[])
{
int numb = 3; String rptNumb;
DecimalFormat df = new DecimalFormat("000");
rptNumb = df.format(numb); System.out.println(rptNumb+"\n");
}
}

The preceding example created a DecimalFormat object for the default Locale. If you want a
DecimalFormat object for a nondefault Locale, you instantiate a NumberFormat and then cast it
to DecimalFormat. Here's an example:

NumberFormat nf = NumberFormat.getNumberInstance(loc);
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern(pattern);
String output = df.format(value);

354
System.out.println(pattern + " " + output + " " +
loc.toString());

Running the previous code example results in the output that follows. The formatted number,
which is in the second column, varies with Locale:

###,###.### 123,456.789 en_US


###,###.### 123.456,789 de_DE
###,###.### 123 456,789 fr_FR

So far the formatting patterns discussed here follow the conventions of U.S. English. For
example, in the pattern ###,###.## the comma is the thousands-separator and the period
represents the decimal point. This convention is fine, provided that your end users aren't exposed
to it. However, some applications, such as spreadsheets and report generators, allow the end
users to define their own formatting patterns. For these applications the formatting patterns
specified by the end users should use localized notation. In these cases you'll want to invoke the
applyLocalizedPattern method on the DecimalFormat object.

You can use the DecimalFormatSymbols class to change the symbols that appear in the
formatted numbers produced by the format method. These symbols include the decimal
separator, the grouping separator, the minus sign, and the percent sign, among others.

The next example demonstrates the DecimalFormatSymbols class by applying a strange format
to a number. The unusual format is the result of the calls to the setDecimalSeparator,
setGroupingSeparator, and setGroupingSize methods.

DecimalFormatSymbols unusualSymbols =
new DecimalFormatSymbols(currentLocale);
unusualSymbols.setDecimalSeparator('|');
unusualSymbols.setGroupingSeparator('^');

String strange = "#,##0.###";


DecimalFormat weirdFormatter =
new DecimalFormat(strange, unusualSymbols);
weirdFormatter.setGroupingSize(4);

String bizarre = weirdFormatter.format(12345.678);


System.out.println(bizarre);

When run, this example prints the number in a bizarre format:

1^2345|678

15.6 Format class

The class Format provides several overloaded Format.print(..) static methods to output a
single number or string with formatting descriptions similar to the printf function in C.

355
For example,

  double q =10.0/3.0;
  Format.print("0.4f", q);

will result in an output of

  3.3333

To send formatted outputs directly to a string, the class provides several overloaded
format(arg) methods, where arg is a number type. An instance of the format must first be
created with the desired formatting description.

This can be done in a convenient single line approach by appending the method invocation to the
instantiation operation as shown here:

  double q =10.0/3.0;
  String str = new Format("0.3e").format(q)

which results in the string variable str referencing "3.333e+000".

The following program shows the use of Format class.

import java.text.*;

class FormatDemo {
public static void main(String args[]) {
double q = 1.0/3.0;

    // Create an instance of the format pattern


    // and then create the string with the method format
    String qValStr = new Format ("%0.3f").format (q);
    System.out.println ("1.0/3.0 = " + qValStr);

    // Can change the format pattern:


    qValStr = new Format ("%0.5f").format (q);
    System.out.println ("1.0/3.0 = " + qValStr);

    // The # symbol indicates trailing blanks


    q = 1.0/2.0;
    qValStr = new Format ("%0.5g").format (q);
    System.out.println ("1.0/2.0 = " + qValStr);

    //
    q = 1000.0/3.0;
    qValStr = new Format ("%0.2e").format (q);
    System.out.println ("1000.0/3.0 = " + qValStr);

    //
    q = 3.0/4567.0;

356
    qValStr = new Format ("%0.2e").format (q);
    System.out.println ("3.0/4567.0 = " + qValStr);

    // Negative infinity


    q = -1.0/0.0;
    qValStr = new Format ("%0.3e").format (q);
    System.out.println ("-1.0/0.0 = " + qValStr);

    // NaN
    q = 0.0/0.0;
    qValStr = new Format ("%0.3e").format (q);
    System.out.println ("0.0/0.0 = " + qValStr);
}
}

Output of this program:

1.0/3.0 = 0.333
1.0/3.0 = 0.33333
1.0/2.0 = 0.5
1000.0/3.0 = 3.33e+002
3.0/4567.0 = 6.57e-004
-1.0/0.0 = -Inf
0.0/0.0 = NaN

Summary

To format a number to display to an end user, you use the NumberFormat class in the java.text
package. When using NumberFormat, you can get a default format for decimal numbers,
percentages, or currency. Or, you can design a custom format using patterns.

357
Chapter 16 : Collections Framework and Generics
16.1 What is a Collection?

A collection (sometimes called a container) is simply an object that groups multiple elements
into a single unit. Collections are used to store, retrieve and manipulate data, and to transmit
data from one method to another. Collections typically represent data items that form a natural
group.

A Java collection is a flexible data structure that can hold heterogeneous objects where the
elements may have any reference type. It is your responsibility, however, to keep track of what
types of objects your collections contain. As an example, consider adding an int to a collection;
since you cannot have collections of primitive data types you must convert the int to the
corresponding reference type (i.e. Integer) before storing it in the collection. Now, when the
element is extracted from the collection an Object is returned that must be cast to an Integer in
order to ensure type safety. All this makes Java programs unnecessarily hard to read and
maintain, and are more likely to fail with runtime errors.

16.2 Generics

The motivation for adding generics to the Java programming language stems from the lack of
information about a collection's element type, the need for developers to keep track of what type
of elements collections contain, and the need for casts all over the place. Using generics, a
collection is no longer treated as a list of Object references, but you would be able to
differentiate between a collection of references to Integers and collection of references to Bytes.
A collection with a generic type has a type parameter that specifies the element type to be stored
in the collection.

Generics allow you to define a class or interface once and instantiate it with a variety of types. A
generic (also known as a parametrized type) is a type that has one or more type parameters. To
use a generic you supply an actual type argument for each type parameter and in doing so
constrain the generic type to act only on the argument types.

Defining and Using Generic Types

To define a generic, you include type parameters following the type name. The type parameters
are a comma separated list of identifiers delimited by angle brackets. By convention, type
parameters are uppercase letters. The type parameters then appear in the type's methods, either as
the type of arguments in the method's parameter list or as the type of its return value.

GenSample.java contains a very simple generic class called BasicGeneric, and a second class
called GenSample that calls it.

class BasicGeneric <A>


{

358
private A data;

public BasicGeneric(A data)


{
this.data = data;
}

public A getData()
{
return data;
}
}

public class GenSample


{
public String test01(String input)
{
String data01 = input;
BasicGeneric<String> basicGeneric = new
BasicGeneric<String>(data01);
String data02 = basicGeneric.getData();
return data02;
}

public int test02(int input)


{
Integer data01 = new Integer(input);
BasicGeneric <Integer> basicGeneric = new
BasicGeneric<Integer>(data01);
Integer data02 = basicGeneric.getData();
return data02;
}

public static void main(String [] args)


{
GenSample sample = new GenSample();
System.out.println(sample.test01("This generic
data"));
System.out.println(sample.test02(12));
}
}

Here you can see the brackets that surround the capital letter A: <A>.  This syntax specifies that
the class is a generic type. Notice also that the class declares a variable of type A – data. This
syntax can be confusing at first glance. But it is quite sensible when you begin to understand
generics. BasicGeneric does not work with any specific type. As a result, we don't assign a type
to A. It is a generic type. But when you declare an instance of this class, you must specify the
type with which you want to work:

BasicGeneric<String> basicGeneric

359
The method getData() returns a value of type A, which is to say that it will return a generic type.
But that does not mean that the function will not have a type at run time, or even at compile time.
After you declare an instance of BasicGeneric, you will have specified the type of A. After that,
BasicGeneric will act as if it were declared from the very beginning to work with that specific
type, and that type only.

16.3 What Is a Collections Framework?

A collections framework is a unified architecture for representing and manipulating collections.


The collections framework is a part of java.util package. All collections frameworks contain
three things:
 Interfaces: abstract data types representing collections. Interfaces allow collections to be
manipulated independently of the details of their representation. In object-oriented
languages like Java, these interfaces generally form a hierarchy.
 Implementations: concrete implementations of the collection interfaces. In essence,
these are reusable data structures.
 Algorithms: methods that perform useful computations, like searching and sorting, on
objects that implement collection interfaces. These algorithms are said to be
polymorphic because the same method can be used on many different implementations of
the appropriate collections interface. In essence, algorithms are reusable functionality.

Benefits of Collection Framework

 It reduces programming effort: By providing useful data structures and algorithms, a


collections framework frees you to concentrate on the important parts of your program,
rather than the low-level plumbing required to make it work. By facilitating
interoperability among unrelated APIs, the collections framework frees you from writing
oodles of adapter objects or conversion code to connect APIs.
 It increases program speed and quality: The collections framework does this primarily
by providing high-performance, high-quality implementations of useful data structures
and algorithms. Also, because the various implementations of each interface are
interchangeable, programs can be easily tuned by switching collection implementations.
Finally, because you're freed from the drudgery of writing your own data structures,
you'll have more time to devote to improving the quality and performance of the rest of
the program.
 It allows interoperability among unrelated APIs: The collections interfaces will
become the "lingua franca" by which APIs pass collections back and forth. If my
network administration API furnishes a Collection of node names, and your GUI
toolkit expects a Collection of column headings, our APIs will interoperate seamlessly
even though they were written independently.
 It reduces the effort to learn and use new APIs: Many APIs naturally take collections
on input and output. In the past, each such API had a little "sub-API" devoted to
manipulating its collections. There was little consistency among these ad-hoc collections
sub-APIs, so you had to learn each one from scratch and it was easy to make mistakes
when using them. With the advent of standard collections interfaces, the problem goes
away.

360
 It reduces effort to design new APIs: This is the flip-side of the previous advantage:
designers and implementers don't have to reinvent the wheel each time they create an API
that relies on collections. They just use the standard collections interfaces.
 It 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.

16.4 Collection Interfaces

The core collection interfaces are the interfaces used to manipulate collections, and to pass them
from one method to another. The basic purpose of these interfaces is to allow collections to be
manipulated independently of the details of their representation. The core collection interfaces
are the heart and soul of the collections framework. The core collections interfaces are shown
below:

Note that all of the core collection interfaces are generic. For example, the declaration of the
Collection interface is:

public interface Collection<E> ...

The <E> syntax tells you that the interface is generic. When you declare a <code> Collection
instance you can and should specify the type of object contained in the collection. Specifying the
type allows the compiler to verify (at compile time) that the type of object you put into the
collection is correct, thus reducing errors at runtime.

Collection

The Collection interface is the root of the collection hierarchy. The Collection interface is the
least common denominator that all collections implement, and is used to pass collections around
and to manipulate them when maximum generality is desired. Some types of collections allow
duplicate elements, and others do not. Some are ordered and others unordered. The Java platform
doesn't provide any direct implementations of this interface but provides implementations of
more specific subinterfaces, such as Set and List.

Set

A Set is a collection that cannot contain duplicate elements. As you might expect, this interface
models the mathematical set abstraction. The Set interface extends Collection and contains no

361
methods other than those inherited from Collection. It is used to represent sets like the cards
comprising a poker hand, the courses making up a student's schedule, or the processes running
on a machine.

List

A List is an ordered collection (sometimes called a sequence). Lists can contain duplicate
elements. The user of a List generally has precise control over where in the List each element
is inserted. The user can access elements by their integer index (position).

Queue

A collection used to hold multiple elements prior to processing. Besides basic Collection
operations, queues provide additional insertion, extraction, and inspection operations. Queues
typically, but do not necessarily, order elements in a FIFO (first-in-first-out) manner. Among the
exceptions are priority queues, which order elements according to a supplied comparator, or the
elements' natural ordering. Whatever the ordering used, the head of the queue is that element that
would be removed by a call to remove or poll. In a FIFO queue, all new elements are inserted at
the tail of the queue. Other kinds of queues may use different placement rules. Every Queue
implementation must specify its ordering properties.

Map

A Map is an object that maps keys to values. Maps cannot contain duplicate keys: Each key can
map to at most one value.

SortedSet

A SortedSet is a Set that maintains its elements in ascending order.

SortedMap

A SortedMap is a Map that maintains its mappings in ascending key order. It is the Map analogue
of SortedSet. The SortedMap interface is used for apps like dictionaries and telephone
directories.

16.5 The Collection Interface

The Collection interface is used to pass around collections of objects where maximum generality
is desired. For example, by convention all general-purpose collection implementations have a
constructor that takes a Collection argument. This constructor, known as a conversion
constructor, initializes the new collection to contain all the elements in the specified Collection,
whatever the given collection's subinterface or implementation type. In other words, it allows
you to convert the type of the collection.

362
Suppose, for example, that you have a Collection<String> c, which may be a List, a Set, or
another kind of Collection. The following idiom creates a new ArrayList (an implementation of
the List interface), initially containing all the elements in c:

List<String> list = new ArrayList<String>(c);

The interface does about what you'd expect, given that a Collection represents a group of objects.
The interface has methods to tell you how many elements are in the collection (size, isEmpty), to
check whether a given object is in the collection (contains), to add and remove an element from
the collection (add, remove), and to provide an iterator over the collection (iterator).

The add method is defined generally enough so that it makes sense for collections that allow
duplicates as well as those that don't. It guarantees that the Collection will contain the specified
element after the call completes, and returns true if the Collection changes as a result of the call.
Similarly, the remove method is defined to remove a single instance of the specified element
from the Collection, assuming that it contains the element to start with, and to return true if the
Collection was modified as a result.

The following program shows a simple use of ArrayList. An arraylist is created , and then
objects of type String are added to it. The list is then displayed. Some of the elements are
removed and the list is displayed again.

import java.util.*;

class ArrayListDemo {
public static void main(String args[]) {
//create an array list
ArrayList al = new ArrayList();
System.out.println(“Initial size of al :”+al.size());
//add elements to arraylist
al.add(“C”);
al.add(“A”);
al.add(“E”);
al.add(“B”);
al.add(“D”);
al.add(“F”);
System.out.println(“Size of al after additions:” +
al.size());
//display the array list
System.out.println(“Contents of al:”+al);
//Remove elements from arraylist
al.remove(“F”);
al.remove(“E”);
System.out.println(“Size of al after deletions :”
+al.size());
System.out.println(“Contents of al : ” + al);
}
}

363
The output of this program is shown here:

Initial size of al : 0
Size of al after additions : 6
Contents of al : [C,A,E,B,D,F]
Size of al after deletions : 4
Contents of al : [C,A,B,D]

Traversing Collections

There are two ways to traverse collections: with the for-each construct and using iterators.

For-Each Construct

The for-each construct allows you to concisely traverse a collection or array using a for loop The
for Statement. The following code uses the for-each construct to print out each element of a
collection on a separate line:

for (Object o : collection)


System.out.println(o);

The following code shows an example

import java.util.*;

class ArrayListDemo2 {
public static void main(String args[]) {
ArrayList al = new ArrayList();
al.add(new Integer(10));
al.add(“ABC”);
al.add(new Float(1.0));
for(Object o : al) {
System.out.println(o);
}
}
}

Iterators

An Iterator is an object that enables you to traverse through a collection, and to remove elements
from the collection selectively, if desired. You get an Iterator for a collection by calling its
iterator method.

The hasNext method returns true if the iteration has more elements, and the next method returns
the next element in the iteration. The remove method removes from the underlying Collection
the last element that was returned by next. The remove method may be called only once per call
to next and throws an exception if this rule is violated.

364
Note that Iterator.remove is the only safe way to modify a collection during iteration; the
behavior is unspecified if the underlying collection is modified in any other way while the
iteration is in progress.

Use an iterator instead of the for-each construct when:

 You need to remove the current element. The for-each construct hides the iterator, so you
cannot call remove. Therefore, the for-each construct is not usable for filtering.
 You need to replace elements in a list or array as you traverse it.
 You need to iterate over multiple collections in parallel.

An example that shows the use of Iterator:

//Demonstrate Iterators
import java.util.*;

class IteratorDemo {
public static void main(String args[]) {
ArrayList al = new ArrayList();
//add elements to arraylist
al.add(“A”);
al.add(“B”);
al.add(“C”);
al.add(“D”);
al.add(“E”);
//use Iterator to display contents of al
Iterator itr = al.iterator();
while(itr.hasNext()) {
Object element = itr.next();
System.out.print(element+ “ ”);
if(((String)element).equals(“E”)) {
itr.remove();
}
}
System.out.println();
System.out.println(al);
}
}

The output of this program is as follows :

A B C D E
[A,B,C,D]

Collection Interface Bulk Operations

The bulk operations perform an operation on an entire Collection. You could implement these
shorthand operations using the basic operations, though in most cases such implementations
would be less efficient. The bulk operations are:

365
 containsAll: Returns true if the target Collection contains all of the elements in the
specified Collection.
 addAll: Adds all the elements in the specified Collection to the target Collection.
 removeAll: Removes from the target Collection all its elements that are also contained
in the specified Collection.
 retainAll: Removes from the target Collection all its elements that are not also
contained in the specified Collection. That is, it retains in the target Collection only
those elements that are also contained in the specified Collection.
 clear: Removes all elements from the Collection.

The addAll, removeAll, and retainAll methods all return true if the target Collection was
modified in the process of executing the operation.

Collection Interface Array Operations

The toArray methods are provided as a bridge between collections and older APIs that expect
arrays on input. The array operations allow the contents of a Collection to be translated into an
array. The simple form with no arguments creates a new array of Object. The more complex
form allows the caller to provide an array or to choose the runtime type of the output array.

For example, suppose that c is a Collection. The following snippet dumps the contents of c into a
newly allocated array of Object whose length is identical to the number of elements in c:

Object[] a = c.toArray();

Suppose that c is known to contain only strings (perhaps because c is of type


Collection<String>). The following snippet dumps the contents of c into a newly allocated
array of String whose length is identical to the number of elements in c:

String[] a = c.toArray(new String[0]);

An example of converting an ArrayList into an array.

import java.util.*;

class ArrayListToArray {
public static void main(String args[]){
ArrayList al = new ArrayList();
//add elements to array list
al.add(new Integer(1));
al.add(new Integer(2));
al.add(new Integer(3));
al.add(new Integer(4));
System.out.println(“Contents of al:”+al);
//get array
Object [] ia = al.toArray();
int sum=0;

366
//sum of array elements
for(int i=0; i < ia.length ; i++) {
sum += (Integer)ia;
}
System.out.println(“Sum is:”+sum);
}
}

The output of the program is shown below:

Contents of al: [1,2,3,4]


Sum is: 10

16.6 The Set Interface

A Set is a Collection that cannot contain duplicate elements. It models the mathematical set
abstraction. The Set interface contains only methods inherited from Collection, and adds the
restriction that duplicate elements are prohibited. Set also adds a stronger contract on the
behavior of the equals and hashCode operations, allowing Set instances to be compared
meaningfully even if their implementation types differ. Two Set instances are equal if they
contain the same elements.

The Java platform contains three general-purpose Set implementations: HashSet, TreeSet, and
LinkedHashSet HashSet, which stores its elements in a hash table, is the best-performing
implementation but it makes no guarantees concerning the order of iteration. TreeSet, which
stores its elements in a red-black tree, orders its elements based on their values, but is
substantially slower than HashSet. LinkedHashSet, which is implemented as a hash table with a
linked list running through it, orders its elements based on the order in which they were inserted
into the set (insertion-order). LinkedHashSet spares its clients from the unspecified, generally
chaotic ordering provided by HashSet, at a cost that is only slightly higher.

Here's a simple but useful Set idiom. Suppose you have a Collection, c, and you want to create
another Collection containing the same elements but with all duplicates eliminated. The
following one-liner does the trick:

Collection<Type> noDups = new HashSet<Type>(c);

It works by creating a Set, which by definition, cannot contain duplicate,) initially containing all
the elements in c

Here is a minor variant of this idiom that preserves the order of the original collection while
removing duplicate element:

Collection<Type> noDups = new HashSet<Type>(c);

Here is a generic method that encapsulates the above idiom, returning a set of the same generic
type as the one passed in:

367
public static <E> Set<E> removeDups(Collection<E> c) {
return new LinkedHashSet<E>(c);
}

Set Interface Basic Operations

The size operation returns the number of elements in the Set (its cardinality). The isEmpty
method does exactly what you think it does. The add method adds the specified element to the
Set if it's not already present, and returns a Boolean indicating whether the element was added.
Similarly, the remove method removes the specified element from the Set if it's present and
returns a Boolean indicating whether the element was present. The iterator method returns an
Iterator over the Set.

Here's a program that takes the words in its argument list and prints out any duplicate words, the
number of distinct words, and a list of the words with duplicates eliminated:

import java.util.*;
public class FindDups {
public static void main(String args[]) {
Set<String> s = new HashSet<String>();
for (String a : args) {
if (!s.add(a)) {
System.out.println("Duplicate: " + a);
}
}
System.out.println(s.size()+" distinct words:" + s);
}
}

Now let's run the program:

java FindDups i came i saw i left

The following output is produced:

Duplicate: i
Duplicate: i
4 distinct words: [i, left, saw, came]

Note that the code always refers to the collection by its interface type (Set), rather than by its
implementation type (HashSet). This is a strongly recommended programming practice, as it
gives you the flexibility to change implementations merely by changing the constructor. If either
the variables used to store a collection or the parameters used to pass it around are declared to be
of the collection's implementation type rather than its interface type, all such variables and
parameters must be changed in order to change the collection's implementation type. If the
program uses any nonstandard operations that are present in the original implementation type but

368
not in the new one, the program will fail. Referring to collections only by their interface prevents
you from using any nonstandard operations.

The implementation type of the Set in the preceding example is HashSet, which makes no
guarantees as to the order of the elements in the Set. If you want the program to print the word
list in alphabetical order, merely change the set's implementation type from HashSet to TreeSet.
Making this trivial one-line change causes the command line in the previous example to generate
the following output:

java FindDups i came i saw i left


Duplicate word: i
Duplicate word: i
4 distinct words: [came, i, left, saw]

Set Interface Bulk Operations

The bulk operations are particularly well suited to Sets; when applied to sets, they perform
standard set-algebraic operations. Suppose s1 and s2 are Sets. Here's what the bulk operations
do:

 s1.containsAll(s2): Returns true if s2 is a subset of s1. (s2 is a subset of s1 if set s1


contains all the elements in s2.)
 s1.addAll(s2): Transforms s1 into the union of s1 and s2. (The union of two sets is
the set containing all the elements contained in either set.)
 s1.retainAll(s2): Transforms s1 into the intersection of s1 and s2. (The intersection
of two sets is the set containing only the elements that are common to both sets.)
 s1.removeAll(s2): Transforms s1 into the (asymmetric) set difference of s1 and s2.
(For example, the set difference of s1 - s2 is the set containing all the elements found in
s1 but not in s2.)

To calculate the union, intersection, or set difference of two sets nondestructively (without
modifying either set), the caller must copy one set before calling the appropriate bulk operation.
The resulting idioms follow:

Set<Type> union = new HashSet<Type>(s1);


union.addAll(s2);

Set<Type> intersection = new HashSet<Type>(s1);


intersection.retainAll(s2);

Set<Type> difference = new HashSet<Type>(s1);


difference.removeAll(s2);

The implementation type of the result Set in the preceding idioms is HashSet, which is, as
already mentioned, the best all-around Set implementation in the Java platform. However, any
general-purpose Set implementation could be substituted.

369
Let's revisit the FindDups program. Suppose that you want to know which words in the argument
list occur only once and which occur more than once but that you do not want any duplicates
printed out repeatedly. This effect can be achieved by generating two sets, one containing every
word in the argument list and the other containing only the duplicates. The words that occur only
once are the set difference of these two sets, which we know how to compute. Here's how the
resulting program looks:

import java.util.*;

public class FindDups2 {


public static void main(String args[]) {
Set<String> uniques = new HashSet<String>();
Set<String> dups = new HashSet<String>();

for (String a : args) {


if (!uniques.add(a)) {
dups.add(a);
}
}

// Destructive set-difference
uniques.removeAll(dups);
System.out.println("Unique words: " + uniques);
System.out.println("Duplicate words: " + dups);
}
}

When run with the same same argument list used earlier (i came i saw i left), the program yields
the output:

Unique words: [left, saw, came]


Duplicate words: [i]

A less common set-algebraic operation is the symmetric set difference: the set of elements
contained in either of two specified sets but not in both. The following code calculates the
symmetric set difference of two sets nondestructively:

Set<Type> symmetricDiff = new HashSet<Type>(s1);


symmetricDiff.addAll(s2);
Set<Type> tmp = new HashSet<Type>(s1);
tmp.retainAll(s2));
symmetricDiff.removeAll(tmp);

Set Interface Array Operations

The array operations don't do anything special for Sets beyond what they do for any other
Collection.

Set Implementations

370
HashSet extends AbstractSet and implements the Set interface. It creates a collection that uses a
hash table for storage. An example of using HashSet.

import java.util.*;

class HashSetDemo {
public static void main(String args[]) {
//create a hash set
HashSet hs = new HashSet();
hs.add(“A”);
hs.add(“B”);
hs.add(“C”);
hs.add(“D”);
hs.add(“E”);
System.out.println(hs);
}
}

The LinkedHashSet extends HashSet and maintains a linked list of entries in the set in the order
in which they were inserted.

TreeSet stores objects in ascending order. Access and retrieval times are quite fast which makes
TreeSet an excellent choice when storing large amounts of sorted information that must be found
quickly. An example of TreeSet is shown below:

import java.util.*;

class TreeSetDemo {
public static void main(String args[]) {
TreeSet ts = new TreeSet();
ts.add(“C”);
ts.add(“A”);
ts.add(“B”);
ts.add(“E”);
ts.add(“F”);
ts.add(“D”);
System.out.println(ts);
}
}

The output from this program is shown here:

[A,B,C,D,E,F]

16.7 The List Interface

A List is an ordered Collection (sometimes called a sequence). Lists may contain duplicate
elements. In addition to the operations inherited from Collection, the List interface includes
operations for the following:

371
 Positional Access: Manipulate elements based on their numerical position in the list.
 Search: Search for a specified object in the list and return its numerical position.
 List Iteration: Extend Iterator semantics to take advantage of the list's sequential
nature.
 Range-view: Perform arbitrary range operations on the list.

The Java platform contains two general-purpose List implementations. ArrayList, which is
generally the better-performing implementation, and LinkedList which offers better
performance under certain circumstances. Also, Vector has been retrofitted to implement List.

Comparison to Vector

If you've used Vector, you're already familiar with the general flavor of List. List fixes several
minor API deficiencies in Vector. Commonly used Vector operations such as elementAt and
setElementAt, have been given much shorter names. When you consider that these two
operations are the List analogue of square brackets for arrays, it becomes apparent that shorter
names are highly desirable. Consider the following assignment statement:

a[i] = a[j].times(a[k]);

The Vector equivalent is:

v.setElementAt(v.elementAt(j).times(v.elementAt(k)), i);

The List equivalent is:

v.set(i, v.get(j).times(v.get(k)));

You may already have noticed that the set method, which replaces the Vector method
setElementAt, reverses the order of the arguments so that they match the corresponding array
operation. Consider this assignment statement:

gift[5] = "golden rings";

The Vector equivalent is:

gift.setElementAt("golden rings", 5);

The List equivalent is:

gift.set(5, "golden rings");

For consistency's sake, the method add(int, E), which replaces insertElementAt(Object, int),
also reverses the order of the arguments.

The various range operations in Vector (indexOf, lastIndexOf(setSize) have been replaced by a
single range-view operation (subList), which is far more powerful and consistent.

372
Collection Operations

The operations inherited from Collection all do about what you'd expect them to do, assuming
you're already familiar with them from Collection. The remove operation always removes the
first occurrence of the specified element from the list. The add and addAll operations always
append the new element(s) to the end of the list. Thus, the following idiom concatenates one list
to another:

list1.addAll(list2);

Here's a non-destructive form of this idiom, which produces a third List consisting of the
second list appended to the first:

List<Type> list3 = new ArrayList<Type>(list1);


list3.addAll(list2);

Note that the idiom, in its non-destructive form, takes advantage of ArrayList's standard
conversion constructor.

Like the Set interface, List strengthens the requirements on the equals and hashCode methods so
that two List objects can be compared for logical equality without regard to their implementation
classes. Two List objects are equal if they contain the same elements in the same order.

Positional Access and Search Operations

The basic positional access operations (get, set, add and remove) behave just like their longer-
named counterparts in Vector (elementAt, setElementAt, insertElementAt and
removeElementAt) with one noteworthy exception. The set and remove operations return the
old value that is being overwritten or removed; the Vector counterparts (setElementAt and
removeElementAt) return nothing (void). The search operations indexOf and lastIndexOf
behave exactly like the identically named operations in Vector.

The addAll operation inserts all of the elements of the specified Collection starting at the
specified position. The elements are inserted in the order they are returned by the specified
Collection's iterator. This call is the positional access analogue of Collection's addAll operation.

Here's a little method to swap two indexed values in a List:

public static <E> void swap(List<E> a, int i, int j) {


E tmp = a.get(i);
a.set(i, a.get(j));
a.set(j, tmp);
}

Of course there's one big difference. This is a polymorphic algorithm: It swaps two elements in
any List, regardless of its implementation type. Here's another polymorphic algorithm that uses
the swap method above:

373
public static void shuffle(List<?> list, Random rnd) {
for (int i = list.size(); i > 1; i--)
swap(list, i - 1, rnd.nextInt(i));
}

This algorithm, which is included in the Java platform's Collections class, randomly permutes
the specified List using the specified source of randomness. It's a bit subtle: It runs up the list
from the bottom, repeatedly swapping a randomly selected element into the current position.
Unlike most naive attempts at shuffling, it's fair (all permutations occur with equal likelihood,
assuming an unbiased source of randomness) and fast (requiring exactly list.size()-1 swaps).
The following program uses this algorithm to print the words in its argument list in random
order:

import java.util.*;

public class Shuffle {


public static void main(String args[]) {
List<String> list = new ArrayList<String>();
for (String a : args) {
list.add(a);
}
Collections.shuffle(list, new Random());
System.out.println(list);
}
}

We can make this program even shorter and faster. The Arrays class has a static factory method
called asList that allows an array to be viewed as a List. This method does not copy the array.
Changes in the List write through to the array, and vice-versa. The resulting List is not a
general-purpose List implementation, in that it doesn't implement the (optional) add and remove
operations: Arrays are not resizable. Taking advantage of Arrays.asList and calling the library
version of shuffle that uses a default source of randomness, you get the following tiny
program, whose behavior is identical to the previous program:

import java.util.*;

public class Shuffle {


public static void main(String args[]) {
List<String> list = Arrays.asList(args);
Collections.shuffle(list);
System.out.println(list);
}
}

An example that demonstrates the use of various algorithms

import java.util.*;

class AlgorithmDemo {

374
public static void main(String args[]) {
ArrayList al = new ArrayList();
al.add(new Integer(-8));
al.add(new Integer(20));
al.add(new Integer(-20));
al.add(new Integer(8));
//create a reverse order Comparator
Comparator r = Collections.reverseOrder();
//Sort list using comparator
Collections.sort(al,r);
//Get iterator
Iterator itr = al.iterator();
System.out.println(“List sorted in reverse:”);
while(itr.hasNext()) {
System.out.print(li.next()+ “ ”);
}
System.out.println();
Collections.shuffle(al);
//display randomized list
itr = al.iterator();
System.out.println(“List shuffled:”);
while(itr.hasNext()) {
System.out.print(li.next()+ “ ”);
}
System.out.println();
System.out.println(“Minimum:”+Collections.min(al));
System.out.println(“Maximum:”+Collections.max(al));
}
}

An example that shows the use of Arrays class

import java.util.*;

class ArraysDemo {
public static void main(String args[]) {
//allocate and initialize array
int array[] =new int[10];
for(int i=0; i< 10; i++) {
array[i] = -3 * i;
}
//display, sort and display
System.out.print(“Original contents:”);
display(array);
Arrays.sort(array);
System.out.print(“Sorted:”);
display(array);

//fill and display


Arrays.fill(array,2,6,-1);
System.out.print(“After fill:”);

375
display(array);

//sort and display


Arrays.sort(array);
System.out.print(“After sorting again:”);
display(array);

//binary search for –9


System.out.print(“The value –9 is at location:”);
int index = Arrays.binarySearch(array,-9);
System.out.print(index);
}

static void display(int array[]) {


for(int i= 0 ;i<array.length;i++) {
System.out.print(array[i]+ “ ");
}
System.out.println();
}
}

The output is as follows:

Original contents : 0 –3 –6 –9 –12 –15 –18 –21 –24 –27


Sorted : -27 –24 –21 –18 –15 –12 –9 –6 –3 0
After fill: -27 –24 –1 –1 –1 –1 –9 –6 –3 0
After sorting again: -27 –24 –9 –6 –3 –1 –1 –1 –1 0
The value –9 is at location 2

Iterators

The Iterator returned by List's iterator operation returns the elements of the list in proper
sequence. List also provides a richer iterator, called a ListIterator, that allows you to
traverse the list in either direction, modify the list during iteration, and obtain the current position
of the iterator.

The three methods that ListIterator inherits from Iterator (hasNext, next, and remove) do
exactly the same thing in both interfaces. The hasPrevious and the previous operations are
exact analogues of hasNext and next. The former operations refer to the element before the
(implicit) cursor, whereas the latter refer to the element after the cursor. The previous operation
moves the cursor backwards, whereas next moves it forwards.

Here's the standard idiom for iterating backwards through a list:

for (ListIterator<Type> i = list.listIterator(list.size());


i.hasPrevious(); ) {
Type t = i.previous();
...
}

376
Note the argument to listIterator in the preceding idiom. The List interface has two forms of the
listIterator method. The form with no arguments returns a ListIterator positioned at the beginning
of the list; the form with an int argument returns a ListIterator positioned at the specified index.
The index refers to the element that would be returned by an initial call to next. An initial call to
previous would return the element whose index was index-1. In a list of length n, there are n+1
valid values for index, from 0 to n, inclusive.

Intuitively speaking, the cursor is always between two elements, the one that would be returned
by a call to previous and the one that would be returned by a call to next. The n+1 valid index
values correspond to the n+1 gaps between elements, from the gap before the first element to the
gap after the last one. The figure below shows the five possible cursor positions in a list
containing four elements.

Calls to next and previous can be intermixed, but you have to be a bit careful. The first call to
previous returns the same element as the last call to next. Similarly, the first call to next after a
sequence of calls to previous returns the same element as the last call to previous.

It should come as no surprise that the nextIndex method returns the index of the element that
would be returned by a subsequent call to next, and previousIndex returns the index of the
element that would be returned by a subsequent call to previous. These calls are typically used
either to report the position where something was found or to record the position of the
ListIterator so that another ListIterator with identical position can be created.

It should also come as no surprise that the number returned by nextIndex is always one greater
than the number returned by previousIndex. This implies the behavior of the two boundary cases:
a call to previousIndex when the cursor is before the initial element returns -1, and a call to
nextIndex when the cursor is after the final element returns list.size(). To make all of this
concrete, here's a possible implementation of List.indexOf:

public int indexOf(E o) {


for (ListIterator<E> i = listIterator(); i.hasNext(); ) {
if (o==null ? i.next()==null : o.equals(i.next())) {
return i.previousIndex();
}
}
return -1; // Object not found
}

Note that the indexOf method returns i.previousIndex() though it is traversing the list in the
forward direction. The reason is that i.nextIndex() would return the index of the element that we
are about to examine, and we want to return the index of the element that we just examined.

377
The Iterator interface provides the remove operation to remove from the Collection the last
element returned by next. For ListIterator, this operation removes the last element returned by
next or previous. The ListIterator interface provides two additional operations to modify
the list: set and add. The set method overwrites the last element returned by next or previous
with the specified element. The following polymorphic algorithm uses set to replace all
occurrences of one specified value with another:

public static <E> void replace(List<E> s, E val, E newVal) {


for (ListIterator<E> i = s.listIterator(); i.hasNext(); ) {
if (val==null ? i.next()==null : val.equals(i.next())) {
i.set(newVal);
}
}
}

The only bit of trickiness in this example is the equality test between val and i.next. We have
to special-case an val value of null in order to prevent a NullPointerException.

The add method inserts a new element into the list, immediately before the current cursor
position. This method is illustrated in the following polymorphic algorithm to replace all
occurrences of a specified value with the sequence of values contained in the specified list:

public static <E> void replace(List<E> s, E val,


List<E> newVals) {
for (ListIterator<E> i = s.listIterator(); i.hasNext();){
if (val==null ? i.next()==null : val.equals(i.next())) {
i.remove();
for (E e : newVals)
i.add(e);
}
}
}

Range-View Operation

The range-view operation, subList(int fromIndex, int toIndex), returns a List view of
the portion of this list whose indices range from fromIndex, inclusive, to toIndex, exclusive.
This half-open range mirrors the typical for loop:

for (int i = fromIndex; i < toIndex; i++) {


...
}

As the term view implies, the returned List is backed by the List on which subList was
called, so changes in the former List are reflected in the latter.

This method eliminates the need for explicit range operations (of the sort that commonly exist
for arrays). Any operation that expects a List can be used as a range operation by passing a

378
subList view instead of a whole List. For example, the following idiom removes a range of
elements from a list:

list.subList(fromIndex, toIndex).clear();

Similar idioms may be constructed to search for an element in a range:

int i = list.subList(fromIndex, toIndex).indexOf(o);


int j = list.subList(fromIndex, toIndex).lastIndexOf(o);

Note that the above idioms return the index of the found element in the subList, not the index in
the backing List.

Any polymorphic algorithm that operates on a List, such as the replace and shuffle examples
above, works with the List returned by subList.

Here's a polymorphic algorithm whose implementation uses subList to deal a hand from a deck.
That is to say, it returns a new List (the "hand") containing the specified number of elements
taken from the end of the specified List (the "deck"). The elements returned in the hand are
removed from the deck.

public static <E> List<E> dealHand(List<E> deck, int n) {


int deckSize = deck.size();
List<E> handView = deck.subList(deckSize - n, deckSize);
List<E> hand = new ArrayList<E>(handView);
handView.clear();
return hand;
}

Note that this algorithm removes the hand from the end of the deck. For many common List
implementations, such as ArrayList, the performance of removing elements from the end of the
list is substantially better than that of removing elements from the beginning.

Here's a program using the dealHand method in combination with Collections.shuffle to generate
hands from a normal 52-card deck. The program takes two command line arguments: the number
of hands to deal and the number of cards in each hand.

import java.util.*;

class Deal {
public static void main(String[] args) {
int numHands = Integer.parseInt(args[0]);
int cardsPerHand = Integer.parseInt(args[1]);

// Make a normal 52-card deck


String[] suit = new String[]
{"spades", "hearts", "diamonds", "clubs"};
String[] rank = new String[]
{"ace","2","3","4","5","6","7","8",

379
"9","10","jack","queen","king"};
List<String> deck = new ArrayList<String>();
for (int i = 0; i <suit.length; i++) {
for (int j = 0; j <rank.length; j++) {
deck.add(rank[j] + " of " + suit[i]);
}
}
Collections.shuffle(deck);

for (int i=0; i<numHands; i++) {


System.out.println(dealHand(deck, cardsPerHand));
}
}
}

Running the program produces the following output:

java Deal 4 5

[8 of hearts, jack of spades, 3 of spades, 4 of spades,


king of diamonds]
[4 of diamonds, ace of clubs, 6 of clubs, jack of hearts,
queen of hearts]
[7 of spades, 5 of spades, 2 of diamonds, queen of diamonds,
9 of clubs]
[8 of spades, 6 of diamonds, ace of spades, 3 of hearts,
ace of hearts]

Although the subList operation is extremely powerful, some care must be exercised when using
it. The semantics of the List returned by subList become undefined if elements are added to or
removed from the backing List in any way other than via the returned List. Thus, it's highly
recommended that you use the List returned by subList only as a transient object: to perform one
or a sequence of range operations on the backing List. The longer you use the sublist instance,
the greater the probability that you'll compromise it by modifying the backing List directly or
through another sublist object. Note that it is legal to modify a sublist of a sublist and to continue
using the original sublist (though not concurrently).

List Algorithms

Most of the polymorphic algorithms in the Collections class apply specifically to List. Having all
these algorithms at your disposal makes it very easy to manipulate lists. Here's a summary of
these algorithms.

 sort: Sorts a List using a merge sort algorithm, which provides a fast, stable sort. (A
stable sort is one that does not reorder equal elements.)
 shuffle: Randomly permutes the elements in a List.
 reverse: Reverses the order of the elements in a List.
 rotate: Rotates all of the elements in a List by a specified distance.
 swap: Swaps the elements at specified positions in in a List.

380
 replaceAll: Replaces all occurrences of one specified value with another.
 fill: Overwrites every element in a List with the specified value.
 copy: Copies the source List into the destination List.
 binarySearch: Searches for an element in an ordered List using the binary search
algorithm.
 indexOfSubList: Returns the index of the first sublist of one List that is equal to
another.
 lastIndexOfSubList: Returns the index of the last sublist of one List that is equal to
another.

16.8 The Queue Interface

A Queue is a collection for holding elements prior to processing. Besides basic Collection
operations, queues provide additional insertion, removal, and inspection operations.

Each Queue method exists in two forms: one throws an exception if the operation fails, the other
returns a special value (either null or false, depending on the operation). The regular structure
of the interface is illustrated in the following table:

Queue Interface Structure

  Throws exception Returns special value


Insert add(e) offer(e)
Remove remove() poll()
Examine element() peek()

Queues typically, but not necessarily, order elements in a FIFO (first-in-first-out) manner.
Among the exceptions are priority queues, which order elements according to a their values.
Whatever ordering is used, the head of the queue is the element that would be removed by a call
to remove or poll. In a FIFO queue, all new elements are inserted at the tail of the queue. Other
kinds of queues may use different placement rules. Every Queue implementation must specify its
ordering properties.

The add method, which Queue inherits from Collection, inserts an element unless it would
violate the queue's capacity restrictions, in which case it throws IllegalStateExcepion. The offer
method, which is intended solely for use on bounded queues, differs from add only in that it
indicates failure to insert an element by returning false.

The remove and poll methods both remove and return the head of the queue. Exactly which
element gets removed is a function of the queue's ordering policy. The remove and poll methods
differ in their behavior only when the queue is empty. Under these circumstances, remove throws
NoSuchElementException, while poll returns null.

381
The element and peek methods return, but do not remove, the head of the queue. They differ
from one another in precisely the same fashion as remove and poll: if the queue is empty,
element throws NoSuchElementException while peek returns false.

Queue implementations generally do not allow insertion of null elements. The LinkedList
implementation (which was retrofitted to implement Queue) is an exception. For historical
reasons, it permits null elements, but you should refrain from taking advantage of this, as null is
used as a special return value by the poll and peek methods.

Queue implementations generally do not define element-based versions of the equals and
hashCode methods but instead inherit the identity-based versions from Object.

In the following example program, a queue is used to implement a countdown timer. The queue
is preloaded with all the integer values from a number specified on the command line to zero, in
descending order. Then the values are removed from the queue and printed at one second
intervals. The program is artificial in that it would be more natural to do the same thing without
using a queue, but it illustrates the use of a queue to store elements prior to subsequent
processing:

import java.util.*;

public class Countdown {


public static void main(String[] args) throws
InterruptedException {
int time = Integer.parseInt(args[0]);
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = time; i >= 0; i--)
queue.add(i);
while(!queue.isEmpty()) {
System.out.println(queue.remove());
Thread.sleep(1000);
}
}
}

In the following example, a priority queue is used to sort a collection of elements. Again this
program is artificial, in that there is no reason to use it in favor of the sort method provided in
Collections, but it illustrates the behavior of priority queues:

static <E> List<E> heapSort(Collection<E> c) {


Queue<E> queue = new PriorityQueue<E>(c);
List<E> result = new ArrayList<E>();
while (!queue.isEmpty())
result.add(queue.remove());
return result;
}

The following program illustrates several methods supported by LinkedList.

382
import java.util.*;

class LinkedListDemo {
public static void main(String args[]) {
//create a linked list
LinkedList ll = new LinkedList();
//add elements to linked list
ll.add(“A”);
ll.add(“B”);
ll.add(“C”);
ll.add(“D”);
ll.addLast(“E”);
ll.addFirst(“F”);
ll.add(1, “A2”);
System.out.println(“Original contents of ll:”+ll);
//remove elements from linked list
ll.remove(“F”);
ll.remove(2);
System.out.println(“Contents of ll after deletion:”
+ ll);
//remove first and last elements
ll.removeFirst();
ll.removeLast();
System.out.println(“ll after deleting first and
last:”+ ll);
//get and set value
Object val = ll.get(1);
ll.set(1,(String)val+ “changed”);
System.out.println(“ll after change:” + ll);
}
}

The output of this program is shown here

Original contents of ll : [F,A,B,C,D,E]


Contents of ll after deletion: [A,B,D,E]
ll after deleting first and last: [B,D]
ll after change: [B,Dchanged]

16.9 The Map Interface

A Map is an object that maps keys to values. A map cannot contain duplicate keys: Each key can
map to at most one value.

The Java platform contains three general-purpose Map implementations: HashMap, TreeMap, and
LinkedHashMap. Their behavior and performance are precisely analogous to HashMap, TreeMap,
and LinkedHashMap. Also, Hashtable was retrofitted to implement Map.

Comparison to Hashtable

383
If you've used Hashtable, you're already familiar with the general flavor of Map. (Of course Map
is an interface, while Hashtable is a concrete implementation.) Here are the major differences:

 Map provides Collection views instead of direct support for iteration via Enumeration
objects. Collection views greatly enhance the expressiveness of the interface.
 Map allows you to iterate over keys, values, or key-value pairs; Hashtable does not
provide the third option.
 Map provides a safe way to remove entries in the midst of iteration; Hashtable did not.

Finally, Map fixes a minor deficiency in the Hashtable interface. Hashtable has a method called
contains, which returns true if the Hashtable contains a given value. Given its name, you'd
expect this method to return true if the Hashtable contained a given key, as the key is the
primary access mechanism for a Hashtable. The Map interface eliminates this source of
confusion by renaming the method containsValue. Also, this improves the consistency of the
interface: containsValue parallels containsKey.

Map Interface Basic Operations

The basic operations (put, get, containsKey, containsValue, size, and isEmpty) behave exactly
like their counterparts in Hashtable. Here's a program to generate a frequency table of the words
found in its argument list. The frequency table maps each word to the number of times it occurs
in the argument list.

import java.util.*;

public class Freq {


public static void main(String args[]) {
Map<String, Integer> m = new HashMap<String, Integer>();

// Initialize frequency table from command line


for (String a : args) {
Integer freq = m.get(a);
m.put(a, (freq == null ? 1 : freq + 1));
}
System.out.println(m.size() + " distinct words:");
System.out.println(m);
}
}

The only thing tricky about this program is the second argument of the put statement. That
argument is a conditional expression that has the effect of setting the frequency to one if the
word has never been seen before or one more than its current value if the word has already been
seen. Try running this program with the command:

java Freq if it is to be it is up to me to delegate

The program yields the following output:

384
8 distinct words:
{to=3, delegate=1, be=1, it=2, up=1, if=1, me=1, is=2}

Suppose you'd prefer to see the frequency table in alphabetical order. All you have to do is
change the implementation type of the Map from HashMap to TreeMap. Making this four-
character change causes the program to generate the following output from the same command
line:

8 distinct words:
{be=1, delegate=1, if=1, is=2, it=2, me=1, to=3, up=1}

Similarly, you could make the program print the frequency table in the order the words first
appear on the command line simply by changing the implementation type of the map to
LinkedHashMap. Doing so results in the following output:

8 distinct words:
{if=1, it=2, is=2, to=3, be=1, up=1, me=1, delegate=1}

This flexibility provides a potent illustration of the power of an interface-based framework.

Like the Set and List interfaces, Map strengthens the requirements on the equals and hashCode
methods so that two Map objects can be compared for logical equality without regard to their
implementation types. Two Map instances are equal if they represent the same key-value
mappings.

By convention, all Map implementations provide constructors that take a Map object and
initialize the new Map to contain all the key-value mappings in the specified Map. This standard
Map conversion constructor is entirely analogous to the standard Collection constructor: It
allows the caller to create a Map of a desired implementation type that initially contains all of the
mappings in another Map, regardless of the other Map's implementation type. For example,
suppose you have a Map, named m. The following one-liner creates a new HashMap initially
containing all of the same key-value mappings as m:

Map<K, V> copy = new HashMap<K, V>(m);

Map Interface Bulk Operations

The clear operation does exactly what you think it does: it removes all the mappings from the
Map. The putAll operation is the Map analogue of the Collection interface's addAll operation. In
addition to its obvious use of dumping one Map into another, it has a second, more subtle use.
Suppose a Map is used to represent a collection of attribute-value pairs; the putAll operation, in
combination with the Map conversion constructor, provides a neat way to implement attribute
map creation with default values. Here's a static factory method demonstrating this technique:

static <K, V> Map<K, V> newAttributeMap(


Map<K, V>defaults, Map<K, V> overrides) {
Map<K, V> result = new HashMap<K, V>(defaults);
result.putAll(overrides);

385
return result;
}

Collection Views

The Collection view methods allow a Map to be viewed as a Collection in these ways:

 keySet: the Set of keys contained in the Map.


 values: The Collection of values contained in the Map. This Collection is not a Set,
as multiple keys can map to the same value.

The Collection views provide the only means to iterate over a Map. Here's an example
illustrating the standard idiom for iterating over the keys in a Map with a for-each construct:

for (KeyType key : m.keySet())


System.out.println(key);

and with an iterator:

// Filter a map based on some property of its keys


for (Iterator<Type> i=m.keySet().iterator(); i.hasNext(); )
if (i.next().isBogus())
i.remove();

At first, many people worry that these idioms may be slow because the Map has to create a new
Collection instance each time a Collection view operation is called. There's no reason that a Map
can't always return the same object each time it is asked for a given Collection view. This is
precisely what all the Map implementations in java.util do.

With all three Collection views, calling an Iterator's remove operation removes the associated
entry from the backing Map, assuming that the backing map supports element removal to begin
with.

The Collection views support element removal in all its many forms: the remove, removeAll,
retainAll, and clear operations, as well as the Iterator.remove operation. (Yet again, this assumes
that the backing Map supports element removal.)

The Collection views do not support element addition under any circumstances. It would make
no sense for the keySet and values views, and it's unnecessary for the entrySet view, as the
backing Map's put and putAll provide the same functionality.

Fancy Uses of Collection Views: Map Algebra

When applied to the Collection views, the bulk operations (containsAll, removeAll and
retainAll) are a surprisingly potent tool. Suppose that you want to know whether two Map
objects contain mappings for all the same keys:

386
if (m1.keySet().equals(m2.keySet())) {
...
}

Suppose you have a map that represents a collection of attribute-value pairs, and two sets
representing required attributes and permissible attributes. (The permissible attributes include the
required attributes.) The following snippet determines whether the attribute map conforms to
these constraints and prints a detailed error message if it doesn't:

static <K, V> boolean validate(Map<K, V> attrMap,


Set<K> requiredAttrs, Set<K>permittedAttrs) {
boolean valid = true;
Set<K> attrs = attrMap.keySet();
if(!attrs.containsAll(requiredAttrs)) {
Set<K> missing = new HashSet<K>(requiredAttrs);
missing.removeAll(attrs);
System.out.println("Missing attributes: " + missing);
valid = false;
}
if (!permittedAttrs.containsAll(attrs)) {
Set<K> illegal = new HashSet<K>(attrs);
illegal.removeAll(permittedAttrs);
System.out.println("Illegal attributes: " + illegal);
valid = false;
}
return valid;
}

Suppose that you want to know all the keys common to two Map objects:

Set<KeyType>commonKeys = new HashSet<KeyType>(m1.keySet());


commonKeys.retainAll(m2.keySet);

A similar idiom gets you the common values.

All the idioms presented thus far have been nondestructive; that is, don't modify the backing
Map. Here are a few that do. Suppose that you want to remove all the key-value pairs that one
Map has in common with another:

m1.entrySet().removeAll(m2.entrySet());

Suppose you want to remove from one Map all the keys that have mappings in another:

m1.keySet().removeAll(m2.keySet());

What happens when you start mixing keys and values in the same bulk operation? Suppose that
you have a Map, managers, that maps each employee in a company to the employee's manager.
We'll be deliberately vague about the types of the key and the value objects. It doesn't matter, so

387
long as they're the same. Now suppose you want to know who all the "individual contributors"
(or nonmanagers) are. The following snippet tells you exactly what you want to know:

Set<Employee> individualContributors =
new HashSet<Employee>(managers.keySet());
individualContributors.removeAll(managers.values());

Suppose that you want to fire all the employees who report directly to some manager, Simon:

Employee simon = ... ;


managers.values().removeAll(Collections.singleton(simon));

Note that this idiom makes use of Collections.singleton, a static factory method that returns an
immutable Set with the single, specified element.

Once you've done this, you may have a bunch of employees whose managers no longer work for
the company (if any of Simon's direct-reports were themselves managers). The following code
tells you all of the employees whose manager no longer works for the company:

Map<Employee, Employee> m =
new HashMap<Employee, Employee>(managers);
m.values().removeAll(managers.keySet());
Set<Employee> slackers = m.keySet();

This example is a bit tricky. First, it makes a temporary copy of the Map, and it removes from
the temporary copy all entries whose (manager) value is a key in the original Map. Remember
that the original Map has an entry for each employee. Thus, the remaining entries in the
temporary Map comprise all the entries from the original Map whose (manager) values are no
longer employees. The keys in the temporary copy, then, represent precisely the employees that
we're looking for.

16.10 Object Ordering

A List l may be sorted as follows:

Collections.sort(l);

If the list consists of String elements, it will be sorted into alphabetical order. If it consists of
Date elements, it will be sorted into chronological order. How does this happen? String and Date
both implement the Comparable interface. The Comparable interfaces provides a natural
ordering for a class, which allows objects of that class to be sorted automatically. The following
table summarizes some of the more important Java platform classes that implement Comparable:

Classes Implementing Comparable

Class Natural Ordering


Character UnSigned numerical

388
Byte, Long, Integer, Short,
Double, Float, BigInteger, Signed numerical
BigDecimal
Boolean Boolean.FALSE < Boolean.TRUE
File System-dependent lexicographic on path name
String Lexicographic
Date Chronological
CollationKey Locale-specific lexicographic

If you try to sort a list whose elements do not implement Comparable, Collections.sort(list) will
throw a ClassCastException . Similarly, if you try to sort a list whose elements cannot be
compared to one another, Collections.sort will throw a ClassCastException. Elements that can be
compared to one another are called mutually comparable. Although elements of different types
be mutually comparable, none of classes listed here permit interclass comparison.

This is all you really need to know about the Comparable interface if you just want to sort lists of
comparable elements or to create sorted collections of them.

Writing Your Own Comparable Types

The Comparable interface consists of a single method:

public int compareTo(T o);

The compareTo method compares the receiving object with the specified object and returns a
negative integer, zero, or a positive integer as the receiving object is less than, equal to, or
greater than the specified object. If the specified object cannot be compared to the receiving
object, the method throws a ClassCastException.

The following class representing a person's name implements Comparable:

import java.util.*;

public final class Name implements Comparable<Name> {


private final String firstName, lastName;

public Name(String firstName, String lastName) {


if (firstName == null || lastName == null) {
throw new NullPointerException();
}
this.firstName = firstName;
this.lastName = lastName;
}

public String firstName() { return firstName; }


public String lastName() { return lastName; }

389
public boolean equals(Object o) {
if (!(o instanceof Name))
return false;
Name n = (Name) o;
return n.firstName.equals(firstName) &&
n.lastName.equals(lastName);
}

public int hashCode() {


return 31*firstName.hashCode() + lastName.hashCode();
}

public String toString() {


return firstName + " " + lastName;
}

public int compareTo(Name n) {


int lastCmp = lastName.compareTo(n.lastName);
return (lastCmp != 0 ? lastCmp :
firstName.compareTo(n.firstName));
}
}

To keep the example short, the class is somewhat limited: It doesn't support middle names, it
demands both a first and a last name, and it is not internationalized in any way. Nonetheless, it
illustrates several important points:

 Name objects are immutable. All other things being equal, immutable types are the way to
go, especially for objects that will be used as elements in Sets, or as keys in Maps. These
collections will break if you modify their elements or keys while they're in the collection.
 The constructor checks its arguments for null. This ensures that all Name objects are well
formed, so that none of the other methods will ever throw a NullPointerException.
 The hashCode method is redefined. This is essential for any class that redefines the
equals method. (Equal objects must have equal hash codes.)
 The equals method returns false if the specified object is null, or of an inappropriate
type. The compareTo method throws a runtime exception under these circumstances.
Both of these behaviors are required by the general contracts of the respective methods.
 The toString method has been redefined to print the Name in human-readable form. This
is always a good idea, especially for objects that are going to get put into collections. The
various collection types' toString methods depend on the toString methods of their
elements, keys and values.

Since this section is about element ordering, let's talk a bit more about Name's compareTo
method. It implements the standard name-ordering algorithm, where last names take precedence
over first names. This is exactly what you want in a natural ordering. It would be very confusing
if the natural ordering were unnatural!

390
Take a look at how compareTo is implemented, because it's quite typical. First, you compare the
most significant part of the object (in this case, the last name). Often, you can just use the natural
ordering of the part's type. In this case, the part is a String, and the natural (lexicographic)
ordering is exactly what's called for. If the comparison results in anything other than zero, which
represents equality, you're done: you just return the result. If the most significant parts are equal,
you go on to compare the next-most-significant parts. In this case, there are only two parts: first
name and last name. If there were more parts, you'd proceed in the obvious fashion, comparing
parts until you found two that weren't equal or you were comparing the least-significant parts, at
which point you'd return the result of the comparison.

Just to show that it all works, here's a program that builds a list of names and sorts them:

import java.util.*;

public static void main(String[] args) {


Name nameArray[] = {
new Name("John", "Lennon"),
new Name("Karl", "Marx"),
new Name("Groucho", "Marx"),
new Name("Oscar", "Grouch")
};
List<Name> names = Arrays.asList(nameArray);
Collections.sort(names);
System.out.println(names);
}
}

If you run this program, here's what it prints:

[Oscar Grouch, John Lennon, Groucho Marx, Karl Marx]

There are four restrictions on the behavior of the compareTo method, which we won't go over
now because they're fairly technical and boring and are better left in the API documentation. It's
really important that all classes that implement Comparable obey these restrictions, so read the
documentation for Comparable if you're writing a class that implements it. Attempting to sort a
list of objects that violate these restrictions has undefined behavior. Technically speaking, these
restrictions ensure that the natural ordering is a total order on the objects of a class that
implements it; this is necessary to ensure that sorting is well-defined.

Comparators

What if you want to sort some objects in an order other than their natural order? Or what if you
want to sort some objects that don't implement Comparable? To do either of these things, you'll
need to provide a Comparator, an object that encapsulates an ordering. Like the Comparable
interface, the Comparator interface consists of a single method:

int compare(T o1, T o2);

391
The compare method compares its two arguments, returning a negative integer, zero, or a
positive integer as the first argument is less than, equal to, or greater than the second. If either of
the arguments has an inappropriate type for the Comparator, the compare method throws a
ClassCastException.

Much of what was said about Comparable applies to Comparator as well. Writing a compare
method is nearly identical to writing a compareTo method, except that the former gets both
objects passed in as arguments. The compare method has to obey the same four technical
restrictions as Comparable's compareTo method, for the same reason: a Comparator must induce
a total order on the objects it compares.

Suppose that you have a class called Employee:

public class Employee implements Comparable<Employee> {


public Name name() { ... }
public int number() { ... }
public Date hireDate() { ... }
...
}

Let's assume that the natural ordering of Employee instances is Name ordering (as defined in the
previous example) on employee name. Unfortunately, the boss has asked us for a list of
employees in order of seniority. This means that we have to do some work, but not much. Here's
a program that will produce the required list:

import java.util.*;

class EmpSort {
static final Comparator<Employee> SENIORITY_ORDER =
new Comparator<Employee>() {
public int compare(Employee e1, Employee e2) {
return e2.hireDate().compareTo(e1.hireDate());
}
};

// Employee Database
static final Collection<Employee> employees = ... ;

public static void main(String[] args) {


List<Employee>e = new ArrayList<Employee>(employees);
Collections.sort(e, SENIORITY_ORDER);
System.out.println(e);
}
}

The Comparator in the program is reasonably straightforward. It relies on the natural ordering of
Date applied to the values returned by the hireDate accessor method. Note that the Comparator
passes the hire date of its second argument to its first, rather than vice versa. The reason is that
the employee who was hired most recently is least senior: sorting in order of hire date would put

392
the list in reverse seniority order. Another technique that people sometimes use to achieve this
effect is to maintain the argument order but to negate the result of the comparison:

//Don't do this!!
return -r1.hireDate().compareTo(r2.hireDate());

You should always use the former technique in favor of the latter, as the latter is not guaranteed
to work! The reason for this is that the compareTo method can return any negative int if its
argument is less than the object on which it is invoked. There is one negative int that remains
negative when negated. Strange as it may seem,

-Integer.MIN_VALUE == Integer.MIN_VALUE

The Comparator in the preceding program works fine for sorting a List, but it does have one
deficiency: it cannot be used to order a sorted collection, such as TreeSet, because it generates
an ordering that is not compatible with equals. This means that this comparator equates objects
that the equals method does not. In particular, any two employees who were hired on the same
date will compare as equal. When you're sorting a List, this doesn't matter, but when you're
using the Comparator to order a sorted collection, it's fatal. If you use this Comparator to insert
multiple employees hired on the same date into a TreeSet, only the first one will be added to the
set. The second will be seen as a duplicate element and will be ignored.

To fix this problem, simply tweak the Comparator so that it produces an ordering that is
compatible with equals. In other words, tweak it so that the only elements that are seen as equal
when using compare are those that are also seen as equal when compared using equals. The way
to do this is to do a two-part comparison (as we did for Name), where the first part is the one that
we're interested in (in this case, the hire date), and the second part is an attribute that uniquely
identifies the object. In this case, the employee number is the obvious attribute. Here's the
Comparator that results:

static final Comparator<Employee> SENIORITY_ORDER =


new Comparator<Employee>() {
public int compare(Employee e1, Employee e2) {
int dateCmp = e2.hireDate().compareTo(e1.hireDate());
if (dateCmp != 0)
return dateCmp;
return (e1.number() < e2.number() ? -1 :
(e1.number() == e2.number() ? 0 : 1));
}
};

One last note: You might be tempted to replace the final return statement in the Comparator with
the simpler:

return r1.empNumber() - r2.empNumber();

Don't do it unless you're absolutely sure that no one will ever have a negative employee number!
This trick does not work in general, as the signed integer type is not big enough to represent the

393
difference of two arbitrary signed integers. If i is a large positive integer and j is a large negative
integer, i - j will overflow and will return a negative integer. The resulting comparator violates
one of the four technical restrictions that we keep talking about (transitivity) and produces
horrible, subtle bugs. This is not a purely theoretical concern; people get burned by it.

An example of using Comparator:

import java.util.*;

//A reverse comparator for Strings


class MyComp implements Comparator {
public int compare(Object a, Object b) {
String astr,bstr;
astr = (String)a;
bstr = (String)b;
//reverse comparison
return bstr.compareTo(astr);
}

//no need to override equals


}

class CompDemo {
public static void main(String args[]) {
//create a tree set
TreeSet ts = new TreeSet(new MyComp());
//add elements to tree set
ts.add(“C”);
ts.add(“A”);
ts.add(“B”);
ts.add(“E”);
ts.add(“F”);
ts.add(“D”);
//Get an iterator
Iterator i = ts.iterator();
//display elements
while(i.hasNext()) {
Object element = i.next();
System.out.println(element + “ ”);
}
System.out.println();
}
}

As the following output shows, the tree is now sorted in the reverse order

F E D C B A

394
16.11 The SortedSet Interface

A SortedSet is a Set that maintains its elements in ascending order, sorted according to the
elements' natural order or according to a Comparator provided at SortedSet creation time. In
addition to the normal Set operations, the SortedSet interface provides operations for:

 Range view: Allows arbitrary range operations on the sorted set.


 Endpoints: Returns the first or last element in the sorted set.
 Comparator access: Returns the Comparator, if any, used to sort the set.

Set Operations

The operations that SortedSet inherits from Set behave identically on sorted sets and
normal sets with two exceptions:

 The Iterator returned by the iterator operation traverses the sorted set in
order.
 The array returned by toArray contains the sorted set's elements in order.

Although the interface doesn't guarantee it, the toString method of the Java platform's
SortedSet implementations returns a string containing all the elements of the sorted set, in
order.

Standard Constructors

By convention, all general-purpose Collection implementations provide a standard conversion


constructor that takes a Collection; SortedSet implementations are no exception. In TreeSet, this
constructor creates an instance that sorts its elements according to their natural order. It would
have been better to check dynamically if the specified collection were a SortedSet instance, and
if so, to sort the new TreeSet according to the same criterion (comparator or natural ordering).
Because TreeSet took the approach that it did, it also provides a constructor that takes a
SortedSet and returns a new TreeSet containing the same elements sorted according to the same
criterion. Note that it is the compile-time type of the argument, not its runtime type, that
determines which of these two constructors is invoked (and whether the sorting criterion is
preserved).

SortedSet implementations also provide by convention a constructor that takes a Comparator and
returns an empty set sorted according to the specified Comparator. If null is passed to this
constructor, it returns a set that sorts its elements according to their natural order.

Range-View Operations

The range-view operations are somewhat analogous to those provided by the List interface, but
there is one big difference. Range views of a sorted set remain valid even if the backing sorted
set is modified directly. This is feasible because the endpoints of a range view of a sorted set are
absolute points in the element space rather than specific elements in the backing collection, as is

395
the case for lists. A range view of a sorted set is really just a window onto whatever portion of
the set lies in the designated part of the element space. Changes to the range view write back to
the backing sorted set, and vice versa. Thus, it's okay to use range views on sorted sets for long
periods of time, unlike range views on lists.

Sorted sets provide three range-view operations. The first, subSet, takes two endpoints, like
subList. Rather than indices, the endpoints are objects and must be comparable to the elements in
the sorted set, using the set's Comparator or the natural ordering of its elements, whichever the
set uses to order itself. Like subList, the range is half open, including its low endpoint but
excluding the high one.

Thus, the following one of code tells you how many words between "doorbell" and "pickle,"
including "doorbell" but excluding "pickle," are contained in a SortedSet of strings called
dictionary:

int count = dictionary.subSet("doorbell", "pickle").size();

Similarly, the following one-liner removes all the elements beginning with the letter "f":

dictionary.subSet("f", "g").clear();

A similar trick can be used to print a table telling you how many words begin with each letter:

for (char ch = 'a'; ch <= 'z'; ) {


String from = String.valueOf(ch++);
String to = String.valueOf(ch);
System.out.println(from + ": " +
dictionary.subSet(from, to).size());
}

Suppose that you want to view a closed interval, which contains both of its endpoints, instead of
an open interval. If the element type allows for the calculation of the successor of a given value
in the element space, merely request the subSet from lowEndpoint to successor(highEndpoint).
Although it isn't entirely obvious, the successor of a string s in String's natural ordering is s +
"\0" (that is, s with a null character appended).

Thus, the following one-liner tells you how many words between "doorbell" and "pickle,"
including "doorbell" and "pickle," are contained in the dictionary:

count = dictionary.subSet("doorbell", "pickle\0").size();

A similar technique can be used to view an open interval, which contains neither endpoint. The
open-interval view from lowEndpoint to highEndpoint is the half-open interval from
successor(lowEndpoint) to highEndpoint. To calculate the number of words between "doorbell"
and "pickle," excluding both:

396
count = dictionary.subSet("doorbell\0",
"pickle").size();

The SortedSet interface contains two more range-view operations, headSet and tailSet, both
of which take a single Object argument. The former returns a view of the initial portion of the
backing SortedSet, up to but not including the specified object. The latter returns a view of the
final portion of the backing SortedSet, beginning with the specified object and continuing to the
end of the backing SortedSet. Thus, the following code allows you to view the dictionary as
two disjoint "volumes" (a — m and n — z):

SortedSet<String> volume1 = dictionary.headSet("n");


SortedSet<String>> volume2 = dictionary.tailSet("n");

Endpoint Operations

The SortedSet interface contains operations to return the first and last elements in the sorted set,
called (not surprisingly) first and last. In addition to their obvious uses, last allows a
workaround for a deficiency in the SortedSet interface. One thing you'd like to do with a
SortedSet is to go into the interior of the set and iterate forward or backward. It's easy enough
to go forward from the interior: Just get a tailSet and iterate over it. Unfortunately, there's no
easy way to go backwards.

The following idiom obtains the first element that is less than a specified object o in the element-
space:

Object predecessor = ss.headSet(o).last();

This is a fine way to go one element backward from a point in the interior of a sorted set. It could
be applied repeatedly to iterate backward, but this is very inefficient, requiring a lookup for each
element returned.

Comparator Accessor

The SortedSet interface contains an accessor method called comparator that returns the
Comparator used to sort the set, or null if the set is sorted according to the natural order of its
elements. This method is provided so that sorted sets can be copied into new sorted sets with the
same ordering. It is used by the SortedSet constructor.

16.12 The SortedMap Interface

A SortedMap is a Map that maintains its entries in ascending order, sorted according to the keys'
natural order, or according to a Comparator provided at SortedMap creation time. The Map
interface provides operations for the normal Map operations and for:

 Range view: Performs arbitrary range operations on the sorted map.


 Endpoints: Returns the first or the last key in the sorted map.
 Comparator access: Returns the Comparator, if any, used to sort the map.

397
Map Operations

The operations that SortedMap inherits from Map behave identically on sorted maps and normal
maps with two exceptions:

 The Iterator returned by the iterator operation on any of the sorted map's
Collection views traverse the collections in order.
 The arrays returned by the Collection views' toArray operations contain the keys,
values, or entries in order.

Although it isn't guaranteed by the interface, the toString method of the Collection views in
all the Java platform's SortedMap implementations returns a string containing all the elements of
the view, in order.

Standard Constructors

By convention, all general-purpose Map implementations provide a standard conversion


constructor that takes a Map; SortedMap implementations are no exception. In TreeMap, this
constructor creates an instance that orders its entries according to their keys' natural order. It
would have been better to check dynamically if the specified Map instance were a SortedMap,
and if so, to sort the new map according to the same criterion (comparator or natural ordering).
Because TreeMap took the approach that it did, it also provides a constructor that takes a
SortedMap and returns a new TreeMap containing the same mappings as the given SortedMap,
sorted according to the same criterion. Note that it is the compile-time type of the argument, not
its runtime type, that determines whether the SortedMap constructor is invoked in preference to
the ordinary map constructor.

SortedMap implementations also provide by convention a constructor that takes a Comparator


and returns an empty map sorted according to the specified Comparator. If null is passed to this
constructor, it returns a set that sorts its mappings according to their keys' natural order.

16.13 Relationships Among Generics

You might expect that a Stack<Object> is a supertype of a Stack<String>, because Object is


a supertype of String. In fact, no such relationship exists for instantiations of generic types. The
lack of a super-subtype relationship among instantiations of a generic type when the type
arguments possess a super-subtype relationship can make programming polymorphic methods
challenging.

Suppose you would like to write a method that prints out a collection of objects, regardless of the
type of objects contained in the collection:

public void printAll(Collection<Object> c) {


for (Object o : c) {
System.out.println(o);
}

398
}

You might choose to create a list of strings and use this method to print all the strings:

List<String> list = new ArrayList<String>();


...
printall(list); //error

If you try this you will notice that the last statement produces a compilation error. Since
ArrayList<String> is not subtype of Collection<Object> it cannot be passed as argument to
the print method even though the two types are instantiations of the same generic type with type
arguments related by inheritance. On the other hand, instantiations of generic types related by
inheritance for the same type argument are compatible:

public void printAll(Collection<Object> c) {


for (Object o : c) {
System.out.println(o);
}
}
List<Object> list = new ArrayList<Object>();
...
printall(list); //this works

List<Object> is compatible with Collection<Object> because the two types are instantiations
of a generic supertype and its subtype and the instantiations are for the same type argument,
namely Object.

16.14 Wildcard Types

To get around the puzzle posed by the first version of the printAll method you can specify that
the argument to printAll is a collection whose element type matches anything, written as
Collection<?>:

public void printAll(Collection<?> c) {


for (Object o : c) {
System.out.println(o);
}
}

The ? type is known as a wildcard type. You can always extract objects from this collection
because the returned type is always guaranteed to be Object. However, you cannot add objects
to this collection, because ? stands for some unknown type and it's not possible to know if the
type of the object you want to add is a subtype of the unknown type. The only exception is null,
which is a member of every type.

You can also constrain (or bound) the wildcard by a type. Bounded wildcards are useful when
you have partial knowledge about the type argument. For example, suppose you have a class
hierarchy consisting of a geometric shape (Shape) and its subtypes (Circle, Rectangle, and so

399
on). The drawing program that references these objects invokes a method drawAll to draw a
collection of these shapes:

public void drawAll(Collection<Shapes> shapes) {


for (Shape s: shapes) {
s.draw();
}
}

Since we have seen that it is not legal to pass in a subtype of Shape (for example, Circle) as the
type argument for the generic collection passed to drawAll, this method has limited usefulness:
for example, it cannot be called with Collection<Circle>. To enable passing a subtype of
Shape as the type argument, you could express the type parameter of the shape collection as a
wildcard. However, since we know that the type argument will be some type of shape, the
wildcard should be bounded by the superclass Shape as follows:

void drawAll(Collection<? extends Shapes> shapes) { ... }

This allows drawAll to accept collections of any subclass of Shape.

In summary, a wildcard with an upper bound is specified as <? extends Type> and stands for all
types that are subtypes of Type. It is also possible to constrain a wildcard with a lower bound. A
wildcard with a lower bound is specified as <? super Type> and stands for all types that are
supertypes of Type. Note that just as it is not possible to add an object to a collection of unknown
type, it is also not legal to add an object to a collection of an unknown type that has a bound.

16.15 Defining and Using Generic Methods

Not only types can be parameterized; methods can be parameterized too. Static and non-static
methods as well as constructors can have type parameters.

The syntax for declaring method type parameters is the same as the syntax for generics. The type
parameter section is delimited by angle brackets and appears before the method's return type. For
example the following Collections class method fills a List of type <? super T> with objects of
type T:

static <T> void fill(List<? super T> list, T obj)

Generic methods allow you to use type parameters to express dependencies among the types of
one or more arguments to a method or its return type (or both). The type parameters of generic
methods generally are independent of any class or interface-level type parameters.

One difference between generic types and generic methods is that generic methods are invoked
like regular methods. The type parameters are inferred from the invocation context, as in this
invocation of the fill method:

public static void main(String[] args) {

400
List<String> list = new ArrayList<String>(10);
for (int i = 0; i < 10; i++) {
list.add("");
}
String filler = args[0];
Collections.fill(list, filler);
...
}

401
Answers
Chapter 2

No. Answer Remark


The escape sequences are as follows: '\b'
(backspace), '\f' (formfeed), '\n' (newline), '\r'
(carriage return), '\t' (horizontal tab), '\\' (backslash),
1 a  1 
'\"' (double quote), '\'' (single quote). Yes, you must
memorize the escape sequences! Just remember
"big farms need red tractors".  
The Java Language Specification requires that the
main method must accept a single argument that is
an array of components of type String. In each of
the three class declarations, the single argument is
2 g  None of the above 
indeed an array of components of type String.
Please note that the square brackets within an array
declaration may appear as part of the type or part of
the declarator (i.e. array name).  
All of these are keywords of the Pascal
3 l  None of the above  programming language, but none are Java
keywords.  
The first letter of an identifier can be any Unicode
character that is a Java letter. The first letter can not
4 d  f  h  4  6  8 
be a number. The dollar sign $ and underscore _ are
considered Java letters.  
A char is a 16 bit unsigned value; so none of the
'\u0000' to '\uffff'  0 to
5 b  d  char values are negative and the minimum value is
65535 
zero. The maximum value is 2 - 1.  
16

6 a  e  1  5  An array creation expression must have either a


dimension expression or an initializer. If both are
present, then a compile-time error is generated.
Similarly, if neither is present, then a compile-time
error is generated. If only the dimension expression
is present, then an array with the specified
dimension is created with all elements set to the
default values. If only the initializer is present, then
an array will be created that has the required
dimensions to accommodate the values specified in
the initializer. Java avoids the possibility of an
incompatible dimension expression and initializer
by not allowing both to appear in the same array
creation expression. A compile-time error is
generated by the array creation expression for a1,

402
No. Answer Remark
because it needs either a dimension expression or
an initializer. A compile-time error is generated at
5, because either the dimension expression or the
initializer must be removed.  
An array variable a1 is declared, and the
declaration contains the initializer {{1,2,3},{4,5,6},
{7,8,9,10}}. The initializer creates an array
containing three components, and each is a
7 a  Prints: 3,4,8  reference to a subarray of type int[]. Each subarray
contains components of type int, so the elements of
the array referenced by a1 are of type int. The array
access expression, a1[0][2] = a1[1st subarray][third
component] = 3. 

Chapter 3

No. Answer Remark


Variables declared inside of a block or method are
called local variables; they are not automatically
1 f  Compile-time error  initialized. The compiler will generate an error as a
result of the attempt to access the local variables
before a value has been assigned.  
Both operands of the conditional and operator and
2 j  Compile-time error 
the conditional or operator must be of type boolean.
All of the declarations are legal. The first three (
061, '\61', '\061' ) are declared in octal format. The
3 f  None of the above 
fourth (0x0031) is declared as a hexadecimal literal.
The fifth ('\u0031') is a Unicode escape sequence.  
The sign of an integral numeric type is changed by
4 d  Prints: true,true 
inverting all of the bits and by adding one.
If the left-hand operand of the shift operator is of
type byte, short, or char then the left operand is
promoted to a 32 bit int and all four bytes are
shifted. If the promoted type of the left-hand
operand is of type int, then the shift distance is
always within the range of 0 to 31, inclusive; and is
5 e  Prints: 10 
specified by the least significant 5 bits of the right-
hand operand. In this case, the shift distance is 33,
and the five least significant bits are 00001; so the
shift distance is one bit. Note: If the type of the left
hand operand is long, then the least significant six
bits of the right hand operand are used.  
6 c  Prints: 5  The two statements, int a=1 followed by a += ++a +

403
No. Answer Remark
a++, can be rewritten as the single statement,
a=(int)((1)+(++a + a++)). Further evaluation
produces a=(int)((1)+(2 + 2)). Generally speaking,
a compound assignment expression of the form E1
op= E2 can be rewritten as E1=(T)((E1)op(E2))
where T is the type of E1.  
Suppose the left operand were divided by the right
operand. The remainder operator returns the
7 b  Prints: 2,true  remainder of the division operation. For integral
types, the identity, (y == ((y/x)*x+(y%x))), is
always true.  
The expression used to assign variable b1 is
equivalent to the expression used to assign variable
8 b  Prints: FFT 
b2. The results demonstrate that the conditional
operator (?:) groups from right-to-left.  

Chapter 4

No. Answer Remark


The length member of the array type is an attribute. A
1 c  3  compile-time error is generated as a result of the attempt to
access length as though it were a method.  
The array variable a1 is declared with the initializer, {{1,2,3},
{4,5,6},{7,8,9}}. The array access expression, a1[0][1] =
a1[first subarray][second element] = 2. If the argument of the
2 b  Prints: 147258369  print statement had been a1[i][j] then the output would have
been 123456789. The tricky feature of this question is the
reversal of i and j to produce the deceptive array access
expression, a1[j][i]. The output is 147258369. 
Cases one and three have no break statement, so the next case
3 c  Prints: v w x x y z z 
is also executed and x and z are printed twice.  
On the first pass through the loop, the value of x is 6, so 5 is
subtracted from x. On the second pass, the value of x is 1, so 3
is added to x. On the third pass, the value of x is 4, so 1 is
subtracted from x. On the fourth pass, the value of x is 3, so
4 c  Prints: 61433 
the variable, success, is incremented from zero to one. On the
final pass, the value of x is 3 and the variable, success, is
incremented to the value, 2. The boolean expression of the do
loop is now false, so control passes out of the loop.

Chapter 5

404
No. Answer Remark
An attempt to run
GRC7 from the
command line results
in an error at run-time. 
An attempt to run The JLS requires the main method to be declared
GRC8 from the static. In this example, each of the three main
1 d  e  f 
command line results methods are not declared static. The result is an error
in an error at run-time.  at run-time.  
An attempt to run
GRC9 from the
command line results
in an error at run-time. 
An attempt to run
GRC2 from the The JLS requires the main method to be declared
command line fails.  public. The main methods of GRC2 and GRC3 are
2 e  f 
An attempt to run not declared public and can not be invoked from the
GRC3 from the command line.
command line fails. 
The local variable y has not been initialized so the
Compile-time error at
3 e  attempt to access the variable results in a compile-
line 5. 
time error.  
The numeric sum of variables a, b, c, d and e is zero.
4 c  Prints: 0null  The zero is converted to a String and concatenated
with s.  
Local variables are not initialized automatically, and
must be initialized explicitly before attempting to
5 c  Compile-time error  access the value. The local variable i3 will not be
initialized if i1 is less than or equal to zero; so the
result is a compile-time error.  
The index for the first element of an array is zero so
the first argument printed by this program is the
6 b  Prints: BCD 
second argument on the command line following the
name of the class.

405
No. Answer Remark
A method invocation conversion can widen an
argument of type float to match a method parameter
of type double, so any argument that can be passed
to m(float i) can also be passed to m(double i)
without generating a compile-time type error. For
that reason, we can say that m(float i) is more
specific than m(double i). Since both methods are
applicable, the more specific of the two, m(float i), is
chosen over the less specific, m(double i). The
7 a  Prints: float,float  arguments of the method invocation expressions,
m(a1) and m(b1), are of types int and long
respectively. A method invocation conversion can
widen an argument of type int or long to match
either of the two method parameter types float or
double; so both methods, m(float i) and m(double i),
are applicable to the two method invocation
expressions. Since both methods are applicable, the
more specific of the two, m(float i) is chosen rather
than the less specific, m(double i).  
Although the reference variable r2 is assigned the
value of reference variable r1 in method m1, the
reference pet2 remains unchanged in the main
method. Object references are passed by value: the
8 c  Prints: Bird,Cat  invoked method gets a copy of the object reference.
The reference parameter r1 can be used to modify
the state of the instance referenced by pet1, but r2
can not be used to force pet2 to reference a different
instance.  
The assignment expression, a = c + a, requires an
explicit cast to type int. If one of the two operands of
a numeric expression is of type long and if the other
operand is of type int, short, char or byte; then it will
9 d  4  be promoted to type long, and the result of the
expression will be of type long. (Note: The rule does
not apply to the shift operator.) The type long result
can not be assigned to a variable of type int without
an explicit cast.  
Although the reference parameters i1 and i2 are
reassigned inside of m1, the change has no impact
10 b  Prints: 1,3  outside of m1. Array references are passed by value:
the invoked method gets a copy of the array
reference.  

406
No. Answer Remark
The compiler will implicitly do a narrowing
conversion for an assignment statement if the right
hand operand is a compile time constant of type byte,
11 f  g  h  6  7  8 
short, char, or int and the value falls within the range
of the variable on the left and if the variable is of
type byte, short, or char.  
There is a compile-time error at 2. The char type
variable c2 is not a compile-time constant, so it can
not be assigned to type byte without an explicit cast.
The method parameter c2 is declared final, so the
value of c2 can not be changed within method m2.
The value of method parameter c2 is set at run time
to the value of the argument that is provided when
m2 is invoked at line 3. For that reason, the method
parameter c2 is not a compile-time constant. In
method m2, the statement, "return c2;", is a return
statement with an expression, c2. A compile-time
error occurs if the type of the expression is not
assignable to the declared result type of the method.
The declared result type of method m2 is byte. The
return statement attempts to return the value of the
char type variable c2. If a char value is a compile-
Compile-time error at
12 d  time constant, and if the value falls within the range

of type byte, then the char value is assignable to type
byte. In method m2, variable c2 is not a compile-
time constant, because the value of c2 is not known
at compile time. Instead, the value of c2 is assigned
at run time to the value of the argument. Since the
char type variable c2 is not a compile-time constant,
the value of variable c2 is not assignable to the
return type of method m2 without an explicit cast.
While the declaration of method m2 produces a
compile-time error, the declaration of method m1
does not. The local variable c1 is declared final and
the value is set at compile time; so c1 is a compile-
time constant. The value \u0001 falls within the
range of type byte; so the value of the compile-time
constant c1 is assignable to the return type of method
m1 without an explicit cast.  

Chapter 6

407
No. Answer Remark
The type of the reference color2 is Red. Since Red is not a subclass or
a superclass of Blue, the expression color2 instanceof Blue is rejected
at compile-time. Please note: The expression, x instanceof T, produces
a compile-time error whenever the cast expression (T)x produces a
compile-time error. If the program had been able to compile and run,
the expression color1 instanceof Color would evaluate to true at run-
time. The reference color1 refers to an instance of type Red. Since
Compile-time Red is a subclass of Color, the expression color1 instanceof Color
1 j  would evaluate to true at run-time. The expression, color1 instanceof
error 
Blue would evaluate to false at run-time. The reference, color1, is of
type Color. Since Color is a superclass of Blue, the expression, color1
instanceof Blue, is accepted at compile-time. The type of the object
instance referenced by color1 is Red. Since Red is not Blue or a
subclass of Blue, the expression, color1 instanceof Blue, would be
false at run-time.  

A field is a class member. A static field is sometimes called a class


variable. A non-static field is sometimes called an instance variable. A

final  private  variable declaration that is immediately contained by a block such as a

2 protected  method body is called a local variable. The access modifiers, private,

public  protected and public, can be applied to a field. A final field can not

have its value assigned more than once. The abstract modifier may be
applied to methods but not to fields
If no constructor is declared explicitly, then the compiler will
The compiler implicitly create a default constructor that accepts no parameters, has
attempts to no throws clause, and invokes its superclass constructor. Since class A
create a default has an explicitly declared constructor, the compiler will not create an

3 constructor for implicit default constructor. Class B does not have an explicit

class B.  constructor declaration, so the compiler attempts to create a default
Compile-time constructor. Since class A does not have a no-parameter constructor,
error at 2.  the attempt by class B to invoke the no parameter constructor of A
would fail. As a result, a compiler error is generated at marker 2.  
An anonymous class can not be extended; therefore, an anonymous
class can not be declared abstract. A local class can be abstract. An
A local class
abstract class can not be instantiated. If a class declaration contains an
4 b  can be declared
abstract method, then the class must also be declared abstract. A class
abstract. 
can be declared abstract even if it does not contain an abstract method.
An abstract class can never be declared final.  
5 c  3  4  5  If a class C is declared as a member of an enclosing class then C may
d  be declared using no access modifier or any of the three access
e  modifiers, private, protected or public. However, if class C is not a
local class, anonymous class or a member of an enclosing class or
interface; then C may be declared with the public modifier or with
package access (i.e. no modifier). The other two access modifiers,

408
No. Answer Remark
private and protected, are not applicable to any class that is not a
member class. The class declaration, Class Basics4 {}, generates a
compile-time error, because all of the letters of the reserved word
class must be lower case.  
The declaration A11[] a1 = new A11[1] declares a variable a1 that
references an array that contains one component of type A11. The
declaration A11[][] a2 = new A11[2][] declares a variable a2 that
references an array that contains two components of type A11[]. In
other words, the array referenced by a2 contains two reference
variables, and each is able to reference a subarray. The initial value of
the subarray references is null. The size of the subarrays has not been
specified. The declaration A11[][][] a3 = new A11[3][][] declares a
variable a3 that references an array that contains three components of
type A11[][]. In other words, the array referenced by a3 contains three
reference variables, and each is able to reference a subarray. The
initial value of each subarray reference is null. The dimensions of the
6 b  Prints: A11  subarrays have not been specified. At line 5, a reference to the array
referenced by a1 is assigned to each of the two components of the
array referenced by a2, a2[0] = a2[1] = a1. At line 6, a reference to the
array referenced by a2 is assigned to each of the three components of
the array referenced by a3, a3[0] = a3[1] = a3[2] = a2. In other words,
after line 6, each component of the array referenced by a3 is a
reference to the array referenced by a2, and each element of the array
referenced by a2 is a reference to the array referenced by a1, and the
array referenced by a1 contains a reference to an instance of class
A11. Every element of the multi-dimensional array referenced by a3
contains a reference to a single instance of class A11. The print
method invokes the toString method on the instance, and produces the
output, A11. 

Chapter 7

No. Answer Remark


Line 4 does not generate a compile-time error. The
1 e  None of the above  reference named base actually refers to an instance of
type Sub, so the reference may be cast to type Sub.  
Both class A and B are declared in the same package, so
2 d  Compile-time error at 3.  class B has access to the public, protected, and package
access methods of class A.

Chapter 8

409
No. Answer Remark
The compiler creates a constructor for class C implicitly.
The implicitly created constructor accepts no parameters
and has no throws clause. The constructors for class B
and class C both invoke the constructor for A. The
constructor for class A declares Exception in the throws
1 c  Compile-time error at 3.  clause. Since the constructors for B and C invoke the
constructor for A implicitly, both B and C must declare
Exception in their throws clause. A compile-time error is
generated at marker 3, because the default constructor
does not declare Exception in the throws clause.

2 d  Prints: true,true  Both Error and Exception are subclasses of Throwable.  


The nested catch clause is able to catch a
Level2Exception or any subclass of it. The switch
statement throws a Level1Exception that can not be
3 b  Prints: 0,0,1,1,0,1  caught by the nested catch clause; so the nested finally
block is executed as control passes to the first of the two
outer catch clauses. The outer finally block is executed
as control passes out of the try statement.  
With assertions enabled it
If, under normal operating circumstances, the default
prints 210210 followed by
label of a switch statement should not be reached, then
an AssertionError
4 b  e  an assert statement can be placed after the default label
message.  With assertions
to verify that an unexpected condition has not not
disabled it prints 210210-
occurred.  

Chapter 10

No. Answer Remark


The compiler interprets \u000a as a line terminator. The
escape sequence \n should be used instead. Similarly, \u000d
1 c  d  3  4
is interpreted as a line terminator. The escape sequence \r
should be used instead.  
None of the String literals are declared using double quotes, but all of the
2 e 
above  declarations here use single quotes.  

Chapter 12

No. Answer Remark


1 d  Prints: -128,127  A byte is an 8 bit signed value; so the minimum byte

410
No. Answer Remark
value is -(2 ) and the maximum value is (2 - 1).  
7 7

A short is a 16 bit signed value; so the minimum short


2 b  Prints: -32768,32767 
value is -(2 ) and the maximum value is (2 - 1).  
15 15

A byte is an 8 bit signed value. The left most bit is the


sign bit. The sign bit is set to zero for positive
numbers and is set to one for negative numbers. The
most positive byte value is represented as a sign bit
that is set to zero and all of the other bits set to one.
The Integer.toBinaryString method does not print
leading zeros; so only seven bits are printed. An eight
bit binary value is represented as three octal digits.
The first of the three digits represents the left most
two bits of the binary value. In this case, the left most
3 a  Prints: 1111111,177,127,7f 
two bits are zero and one. The second octal digit
represents the next three bits of the binary value. The
last of the octal digits represents the right most three
bits of binary value. Note that the
Integer.toOctalString method does not print a leading
zero as is required for an octal literal value. An eight
bit binary value is represented as two hexadecimal
digits. The left hex digit represents the left most four
bits of the binary value. The right hex digit represents
the right most four bits of the binary value.  
A byte is an 8 bit signed value. A char is a 16 bit
unsigned value. A short is a 16 bit signed value. The
left most bit of a signed value is the sign bit. The sign
bit is zero for positive numbers and one for negative
4 c  Prints: 7f,ffff,7fff  numbers. The maximum byte value in hexadecimal
format is 7f and in decimal format is 127. The
minimum byte value in hexadecimal format is 80 and
in decimal format is -128. The byte value of decimal
-1 is ff in hexadecimal.  
An int is a 32 bit signed value. The left most bit is the
5 f  Prints: 80000000,7fffffff  sign bit. The sign bit is zero for positive numbers and
one for negative numbers.  
The null literal is converted to an int array type with
the value null. All array types implement the
Cloneable interface, so any array reference can be
6 g  None of the above  assigned to a reference of type Cloneable. The int
array object referenced by the Cloneable reference, c,
can be assigned to a reference of the int array type,
int[].  
7 f  Prints: true,false,true  The positive infinity of type float is promoted to the
positive infinity of type double. NaN is not equal to

411
No. Answer Remark
anything including itself.  

412

Potrebbero piacerti anche