
- •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 9 ■ Java File i/O (NiO.2)
even if two Path objects point to the same file/directory, it is not guaranteed that you will get true from the equals() method. You need to make sure that both are absolute and normalized paths for an equality comparison to succeed for paths.
Using the Files Class
The previous section discussed how to create a Path instance and extract useful information from it. Now you will use Path objects to manipulate files/directories. Java 7 offers a new Files class (in the java.nio.file package) that you can use to perform various file-related operations on files or directories. Note that Files is a utility class, meaning that it is a final class with a private constructor and consists only of static methods. So you can make use of the Files class by calling the static methods it provides, such as copy() to copy files. This class provides a wide range of functionality. With this class you can create directories, files, or symbolic links; create streams such as directory streams, byte channels, or input/output streams; examine the attributes of the files; walk the file tree; or perform file operations such as read, write, copy, or delete. Table 9-2 provides a sample of the important methods in the Files class.
Table 9-2. Some Methods Related to File Attributes in the Files Class
Method |
Description |
Path createDirectory(Path dirPath, FileAttribute<?>. . . dirAttrs)
Path createDirectories(Path dir, FileAttribute<?>. . . attrs)
Creates a file given by the dirPath, and sets the attributes given by dirAttributes. May throw exceptions such as FileAlreadyExistsException or UnsupportedOperationException (e.g., when the file attributes cannot be set as given by dirAttrs). The difference between createDirectory and
createDirectories is that createDirectories creates intermediate directories given by dirPath if they are not already present.
Path createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>. . . attrs)
Path createTempDirectory(Path dir,
String prefix, FileAttribute<?>. . . attrs)
Path copy(Path source, Path target, CopyOption. . . options)
Path move(Path source, Path target, CopyOption. . . options)
boolean isSameFile(Path path, Path path2)
Creates a temporary file with given prefix, suffix, and attributes in the directory given by dir.
Creates a temporary directory with the given prefix, directory attributes in the path specified by dir.
Copy the file from source to target. CopyOption could be REPLACE_EXISTING, COPY_ATTRIBUTES, or NOFOLLOW_LINKS. Can throw exceptions such as
FileAlreadyExistsException.
Similar to the copy operation except that the source file is removed; if the source and target are in the same directory, it is a file rename operation.
Checks if the two Path objects are located the same file or not.
boolean exists(Path path, |
Checks if a file/directory exists in the given path; can |
LinkOption. . . options) |
specify LinkOption.NOFOLLOW_LINKS to not to follow |
|
symbolic links. |
|
|
|
(continued) |
258
|
chapter 9 ■ Java File I/O (NIO.2) |
Table 9-2. (continued) |
|
|
|
Method |
Description |
Boolean isRegularFile(Path path, |
Returns true if the file represented by path is a |
LinkOption. . .) |
regular file. |
Boolean isSymbolicLink(Path path) |
Returns true if the file presented by path is a |
|
symbolic link. |
Boolean isHidden(Path path) |
Return true if the file represented by path is a |
|
hidden file. |
long size(Path path)
UserPrincipal getOwner(Path path, LinkOption. . .), Path setOwner(Path path, UserPrincipal owner)
FileTime getLastModifiedTime(Path path, LinkOption. . .), Path setLastModifiedTime(Path path, FileTime time)
Returns the size of the file in bytes represented by path.
Gets/sets the owner of the file.
Gets/sets the last modified time for the specified time.
Object |
getAttribute(Path |
path, String attribute, |
Gets/sets the specified attribute of the specified file. |
LinkOption. . .), Path setAttribute(Path path, |
|
||
String |
attribute, Object |
value, LinkOption. . .) |
|
|
|
|
|
Checking File Properties and Metadata
In the last section on the Path interface, you tried to figure out whether two paths are pointing to the same file or not (see Listing 9-3). There is another way to find out the same thing. You can use the isSameFile() method from the Files class. Listing 9-4 shows how to do it.
Listing 9-4. PathCompare2.java
import java.io.IOException; import java.nio.file.*;
// illustrates how to use File class to compare two paths class PathCompare2 {
public static void main(String[] args) throws IOException { Path path1 = Paths.get("Test");
Path path2 = Paths.get("D:\\OCPJP7\\programs\\NIO2\\Test");
System.out.println("Files.isSameFile(path1, path2) is: " + Files.isSameFile(path1, path2));
}
}
The program prints the following:
Files.isSameFile(path1, path2) is: true
In this case, you create the Test directory in the path D:\OCPJP7\programs\NIO2\ and it worked fine. However, if the Test file/directory does not exist in the given path, you’ll get a NoSuchFileException. But how
can you figure out if a file/directory exists in the given path? The Files class offers the exists() method to do that.
259
chapter 9 ■ Java File I/O (NIO.2)
In fact, you can distinguish between a file and a directory using another method called isDirectory() from the Files class. Listing 9-5 uses these methods.
Listing 9-5. PathExists.java
import java.nio.file.*;
class PathExists {
public static void main(String[] args) { Path path = Paths.get(args[0]);
if(Files.exists(path, LinkOption.NOFOLLOW_LINKS)) {
System.out.println("The file/directory " + path.getFileName() + " exists"); // check whether it is a file or a directory
if(Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) { System.out.println(path.getFileName() + " is a directory");
}
else {
System.out.println(path.getFileName() + " is a file");
}
}
else {
System.out.println("The file/directory " + path.getFileName() + " does not exist");
}
}
}
In this program, you are accepting a file/directory name from the command line and creating a Path object. Then, you are using the exists() method from the Files class to find out whether the file/directory exists or not. The second parameter of the exists() method is link-option, which is used to specify whether you want to follow symbolic links or not; in this case, you are not following symbolic links. If the file/directory associated with the input path exists, then you are checking whether the input path is indicating a file or a directory using the isDirectory() method of the Files class.
We ran this program with two different command line arguments and we got the following output:
D:\OCPJP7\programs\NIO2\src>java PathExists PathExists.java The file/directory PathExists.java exists
PathExists.java is a file
D:\OCPJP7\programs\NIO2\src>java PathExists D:\OCPJP7\ The file/directory OCPJP7 exists
OCPJP7 is a directory
D:\OCPJP7\programs\NIO2\src>java PathExists D:\ The file/directory null exists
null is a directory
In these outputs, you may have noticed the behavior when the root name (drive name in Windows in this case) is given as an argument. A root name is a directory, but path.getFileName() returns null if the path is a root name, hence the output.
260
chapter 9 ■ Java File I/O (NIO.2)
Existing files might not allow you to read, write, or execute based on your credentials. You can check the ability of a program to read, write, or execute programmatically. The Files class provides the methods isReadable(), isWriteable(), and isExecutable() to do that. Listing 9-6 uses these methods in a small example.
Listing 9-6. FilePermissions.java
import java.nio.file.*;
class FilePermissions {
public static void main(String[] args) { Path path = Paths.get(args[0]);
System.out.printf( "Readable: %b, Writable: %b, Executable: %b ", Files.isReadable(path), Files.isWritable(path), Files.isExecutable(path));
}
}
Let’s execute this program with two different inputs; here is the output:
D:\OCPJP7\programs\NIO2\src>java FilePermissions readonly.txt Readable: true, Writable: false, Executable: true D:\OCPJP7\programs\NIO2\src>java FilePermissions FilePermissions.java Readable: true, Writable: true, Executable: true
For the readonly.txt file, the permissions are readable, and executable, but not writable. The file FilePermissions.java itself has all the three permissions: readable, writable, and executable.
There are many other methods that can be used to fetch file properties. Let’s use the getAttribute() method to get some attributes of a file. The method takes variable number of parameters: first, a Path object; second, an attribute name; and subsequently, the link options (see Listing 9-7).
Listing 9-7. FileAttributes.java
import java.io.IOException; import java.nio.file.*;
class FileAttributes {
public static void main(String[] args) { Path path = Paths.get(args[0]); try {
Object object = Files.getAttribute(path, "creationTime", LinkOption.NOFOLLOW_LINKS);
System.out.println("Creation time: " + object);
object = Files.getAttribute(path, "lastModifiedTime", LinkOption.NOFOLLOW_LINKS);
System.out.println("Last modified time: " + object);
object = Files.getAttribute(path, "size", LinkOption.NOFOLLOW_LINKS); System.out.println("Size: " + object);
object = Files.getAttribute(path, "dos:hidden", LinkOption.NOFOLLOW_LINKS); System.out.println("isHidden: " + object);
261
chapter 9 ■ Java File I/O (NIO.2)
object = Files.getAttribute(path, "isDirectory", LinkOption.NOFOLLOW_LINKS); System.out.println("isDirectory: " + object);
} catch (IOException e) { e.printStackTrace();
}
}
}
Let’s first execute this program by giving the name of this program itself and then look at what happens:
D:\> java FileAttributes FileAttributes.java Creation time: 2012-10-06T10:20:10.34375Z
Last modified time: 2012-10-06T10:21:54.859375Z Size: 914
isHidden: false isDirectory: false
The tricky part of the example is the second parameter of the getAttribute() method. You need to provide a correct attribute name to extract the associated value. The expected string should be specified in view:attribute format, where view is the type of FileAttributeView and attribute is the name of the attribute supported by view. If no view is specified, the view is assumed as basic. In this case, you specified all attributes belonging to a basic view except one attribute from dos view. If you do not specify the correct view name,
you will get an UnsupportedOperationException, and if you mess up with the attribute name, you will get an
IllegalArgumentException.
For example, if you type sized instead of size, you’ll get this exception:
Exception in thread “main” java.lang.IllegalArgumentException: ‘sized’ not recognized [ . . . stack trace elided . . . ]
Well, you now know how to read metadata associated with files using the getAttribute() method. However, if you want to read many attributes in one shot, then calling the getAttribute() method for each attribute might not be a good idea (from a performance standpoint). In this case, Java 7 offers a solution: an API— readAttributes()—to read the attributes in one shot. The API comes in two flavors:
Map<String,Object> readAttributes(Path path, String attributes, LinkOption. . . options)
<A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption. . . options)
The first method returns a Map of attribute value pairs and takes variable length parameters. The attributes parameter is the key parameter where you need to specify what you want to retrieve. This parameter is similar to what you used in the getAttribute() method; however, here you can specify a list of attributes you want, and you can also use '*' to specify all attributes. For instance, using "*" means all attributes of the default FileAttributeView, such as BasicFileAttributes (specified as basic-file-attributes). Another example is: dos:*, which refers to all attributes of dos file attributes.
The second method uses generics syntax (Chapter 6). The second parameter here takes a class from the BasicFileAttributes hierarchy. We’ll talk about the hierarchy shortly. The method returns an instance from the
BasicFileAttributes hierarchy.
The file attributes hierarchy is shown in Figure 9-1. The BasicFileAttributes is the base interface from which DosFileAttributes and PosixFileAttributes are derived. Note that these attribute interfaces are provided in the java.nio.file.attribute package.
262

chapter 9 ■ Java File I/O (NIO.2)
BasicFileAttributes
|
|
|
|
|
|
|
|
|
|
|
|
DosFileAttributes |
|
|
PosixFileAttributes |
||
|
|
|
|
|
|
Figure 9-1. The hierarchy of BasicFileAttributes
As you can observe, the BasicFileAttributes interface defines the basic attributes supported by all common platforms. However, specific platforms define their own file attributes, which are captured by DosFileAttributes and PosixFileAttributes. You can specify any one of these interfaces to retrieve associated file attributes. Listing 9-8 contains a program to retrieve all attributes of a file using BasicFileAttributes.
Listing 9-8. FileAttributes2.java
import java.io.IOException; import java.nio.file.*;
import java.nio.file.attribute.*;
class FileAttributes2 {
public static void main(String[] args) { Path path = Paths.get(args[0]); try {
BasicFileAttributes fileAttributes = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("File size: " + fileAttributes.size()); System.out.println("isDirectory: " + fileAttributes.isDirectory()); System.out.println("isRegularFile: " + fileAttributes.isRegularFile()); System.out.println("isSymbolicLink: " + fileAttributes.isSymbolicLink()); System.out.println("File last accessed time: " +
fileAttributes.lastAccessTime());
System.out.println("File last modified time: " + fileAttributes.lastModifiedTime());
System.out.println("File creation time: " + fileAttributes.creationTime()); } catch (IOException e) {
e.printStackTrace();
}
}
}
The following is a sample output of the program:
D:\>java FileAttributes2 FileAttributes2.java File size: 904
isDirectory: false isRegularFile: true isSymbolicLink: false
File last accessed time: 2012-10-06T10:28:29.0625Z File last modified time: 2012-10-06T10:28:22.4375Z File creation time: 2012-10-06T10:26:39.1875Z
263