
- •Contents at a Glance
- •Contents
- •About the Authors
- •About the Technical Reviewer
- •Acknowledgments
- •Introduction
- •Oracle Java Certifications: Overview
- •FAQ 1. What are the different levels of Oracle Java certification exams?
- •FAQ 4. Is OCPJP 7 prerequisite for other Oracle certification exams?
- •FAQ 5. Should I take the OCPJP 7 or OCPJP 6 exam?
- •The OCPJP 7 Exam
- •FAQ 7. How many questions are there in the OCPJP 7 exam?
- •FAQ 8. What is the duration of the OCPJP 7 exam?
- •FAQ 9. What is the cost of the OCPJP 7 exam?
- •FAQ 10. What are the passing scores for the OCPJP 7 exam?
- •FAQ 11. What kinds of questions are asked in the OCPJP 7 exam?
- •FAQ 12. What does the OCPJP 7 exam test for?
- •FAQ 13. I’ve been a Java programmer for last five years. Do I have to prepare for the OCPJP 7 exam?
- •FAQ 14. How do I prepare for the OCPJP 7 exam?
- •FAQ 15. How do I know when I’m ready to take the OCPJP 7 exam?
- •Taking the OCPJP 7 Exam
- •FAQ 16. What are my options to register for the exam?
- •FAQ 17. How do I register for the exam, schedule a day and time for taking the exam, and appear for the exam?
- •The OCPJP 7 Exam: Pretest
- •Answers with Explanations
- •Post-Pretest Evaluation
- •Essentials of OOP
- •FunPaint Application: An Example
- •Foundations of OOP
- •Abstraction
- •Encapsulation
- •Inheritance
- •Polymorphism
- •Class Fundamentals
- •Object Creation
- •Constructors
- •Access Modifiers
- •Public Access Modifier
- •Private Access Modifier
- •Protected and Default Access Modifier
- •Overloading
- •Method Overloading
- •Constructor Overloading
- •Overload resolution
- •Points to Remember
- •Inheritance
- •Runtime Polymorphism
- •An Example
- •Overriding Issues
- •Overriding: Deeper Dive
- •Invoking Superclass Methods
- •Type Conversions
- •Upcasts and Downcasts
- •Casting Between Inconvertible Types
- •Using “instanceof” for Safe Downcasts
- •Java Packages
- •Working with Packages
- •Static Import
- •Summary
- •Abstract Classes
- •Points to Remember
- •Using the “final” Keyword
- •Final Classes
- •Final Methods and Variables
- •Points to Remember
- •Using the “static” Keyword
- •Static Block
- •Points to Remember
- •Flavors of Nested Classes
- •Static Nested Classes (or Interfaces)
- •Points to Remember
- •Inner Classes
- •Points to Remember
- •Local Inner Classes
- •Points to Remember
- •Anonymous Inner Classes
- •Points to Remember
- •Enum Data Types
- •Points to Remember
- •Summary
- •Interfaces
- •Declaring and Using Interfaces
- •Points to Remember
- •Abstract Classes vs. Interfaces
- •Choosing Between an Abstract Class and an Interface
- •Object Composition
- •Composition vs. Inheritance
- •Points to Remember
- •Design Patterns
- •The Singleton Design Pattern
- •Ensuring That Your Singleton Is Indeed a Singleton
- •The Factory Design Pattern
- •Differences Between Factory and Abstract Factory Design Patterns
- •The Data Access Object (DAO) Design Pattern
- •Points to Remember
- •Summary
- •Generics
- •Using Object Type and Type Safety
- •Using the Object Class vs. Generics
- •Container Implementation Using the Object Class
- •Container Implementation Using Generics
- •Creating Generic Classes
- •Diamond Syntax
- •Interoperability of Raw Types and Generic Types
- •Generic Methods
- •Generics and Subtyping
- •Wildcard Parameters
- •Limitations of Wildcards
- •Bounded Wildcards
- •Wildcards in the Collections Class
- •Points to Remember
- •The Collections Framework
- •Why Reusable Classes?
- •Basic Components of the Collections Framework
- •Abstract Classes and Interfaces
- •Concrete Classes
- •List Classes
- •ArrayList Class
- •The ListIterator Interface
- •The LinkedList Class
- •The Set Interface
- •The HashSet Class
- •The TreeSet Class
- •The Map Interface
- •The HashMap Class
- •Overriding the hashCode() Method
- •The NavigableMap Interface
- •The Queue Interface
- •The Deque Interface
- •Comparable and Comparator Interfaces
- •Algorithms (Collections Class)
- •The Arrays Class
- •Methods in the Arrays Class
- •Array as a List
- •Points to Remember
- •Summary
- •Generics
- •Collections Framework
- •Processing Strings
- •String Searching
- •The IndexOf() Method
- •The regionMatches() Method
- •String Parsing
- •String Conversions
- •The Split() Method
- •Regular Expressions
- •Understanding regex Symbols
- •Regex Support in Java
- •Searching and Parsing with regex
- •Replacing Strings with regex
- •String Formatting
- •Format Specifiers
- •Points to Remember
- •Summary
- •Reading and Writing from Console
- •Understanding the Console Class
- •Formatted I/O with the Console Class
- •Special Character Handling in the Console Class
- •Using Streams to Read and Write Files
- •Character Streams and Byte Streams
- •Character Streams
- •Reading Text Files
- •Reading and Writing Text Files
- •“Tokenizing” Text
- •Byte Streams
- •Reading a Byte Stream
- •Data Streams
- •Writing to and Reading from Object Streams: Serialization
- •Serialization: Some More Details
- •Points to Remember
- •Summary
- •A Quick History of I/O APIs
- •Using the Path Interface
- •Getting Path Information
- •Comparing Two Paths
- •Using the Files Class
- •Checking File Properties and Metadata
- •Copying a File
- •Moving a File
- •Deleting a File
- •Walking a File Tree
- •Revisiting File Copy
- •Finding a File
- •Watching a Directory for Changes
- •Points to Remember
- •Summary
- •Introduction to JDBC
- •The Architecture of JDBC
- •Two-Tier and Three-Tier JDBC Architecture
- •Types of JDBC Drivers
- •Setting Up the Database
- •Connecting to a Database Using a JDBC Driver
- •The Connection Interface
- •Connecting to the Database
- •Statement
- •ResultSet
- •Querying the Database
- •Updating the Database
- •Getting the Database Metadata
- •Points to Remember
- •Querying and Updating the Database
- •Performing Transactions
- •Rolling Back Database Operations
- •The RowSet Interface
- •Points to Remember
- •Summary
- •Define the Layout of the JDBC API
- •Connect to a Database by Using a JDBC driver
- •Update and Query a Database
- •Customize the Transaction Behavior of JDBC and Commit Transactions
- •Use the JDBC 4.1 RowSetProvider, RowSetFactory, and RowSet Interfaces
- •Introduction to Exception Handling
- •Throwing Exceptions
- •Unhandled Exceptions
- •Try and Catch Statements
- •Programmatically Accessing the Stack Trace
- •Multiple Catch Blocks
- •Multi-Catch Blocks
- •General Catch Handlers
- •Finally Blocks
- •Points to Remember
- •Try-with-Resources
- •Closing Multiple Resources
- •Points to Remember
- •Exception Types
- •The Exception Class
- •The RuntimeException Class
- •The Error Class
- •The Throws Clause
- •Method Overriding and the Throws Clause
- •Points to Remember
- •Custom Exceptions
- •Assertions
- •Assert Statement
- •How Not to Use Asserts
- •Summary
- •Introduction
- •Locales
- •The Locale Class
- •Getting Locale Details
- •Resource Bundles
- •Using PropertyResourceBundle
- •Using ListResourceBundle
- •Loading a Resource Bundle
- •Naming Convention for Resource Bundles
- •Formatting for Local Culture
- •The NumberFormat Class
- •The Currency Class
- •The DateFormat Class
- •The SimpleDateFormat Class
- •Points to Remember
- •Summary
- •Introduction to Concurrent Programming
- •Important Threading-Related Methods
- •Creating Threads
- •Extending the Thread Class
- •Implementing the Runnable Interface
- •The Start( ) and Run( ) Methods
- •Thread Name, Priority, and Group
- •Using the Thread.sleep() Method
- •Using Thread’s Join Method
- •Asynchronous Execution
- •The States of a Thread
- •Two States in “Runnable” State
- •Concurrent Access Problems
- •Data Races
- •Thread Synchronization
- •Synchronized Blocks
- •Synchronized Methods
- •Synchronized Blocks vs. Synchronized Methods
- •Deadlocks
- •Other Threading Problems
- •Livelocks
- •Lock Starvation
- •The Wait/Notify Mechanism
- •Let’s Solve a Problem
- •More Thread States
- •timed_waiting and blocked States
- •waiting State
- •Using Thread.State enum
- •Understanding IllegalThreadStateException
- •Summary
- •Using java.util.concurrent Collections
- •Semaphore
- •CountDownLatch
- •Exchanger
- •CyclicBarrier
- •Phaser
- •Concurrent Collections
- •Apply Atomic Variables and Locks
- •Atomic Variables
- •Locks
- •Conditions
- •Multiple Conditions on a Lock
- •Use Executors and ThreadPools
- •Executor
- •Callable, Executors, ExecutorService, ThreadPool, and Future
- •ThreadFactory
- •The ThreadLocalRandom Class
- •TimeUnit Enumeration
- •Use the Parallel Fork/Join Framework
- •Useful Classes of the Fork/Join Framework
- •Using the Fork/Join Framework
- •Points to Remember
- •Summary
- •Using java.util.concurrent Collections
- •Applying Atomic Variables and Locks
- •Using Executors and ThreadPools
- •Using the Parallel Fork/Join Framework
- •Chapter 3: Java Class Design
- •Chapter 4: Advanced Class Design
- •Chapter 5: Object-Oriented Design Principles
- •Chapter 6: Generics and Collections
- •Chapter 7: String Processing
- •Chapter 8: Java I/O Fundamentals
- •Chapter 9: Java File I/O (NIO.2)
- •Chapter 10: Building Database Applications with JDBC
- •Chapter 11: Exceptions and Assertions
- •Chapter 12: Localization
- •Chapter 13: Threads
- •Chapter 14: Concurrency
- •OCPJP7 Exam (1Z0-804 a.k.a. Java SE 7 Programmer II) Topics
- •OCPJP 7 Exam (1Z0-805, a.k.a. Upgrade to Java SE 7 Programmer) Topics
- •Answers and Explanations
- •Answer Sheet
- •Answers and Explanations
- •Index

Chapter 8 ■ Java I/O Fundamentals
Character Streams and Byte Streams
Consider the difference between Java source files and class files generated by the compiler. The Java source files have extension of .java and are meant to be read by humans as well as programming tools such as compilers. However, the Java class files have extension of .class and are not meant to be read by humans; they are meant to be processed by low-level tools such as a JVM (executable java.exe in Windows) and Java disassember (executable javap.exe
in Windows). We refer to human-readable files containing text (or characters) as text files; we refer to the machine readable or low-level data storage files as binary files. Naturally, how you interpret what is inside text files vs. binary files is different. For example, in text files, you can interpret the data read from the file and differentiate between a tab character, whitespace character, newline character, etc. However, you don’t deal with data from binary files like that; they are low-level values. To give another example, consider a .txt file you create with a text editor such as Notepad in Windows; it contains human-readable text. Now, consider storing your photo in a .bmp or .jpeg file; these files are certainly not human readable. They are meant for processing by photo editing or image manipulation software, and the files contain data in some pre-determined low-level format.
The java.io package has classes that support both character streams and byte streams. You can use character streams for text-based I/O. Byte streams are used for data-based I/O. Character streams for reading and writing are called readers and writers, respectively (represented by the abstract classes of Reader and Writer). Byte streams for reading and writing are called input streams and output streams, respectively (represented by the abstract classes of InputStream and OutputStream). Table 8-2 summarizes the differences between character streams and byte streams for your quick reference.
Table 8-2. Differences Between Character Streams and Byte Streams
Character streams |
Byte streams |
Meant for reading or writing to characteror text-based I/O such as text files, text documents, XML, and HTML files.
Data dealt with is 16-bit Unicode characters.
Input and output character streams are called readers and writers, respectively.
The abstract classes of Reader and Writer and their derived classes in the java.io package provide support for character streams.
Meant for reading or writing to binary data I/O such as executable files, image files, and files in low-level file formats such as .zip, .class, .obj, and .exe.
Data dealt with is bytes (i.e., units of 8-bit data).
Input and output byte streams are simply called input streams and output streams, respectively.
The abstract classes of InputStream and OutputStream and their derived classes in the java.io package provide support for byte streams.
If you try using a byte stream when a character stream is needed and vice versa, you’ll get a nasty surprise in your programs. For example, a bitmap (.bmp) image file must be processed using a byte stream; if you try using character stream, your program won’t work. So don’t mix up the streams!
Character Streams
In this section, you’ll explore I/O with character streams. You’ll learn how to read from and write to text files plus some optional features such as buffering to speed up the I/O. For reading and writing text files, you can use the classes derived from the Reader and Writer abstract classes, respectively. For character streams, Figure 8-2 shows important Reader classes, and Table 8-3 provides a short description of these classes. Figure 8-3 shows important Writer classes, and Table 8-4 provides a short description of these classes. Note that we’ll cover only a few important classes in this class hierarchy in this chapter.
230

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Chapter 8 ■ Java I/O Fundamentals |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Reader |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BufferedReader |
|
|
FilterReader |
|
|
|
PipedReader |
|
|
InputStreamReader |
|
|
StringReader |
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LineNumberReader |
|
PushbackReader |
|
|
|
|
|
|
FileReader |
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
Figure 8-2. Important classes deriving from the Reader class |
|
|
|
||||||||||||||||||||
Table 8-3. Important Classes Deriving from the Reader Class |
|
|
|
||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
Class name |
|
|
Short description |
|
|
|
|
|
|
|
|
|
|
||||||||||
StringReader |
|
|
A character stream that operates on strings. |
|
|
|
|||||||||||||||||
InputStreamReader |
|
|
This class is a bridge between character streams and byte streams. |
||||||||||||||||||||
FileReader |
|
|
Derived class of InputStreamReader that provides support for reading character files. |
||||||||||||||||||||
PipedReader |
|
|
The PipedReader and PipedWriter classes form a pair for “piped” reading/writing |
||||||||||||||||||||
|
|
|
|
|
|
|
of characters. |
|
|
|
|
|
|
|
|
|
|
||||||
FilterReader |
|
|
Abstract base class for streams that support a filtering operation applied on data as |
||||||||||||||||||||
|
|
|
|
|
|
|
characters are read from the stream. |
|
|
|
|||||||||||||
PushbackReader |
|
|
Derived class of FilterReader that allows read characters to be pushed back into |
||||||||||||||||||||
|
|
|
|
|
|
|
the stream. |
|
|
|
|
|
|
|
|
|
|
||||||
BufferedReader |
|
|
Adds buffering to the underlying character stream so that there is no need to access |
||||||||||||||||||||
|
|
|
|
|
|
|
the underlying file system for each read and write operation. |
||||||||||||||||
LineNumberReader |
|
|
Derived class of BufferedReader that keeps track of line numbers as the characters |
||||||||||||||||||||
|
|
|
|
|
|
|
are read from the underlying character stream. |
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Writer |
|
BufferedWriter |
PipedWriter |
OutputStreamWriter |
StringWriter |
PrintWriter |
|
FilterWriter |
FileWriter |
Figure 8-3. Important classes deriving from the Writer class
231
Chapter 8 ■ Java I/O Fundamentals
Table 8-4. Important Classes Deriving from the Writer Class
|
|
Class name |
Short description |
StringWriter |
A character stream that collects the output in a string buffer, which can be used for |
|
creating a string. |
OutputStreamWriter |
This class is a bridge between character streams and byte streams. |
FileWriter |
Derived class of InputStreamWriter that provides support for writing character files. |
PipedWriter |
The PipedReader and PipedWriter classes form a pair for “piped” reading/writing of |
|
characters in character stream. |
FilterWriter |
Abstract base class for streams that supports a filtering operation applied on data as |
|
characters when writing them to a character stream. |
PrintWriter |
Supports formatted printing of characters to the output character stream. |
BufferedWriter |
Adds buffering to the underlying character stream so that there is no need to access |
|
the underlying file system for each read and write operation. |
|
|
Reading Text Files
Reader classes read the contents in the stream and try interpreting them as characters, such as a tab, end-of-file, newline, etc. Listing 8-4 implements a simplified version of the type command in Windows. The type command displays the contents of the file(s) passed as command-line arguments.
Listing 8-4. Type.java
import java.io.FileNotFoundException; import java.io.FileReader;
import java.io.IOException;
//implements a simplified version of "type" command provided in Windows given
//a text file name(s) as argument, it prints the content of the text file(s) on console class Type {
public static void main(String []files) { if(files.length == 0) {
System.err.println("pass the name of the file(s) as argument"); System.exit(−1);
}
// process each file passed as argument for(String file : files) {
// try opening the file with FileReader
try (FileReader inputFile = new FileReader(file)) { int ch = 0;
//while there are characters to fetch, read, and print the
//characters when EOF is reached, read() will return −1,
//terminating the loop
while( (ch = inputFile.read()) != −1) {
//ch is of type int - convert it back to char
//before printing
System.out.print( (char)ch );
}
232
Chapter 8 ■ Java I/O Fundamentals
}catch (FileNotFoundException fnfe) {
//the passed file is not found ...
System.err.printf("Cannot open the given file %s ", file);
}
catch(IOException ioe) {
// some IO error occurred when reading the file ...
System.err.printf("Error when processing file %s... skipping it", file);
}
// try-with-resources will automatically release FileReader object
}
}
}
For a sample text file, here is the output for the type command in Windows and our Type program:
D:\> type SaturnMoons.txt
Saturn has numerous icy moons in its rings. Few large moons of Saturn are - Mimas, Enceladus, Tethys, Dione, Rhea, Titan, Iapetus, and Hyperion.
D:\> java Type SaturnMoons.txt
Saturn has numerous icy moons in its rings. Few large moons of Saturn are - Mimas, Enceladus, Tethys, Dione, Rhea, Titan, Iapetus, and Hyperion.
It works as expected. In this program, you are instantiating the FileReader class and pass the name of the file to be opened. If the file is not found, the FileReader constructor will throw a FileNotFoundException.
Once the file is open, you use the read() method to fetch characters in the underlying file. You are reading character by character. Alternatively, you can use methods such as readLine() to read line by line.
Note that the read() method returns an int instead of a char—it’s because when read() reaches End-Of-File (EOF), it returns −1, which is outside the range of char. So, the read() method returns an int to indicate that the end of file has been reached and that you should stop attempting to read any more characters from the underlying stream.
In this program, you only read a text file; you’ll now try to read from as well as write to a text file.
Reading and Writing Text Files
In the previous example (Listing 8-4) of reading a text file, you created the character stream as follows:
FileReader inputFile = new FileReader(file);
This uses unbuffered I/O, which is less efficient when compared to buffered I/O. In other words, the read characters are directly passed instead of using a temporary (internal) buffer, which would speed up the I/O. To programmatically use buffered I/O, you can pass the FileReader reference to a BufferedReader object, as in the following:
BufferedReader inputFile = new BufferedReader(new FileReader(file);
In the same way, you can also use BufferedWriter for buffered output. (In case of byte streams, you can use BufferedInputStream and BufferedOutputStream, which we’ll discuss later in this chapter).
You’ll now use buffered I/O to read from and write to a text file. Listing 8-5 contains a simplified version of the copy command in Windows.
233
Chapter 8 ■ Java I/O Fundamentals
Listing 8-5. Copy.java
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader;
import java.io.FileWriter; import java.io.IOException;
//implements a simplified version of "copy" command provided in Windows
//syntax: java Copy SrcFile DstFile
//copies ScrFile to DstFile; over-writes the DstFile if it already exits class Copy {
public static void main(String []files) {
if(files.length != 2) {
System.err.println("Incorrect syntax. Correct syntax: Copy SrcFile DstFile"); System.exit(−1);
}
String srcFile = files[0]; String dstFile = files[1];
//try opening the source and destination file
//with FileReader and FileWriter
try (BufferedReader inputFile = new BufferedReader(new FileReader(srcFile)); BufferedWriter outputFile = new BufferedWriter(new FileWriter(dstFile))) {
int ch = 0;
//while there are characters to fetch, read the characters from
//source stream and write them to the destination stream while( (ch = inputFile.read()) != −1) {
//ch is of type int - convert it back to char before
//writing it
outputFile.write( (char)ch );
}
//no need to call flush explicitly for outputFile - the close()
//method will first call flush before closing the outputFile stream
}catch (FileNotFoundException fnfe) {
//the passed file is not found ...
System.err.println("Cannot open the file " + fnfe.getMessage());
}
catch(IOException ioe) {
// some IO error occurred when reading the file ...
System.err.printf("Error when processing file; exiting ... ");
}
// try-with-resources will automatically release FileReader object
}
}
Let’s first check if this program works. Copy this Java source program itself (Copy.java) into another file (DuplicateCopy.java). You can use the fc (file compare) command provided in Windows to make sure that the contents of the original file and the copied file are same, to ensure that the program worked correctly.
234