
- •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 6 ■ Generics and Collections
Why doesn’t subtyping work for generic type parameters? Let’s look at what can go wrong if you assume that you can use subtyping for generic type parameters.
// illegal code – assume that the following intialization is allowed List<Number> intList = new ArrayList<Integer>();
intList.add(new Integer(10)); // okay intList.add(new Float(10.0f)); // oops!
The intList of List<Number> type is supposed to hold an ArrayList<Number> object. However, you are storing an ArrayList<Integer>. This looks reasonable since List extends ArrayList and Integer extends Number. However, you can end up inserting a Float value in the intList! Recall that the dynamic type of intList is the
ArrayList<Integer> type—so you are violating type safety here (and thus will get the compiler error of incompatible types). Since generics are designed to avoid type-safety mistakes like this, you cannot assign a derived generic type parameter to a base type parameter.
As you can see, subtyping for generic parameter types is not allowed because it is unsafe—but still it is an inconvenient limitation. Fortunately, Java supports wildcard parameter types in which you can use subtyping. We’ll explore that capability now.
Type parameters for generics have a limitation: generic type parameters should match exactly for assignments. To overcome this subtyping problem, you can use wildcard types.
Wildcard Parameters
You saw in the preceding section that subtyping doesn’t work for generic type parameters. So,
List<Number> intList = new ArrayList<Integer>();
gives the compiler error of
WildCardUse.java:6: incompatible types
found : java.util.ArrayList<java.lang.Integer> required: java.util.List<java.lang.Number>
List<Number> numList = new ArrayList<Integer>();
If you slightly change the statement to use wildcard parameter, it will compile
List<?> wildCardList = new ArrayList<Integer>();
What does a wildcard mean? Just like the wildcard you use for substituting for any card in a card game (ah, it’s so fun to play card games!), you can use a wildcard to indicate that it can match for any type. With List<?>, you mean that it is a List of any type—in other words, you can say it is a “list of unknowns!”
But wait a minute . . . when you want a type indicating “any type,” you use the Object class, don’t you? How about the same statement, but using the Object type parameter?
List<Object> numList = new ArrayList<Integer>();
163
Chapter 6 ■ Generics and Collections
No luck—you get the same error you got above using List<Number>!
WildCardUse.java:6: incompatible types
found : java.util.ArrayList<java.lang.Integer> required: java.util.List<java.lang.Object>
List<Object> numList = new ArrayList<Integer>();
In other words, you are still trying to use subtyping for generic parameters—and it still doesn’t work. As you can see, List<Object> is not same as List<?>. In fact, List<?> is a supertype of any List type, which means you can pass
List<Integer>, or List<String>, or even List<Object> where List<?> is expected. Let’s use the wildcard in an example and see whether it’ll work (see Listing 6-12).
Listing 6-12. WildCardUse.java
// This program demonstrates the usage of wild card parameters class WildCardUse {
static void printList(List<?> list){ for(Object l:list)
System.out.println("[" + l + "]");
}
public static void main(String []args) { List<Integer> list = new ArrayList<>(); list.add(10);
list.add(100);
printList(list);
List<String> strList = new ArrayList<>(); strList.add("10");
strList.add("100");
printList(strList);
}
}
This program prints the following:
[10]
[100]
[10]
[100]
Well, it works, and the list using wildcard can be passed list of integers as well as list of strings. This happens because of the parameter type of printList() method—List<?>. That’s great!
Limitations of Wildcards
Let’s consider the following snippet, which tries to add an element and print the list:
List<?> wildCardList = new ArrayList<Integer>(); wildCardList.add(new Integer(10)); System.out.println(wildCardList);
164

Chapter 6 ■ Generics and Collections
You get the following compiler error:
WildCardUse.java:7: cannot find symbol symbol : method add(java.lang.Integer)
location: interface java.util.List<capture#145 of ? extends java.lang.Number> wildCardList.add(new Integer(10));
Why? You are absolutely sure that the add() method exists in the List interface. Then why doesn’t the compiler find the method?
The problem requires some detailed explanation. When you use wildcard type <?>, you say to the compiler that you are ignoring the type information, so <?> stands for unknown type. Every time you try to pass arguments to a generic type, the java compiler tries to infer the type of the passed argument as well as the type of the generics and to justify the type safety. Now, you are trying to use the add() method to insert an element in the list. Since wildCardList doesn’t know which type of objects it holds, it is risky to add elements to it. You might end up
adding a string—“hello”, for example—instead of an integer value. To avoid this problem (remember, generics was introduced in the language to ensure type safety!), the compiler doesn’t allow you to call methods that modify the object. Since the add method modifies the object, you get an error! The error message also looks confusing, as in
<capture#145 of ? extends java.lang.Number>.
In general, when you use wildcard parameters, you cannot call methods that modify the object. If you try to modify, the compiler will give you confusing error messages. However, you can call methods that access the object.
Bounded Wildcards
Here is a quick recap on wildcards to understand why you need bounded wildcards. You get a compiler error when you try generic types differing in their parameter types, as in
// compiler error:
List<Number> numList = new ArrayList<Integer>();
You use wildcard types to avoid this compiler error:
// now works:
List<?> numList = new ArrayList<Integer>();
Assume you want to be able to store only the list of numbers in the numList. However, you might end up storing a list of any type with wildcards, as in
List<?> numList = new ArrayList<Integer>(); numList = new ArrayList<String>();
Yes, it compiles without any errors. How do you restrict numList to refer to only to Number and its derived classes like Integer, Double, etc.? You do it by using bounded wildcards, like so:
List<? extends Number> numList = new ArrayList<Integer>(); numList = new ArrayList<String>();
165
Chapter 6 ■ Generics and Collections
You get the following compiler error:
BoundedWildCardUse.java:7: incompatible types found : java.util.ArrayList<java.lang.String>
required: java.util.List<? extends java.lang.Number> numList = new ArrayList<String>();
How about this code?
List<? extends Number> numList = new ArrayList<Integer>(); numList = new ArrayList<Double>();
Yes, it compiles fine! What is going on here? In List<? extends Number>, the wildcard (?) is bounded with extends Number. This means that any type you substitute for wildcard (?) should satisfy the condition extends Number. For example, in ? extends Number, if you substitute ? with type Integer, you get
Integer extends Number—which is logically true. So the compilation will succeed for such substitution. But, in ? extends Number, if you substitute ? with type String, you get String extends Number, which is logically false
(remember that String is not a Number). So, you get a compiler error. In other words, you limit or bound the wildcard so that the substituted type must be of the extend Number class.
You can use bounded wildcards in method arguments, return types, etc. Here’s a simple method that uses bounded wildcards:
public static Double sum(List<? extends Number> numList) { Double result = 0.0;
for(Number num : numList) {
result += num.doubleValue();
}
return result;
}
Here is a step-by-step description of this method:
1.The method sum() is meant for taking a list of Numbers and returning the sum of the elements in that list.
2.Since the List is to be limited (bounded) by Number, you declare List as List<? Extends Number>.
3.Since you don’t know the exact type of the list elements (Integer, Double, etc.), you want to use double as the return type for sum. Since primitive types like int and double are implicitly boxed/unboxed when used with collections, you declare the return type as Double, which is more convenient than using the primitive type double.
4.Coming to the body of the method, since the sum of elements is going to be a Double value, you declare the result variable Double and initialize it with zero.
5.In the for-each loop, you use Number as the loop type. Since the wildcard is bounded by Number, you know that (no matter which List object is actually passed as argument) the element type is going to be a Number.
6.You get the double value from the Number type using the doubleValue method.
7.You return the sum of the elements once you are done.
166
Chapter 6 ■ Generics and Collections
Listing 6-13 contains the main() method to test the sum() method.
Listing 6-13. BoundedWildCardUse.java
// This program demonstrates the usage of bounded wild cards
import java.util.*;
class BoundedWildCardUse {
public static Double sum(List<? extends Number> numList) { Double result = 0.0;
for(Number num : numList) {
result += num.doubleValue();
}
return result;
}
public static void main(String []args) {
List<Integer> intList = new ArrayList<Integer>(); List<Double> doubleList = new ArrayList<Double>();
for(int i = 0; i < 5; i++) { intList.add(i); doubleList.add((double) (i * i));
}
System.out.println("The intList is: " + intList); System.out.println("The sum of elements in intList is: " + sum(intList));
System.out.println("The doubleList is: " + doubleList); System.out.println("The sum of elements in doubleList is: " + sum(doubleList));
}
}
It prints the following:
The intList is: [0, 1, 2, 3, 4]
The sum of elements in intList is: 10.0
The doubleList is: [0.0, 1.0, 4.0, 9.0, 16.0] The sum of elements in doubleList is: 30.0
Let’s go over the code step-by-step:
1.You create two ArrayLists, one of type Integer and another of type Double.
2.In a for loop, you insert five elements each into the lists. For intList, you insert the values 0 to 4. For doubleList, you insert the square of the values 0 to 4 (0 to 16). Since the doubleList expects the value to be double values, to make it explicit, you use an explicit cast—((double) (i * i)); if you want, you can remove that explicit cast.
3.You print the contents of the intList and doubleList and also print the sum of elements by calling the sum() method you wrote; from the output you can see that the sum() method worked correctly for both types Integer and Double.
167