1. The two enhancements to numeric literals introduced by Java 7 are binary integer literals and underscores in numeric literals.
2. The diamond operator is an empty pair of angle brackets (<>) that serves as shorthand for specifying the actual type arguments when instantiating a generic type.
3. The answer is true: when multiple exception types are listed in a catch block’s header, the parameter is implicitly regarded as final.
4. The statement that Java 7 uses to implement automatic resource management is try-with-resources.
5. A classloader is an object that dynamically loads compiled classes and other reference types (classes, for short) from classfiles, Java Archive (JAR) files, URLs, and other sources into memory.
6. A classloader’s purpose is to insulate the virtual machine from filesystems, networks, and so on.
7. When the virtual machine starts running, the available classloaders are bootstrap, extension, and system.
8. The answer is false: the abstract ClassLoader class is the ultimate root class for all classloaders (including extension and system) except for bootstrap.
9. The bootstrap classloader is the root classloader.
10. The current classloader is the classloader that loads the class to which the currently executing method belongs.
11. The context classloader is the classloader associated with the current thread.
12. Central to ClassLoader are its Class<?> loadClass(String name) and protected Class<?> loadClass(String name, boolean resolve) methods, which try to load the class with the specified name.
13. The answer is true: context classloaders can be a source of difficulty. You’ll either observe a thrown ClassNotFoundException instance or you may end up with the wrong version of a class.
14. You can use a classloader to load arbitrary resources (such as images). For example, ClassLoader declares an InputStream getResourceAsStream(String name) method for this purpose.
15. The Console class provides methods to access the character-based console device, if any, associated with the current virtual machine.
16. You obtain the console by calling the System class’s Console console() class method and then testing the return value for null. If it isn’t null, you have obtained the console.
17. The answer is false: Console’s String readLine() method reads a single line of text (not including line-termination characters) from the console’s input stream.
18. A design pattern is a catalogued problem/solution entity that consists of a name, a problem statement, a solution, and a list of consequences.
19. The Strategy pattern lets you define a family of algorithms (such as sorting algorithms), encapsulate each algorithm in its own class, and make these algorithms interchangeable. Each encapsulated algorithm is known as a strategy. At runtime, your application chooses the appropriate algorithm that meets its requirements.
20. Double brace initialization is a special syntax for initializing a newly created object in a compact manner, for example, new Office() {{addEmployee(new Employee("John Doe"));}};.
21. The two drawbacks of double brace initialization are a potential bloated number of classfiles and the inability to use Java 7’s diamond operator when instantiating a generic type that’s been subclassed by an anonymous class.
22. A fluent interface is an implementation of an object-oriented API that
provides more readable code. It’s normally implemented via method chaining to relay the instruction context of a subsequent method call. The context is defined through the return value of a called method, the context is self- referential in that the new context is equivalent to the last context, and the context is terminated through the return of a void context.
23. Five advantages that immutable classes have over mutable classes are as follows: objects created from immutable classes are thread-safe and there are no synchronization issues; you can share the internals of an immutable class to reduce memory usage and improve performance; immutable classes support failure atomicity, which means that, after throwing an exception, an object is still in a well-defined and usable state, even when the exception occurred during an operation; immutable classes are excellent building blocks for more complex classes; and immutable objects make good Map keys and Set elements because objects must not change state while in a collection.
24. Four guidelines for making a class immutable are as follows: don’t include setter or other mutator methods in the class design, prevent methods from being overridden, declare all fields final, and prevent the class from exposing any mutable state.
25. Internationalization is the process of creating an application that
automatically adapts to its current user’s culture (without recompilation) so that the user can read text in the user’s language and otherwise interact with the application without observing cultural biases.
26. Localization is the adaptation of internationalized software to support a new culture by adding culture-specific elements (such as text strings that have been translated to the culture).
27. A locale is a geographical, political, or cultural region.
28. Java provides the Locale class to represent a locale.
29. An expression for obtaining the Canadian locale is new Locale("en", "CA") or Locale.CANADA.
30. You can change the default locale that’s made available to the virtual machine by assigning appropriate values to the user.language and
user.country system properties (via the -D command-line option) when you launch the application via the java tool.
31. A resource bundle is a container that holds one or more locale-specific elements, and which are each associated with one and only one locale.
32. The answer is true: each resource bundle family shares a common base name.
33. An application loads its resource bundles by calling the various getBundle() class methods that are located in the abstract ResourceBundle class.
34. MissingResourceException is thrown when a resource bundle cannot be found after an exhaustive search.
35. A property resource bundle is a resource bundle backed by a properties file, which is a text file (with a .properties extension) that stores textual elements as a series of key=value entries. PropertyResourceBundle, a concrete
subclass of ResourceBundle, manages property resource bundles.
36. A list resource bundle is a resource bundle backed by a classfile, which describes a concrete subclass of ListResourceBundle (an abstract subclass of ResourceBundle).
37. The answer is false: when a property resource bundle and a list resource bundle have the same complete resource bundle name, the list resource bundle takes precedence over the property resource bundle.
38. ResourceBundle provides the void clearCache() and void
clearCache(ClassLoader loader) class methods that make it possible to design a server application that clears out all cached resource bundles upon command.
39. Java 6 reworked ResourceBundle to depend on a nested Control class because ResourceBundle’s getBundle() methods were previously hardwired to look for resource bundles, and resource bundlers were always cached.
This lack of flexibility prevented you from performing tasks such as obtaining resource data from sources other than properties files and classfiles (such as an XML file or a database). The nested Control class provides several callback methods that are invoked during the resource bundle search-and- load process. By overriding specific callback methods, you can achieve the desired flexibility. When none of these methods are overridden, the getBundle() methods behave as they always have.
40. The BreakIterator class lets you detect text boundaries.
41. The Collator class lets you make reliable string comparisons, which is especially important for languages where the relative order of their characters doesn’t correspond to the Unicode values of these characters.
42. A date is a recorded temporal moment, a time zone is a set of geographical regions that share a common number of hours relative to Greenwich Mean Time (GMT), and a calendar is a system of organizing the passage of time.
43. The Date class represents a date as a positive or negative milliseconds value that’s relative to the Unix Epoch (January 1, 1970 GMT).
44. You obtain a calendar for the default locale that uses a specific time zone by invoking the Calendar getInstance(TimeZone zone) factory method.
45. The answer is false: Calendar declares a Date getTime() method that returns a calendar’s time representation as a Date instance.
46. The Format subclass that lets you obtain formatters that format numbers as currencies, integers, numbers with decimal points, and percentages (and also to parse such values) is NumberFormat.
47. You would obtain a date formatter to format the time portion of a date in a particular style for the default locale by invoking the DateFormat
getTimeInstance(int style) factory method.
48. The difference between a simple message and a compound message is as follows: a simple message consists of static (unchanging) text, whereas a compound message consists of static text and variable (changeable) data.
49. To format a simple message, you obtain its text from a resource bundle and then display this text to the user. For a compound message, you obtain a pattern (template) for the message from a property resource bundle, pass this pattern along with the variable data to a message formatter to create a simple message, and display this message’s text.
50. Java provides the MessageFormatter class to format simple and compound messages.
51. The class that you should use to format a compound message that contains singular and plural words is ChoiceFormat.
52. The answer is true: the Format class declares parseObject() methods for parsing strings into objects.
53. The package associated with Java’s Logging API is java.util.logging.
54. The Logger class is the entry-point into the Logging API.
55. The standard set of log level constants provided by the Level class are SEVERE, WARNING, INFO, CONFIG, FINE, FINER, and FINEST.
56. The answer is false: loggers default to outputting log records for severe, warning, and informational log levels only.
57. You obtain a logger by invoking one of Logger’s getLogger() or getAnonymousLogger() class methods.
58. You obtain a logger’s nearest parent logger by invoking Logger’s getLogger() method.
59. The four categories of message-logging methods are log(), logp(), logrb(), and miscellaneous (such as info()).
60. The entering() and exiting() methods log messages at the Level.FINER log level.
61. You change a logger’s log level by invoking Logger’s void setLevel(Level newLevel) method.
62. The Filter interface provides the boolean isLoggable(LogRecord record) method for further filtering log records regardless of their log levels.
63. You obtain the name of the method that’s the source of a log record by invoking LogRecord’s String getSourceMethodName() method.
64. The logging framework sends a log record to its ultimate destination (such as the console) by invoking a concrete handler’s overriding void publish(LogRecord record) method.
65. You obtain a logger’s registered handlers by invoking Logger’s Handler[]
getHandlers() method.
66. The answer is false: FileHandler’s default formatter is an instance of XMLFormatter.
67. The LogManager class manages a hierarchical namespace of all named Logger objects and maintains the configuration properties of the logging framework.
68. The Logging API’s logging methods never throw exceptions; it would be burdensome to force developers to wrap all of their logging calls in try/catch constructs. Besides, how would the application recover from an exception
in the logging framework? Because Handler classes such as FileHandler and StreamHandler can experience I/O exceptions, the Logging API provides the ErrorManager class so that a handler can report an exception instead of discarding it.
69. The Preferences API lets you store preferences in a hierarchical manner so that you can avoid name collisions. Because this API is backend-neutral, it doesn’t matter where the preferences are stored (a file, a database, or [on Windows platforms] the registry); you don’t have to hardcode file names and locations. Also, there are no text files that can be modified, and Preferences can be used on diskless platforms.
70. The Preferences API manages preferences by using trees of nodes. These nodes are the analogue of a hierarchical filesystem’s directories. Also, preference name/value pairs stored under these nodes are the analogues of a directory’s files. You navigate these trees in a similar manner to navigating a filesystem: specify an absolute path starting from the root node (/) to the node of interest, such as /window/location and /window/size.
71. The difference between the system preference tree and the user preference tree is as follows: all users share the system preference tree, whereas the user preference tree is specific to a single user, which is generally the person who logged into the underlying platform.
72. The package assigned to the Preferences API is java.util.prefs. This package contains three interfaces (NodeChangeListener,
PreferencesChangeListener, and PreferencesFactory), four regular classes (AbstractPreferences, NodeChangeEvent, PreferenceChangeEvent, and Preferences), and two exception classes (BackingStoreException and InvalidPreferencesFormatException).
73. The Preferences API’s Preferences class is the entry point.
74. You obtain the root node of the system preference tree by invoking Preferences’s Preferences systemRoot() class method.
75. The Runtime class provides Java applications with access to their runtime environment. You obtain an instance of this class by invoking its Runtime getRuntime() class method.
76. Runtime provides several exec() methods for executing other applications.
For example, Process exec(String program) executes the program named program in a separate native process. The new process inherits the
environment of the method’s caller, and a Process object is returned to allow communication with the new process. IOException is thrown when an I/O error occurs.
77. The Java Native Interface is a native programming interface that lets Java code running in a virtual machine interoperate with native libraries written in other languages (such as C, C++, or even assembly language). The JNI is a bridge between the virtual machine and the underlying platform to which the native libraries target.
78. A hybrid library is a combination of a Java class and a native interface library, which is a library that provides a native function counterpart for each declared native method, and it can communicate directly with platform-specific libraries.
79. The JNI throws UnsatisfiedLinkError when you try to load a nonexistent library.
80. The package for working with ZIP archives is java.util.zip.
81. Each stored file in a ZIP archive is known as a ZIP entry, which is represented by the ZipEntry class.
82. The answer is true: the name of a stored file in a ZIP archive cannot exceed 65,536 bytes.
83. ZipOutputStream writes ZIP entries (compressed as well as uncompressed) to a ZIP archive.
84. ZipInputStream reads ZIP entries (compressed as well as uncompressed) from a ZIP archive.
85. ZipFile appears to be an alias for ZipInputStream. 86. The package for working with JAR files is java.util.jar.
87. The manifest is a special file named MANIFEST.MF that stores information about the contents of the JAR file. This file is located in the JAR file’s META-INF directory.
88. The answer is true: when creating a manifest for a JAR output stream, you must store MANIFEST_VERSION; otherwise, you’ll observe a thrown exception at runtime.
89. Listing A-70 presents the SpanishCollation application that was called for in Chapter 16.
Listing A-70. Outputting Spanish Words According to This Language’s Current Collation Rules Followed by Its Traditional Collation Rules
import java.text.Collator;
import java.text.ParseException;
import java.text.RuleBasedCollator;
import java.util.Arrays;
import java.util.Locale;
public class SpanishCollation {
public static void main(String[] args) {
String[] words = {
"ủango", // weak "llamado", // called "lunes", // monday "champán", // champagne "clamor", // outcry "cerca", // near "nombre", // name "chiste", // joke };
Locale locale = new Locale("es", "");
Collator c = Collator.getInstance(locale);
Arrays.sort(words, c);
for (String word: words) System.out.println(word);
System.out.println();
// Define the traditional Spanish sort rules.
String upperNTilde = new String ("\u00D1");
String lowerNTilde = new String ("\u00F1");
String spanishRules = "< a,A < b,B < c,C < ch, cH, Ch, CH < d,D < e,E " + "< f,F < g,G < h,H < i,I < j,J < k,K < l,L < ll, " + "lL, Ll, LL < m,M < n,N < " + lowerNTilde + "," + upperNTilde + " < o,O < p,P < q,Q < r,R < s,S < " + "t,T < u,U < v,V < w,W < x,X < y,Y < z,Z";
try {
c = new RuleBasedCollator(spanishRules);
Arrays.sort(words, c);
for (String word: words) System.out.println(word);
}
catch (ParseException pe) {
System.err.println(pe);
} } }
Compile Listing A-70 as follows:
javac SpanishCollation.java Run this application as follows:
java SpanishCollation
You should observe the following output:
cerca champán chiste clamor llamado lunes nombre ủango cerca clamor champán chiste lunes llamado nombre ủango
90. Listing A-71 presents the ZipList application that was called for in Chapter 16.
Listing A-71. Archive Contents import java.io.FileInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipList {
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("usage: java ZipList zipfile");
return;
}
ZipInputStream zis = null;
try {
zis = new ZipInputStream(new FileInputStream(args[0]));
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
System.out.println(ze.getName());
System.out.println(" Compressed Size: " + ze.getCompressedSize());
System.out.println(" Uncompressed Size: " + ze.getSize());
if (ze.getTime() != -1)
System.out.println(" Modification Time: " + new Date(ze.getTime()));
System.out.println();
zis.closeEntry();
} }
catch (IOException ioe) {
System.err.println("I/O error: " + ioe.getMessage());
} finally {
if (zis != null) try
{
zis.close();
}
catch (IOException ioe) {
assert false; // shouldn't happen in this context }
} } }
1127
Appendix B
Four of a Kind
Application development isn’t an easy task. If you don’t plan carefully before you develop an application, you’ll probably waste your time and money as you endeavour to create it, and waste your users’ time and money when it doesn’t meet their needs.
Caution It’s extremely important to test your software carefully. You could face a lawsuit if malfunctioning software causes financial harm to its users.
In this appendix, I present one technique for developing applications efficiently. I present this technique in the context of a Java application that lets you play a simple card game called Four of a Kind against the computer.
Understanding Four of a Kind
Before sitting down at the computer and writing code, you need to fully understand the problem domain that you are trying to model via that code. In this case, the problem domain is Four of a Kind, and you want to understand how this card game works.
Two to four players play Four of a Kind with a standard 52-card deck. The object of the game is to be the first player to put down four cards that have the same rank (four aces, for example), which wins the game.
The game begins by shuffling the deck and placing it face down. Each player takes a card from the top of the deck. The player with the highest ranked card (king is highest) deals four cards to each player, starting with the player to the dealer’s left. The dealer then starts its turn.
The player examines her cards to determine which cards are optimal for achieving four of a kind.
The player then throws away the least helpful card on a discard pile and picks up another card from the top of the deck. (If each card has a different rank, the player randomly selects a card to throw away.) If the player has four of a kind, the player puts down these cards (face up) and wins the game.
Modeling Four of a Kind in Pseudocode
Now that you understand how Four of a Kind works, you can begin to model this game. You will not model the game in Java source code because you would get bogged down in too many details.
Instead, you will use pseudocode for this task.
Pseudocode is a compact and informal high-level description of the problem domain. Unlike the previous description of Four of a Kind, the pseudocode equivalent is a step-by-step recipe for solving the problem. Check out Listing B-1.
Listing B-1. Four of a Kind Pseudocode for Two Players (Human and Computer) 1. Create a deck of cards and shuffle the deck.
2. Create empty discard pile.
3. Have each of the human and computer players take a card from the top of the deck.
4. Designate the player with the highest ranked card as the current player.
5. Return both cards to the bottom of the deck.
6. The current player deals four cards to each of the two players in alternating fashion, with the first card being dealt to the other player.
7. The current player examines its current cards to see which cards are optimal for achieving four of a kind. The current player throws the least helpful card onto the top of the discard pile.
8. The current player picks up the deck's top card. If the current player has four of a kind, it puts down its cards and wins the game.
9. Designate the other player as the current player.
10. If the deck has no more cards, empty the discard pile to the deck and shuffle the deck.
11. Repeat at step 7.
Deriving Listing B-1’s pseudocode from the previous description is the first step in achieving an application that implements Four of a Kind. This pseudocode performs various tasks including decision making and repetition.
Despite being a more useful guide to understanding how Four of a Kind works, Listing B-1 is too high level for translation to Java. Therefore, you must refine this pseudocode to facilitate the translation process. Listing B-2 presents this refinement.
Listing B-2. Refined Four of a Kind Pseudocode for Two Players (Human and Computer) 1. deck = new Deck()
2. deck.shuffle()
3. discardPile = new DiscardPile() 4. hCard = deck.deal()
5. cCard = deck.deal()
6. if hCard.rank() == cCard.rank() 6.1. deck.putBack(hCard) 6.2. deck.putBack(cCard) 6.3. deck.shuffle() 6.4. Repeat at step 4 7. curPlayer = HUMAN
7.1. if cCard.rank() > hCard.rank() 7.1.1. curPlayer = COMPUTER 8. deck.putBack(hCard)
9. deck.putBack(cCard)