846 |
847 |
848 |
849 |
850 |
851 |
--------------------------------------------------------------------------------
/Effective-Java-Third-Edition-Reading-Notes.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Effective-Java-Third-Edition-Reading-Notes
2 | Reading Effective Java, Third Edition in 11 days (3 hours per day) and make notes as much as possible.
3 |
4 | - [X] Chapter 1: Introduction
5 | - [X] Chapter 2: Creating and Destroying Objects
6 | - [X] Chapter 3: Methods Common to All Objects
7 | - [X] Chapter 4: Classes and Interfaces
8 | - [X] Chapter 5: Generics
9 | - [X] Chapter 6: Enums and Annotations
10 | - [X] Chapter 7: Lambdas and Streams
11 | - [X] Chapter 8: Methods
12 | - [X] Chapter 9: General Programming
13 | - [X] Chapter 10: Exceptions
14 | - [X] Chapter 11: Concurrency
15 | - [ ] Chapter 12: Serialization
16 |
17 |
--------------------------------------------------------------------------------
/src/Main.java:
--------------------------------------------------------------------------------
1 | public class Main {
2 |
3 | public static void main(String[] args) {
4 | System.out.println("Hello Effective Java III !");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/chapter10_Exceptions/Exceptions.md:
--------------------------------------------------------------------------------
1 | # Chapter 10. Exceptions
2 |
3 | WHEN used to best advantage, exceptions can improve a program’s readability, reliability, and maintainability. When
4 | used improperly, they can have the opposite effect. This chapter provides guidelines for using exceptions effectively.
5 |
6 | ## ITEM 69: USE EXCEPTIONS ONLY FOR EXCEPTIONAL CONDITIONS
7 |
8 | Someday, if you are unlucky, you may stumble across a piece of code that looks something like this:
9 |
10 | ```aidl
11 | // Horrible abuse of exceptions. Don't ever do this!
12 | try {
13 | int i = 0;
14 | while(true)
15 | range[i++].climb();
16 | } catch (ArrayIndexOutOfBoundsException e) {
17 |
18 | }
19 | ```
20 |
21 | What does this code do? It’s not at all obvious from inspection, and that’s reason enough not to use it (Item 67). It
22 | turns out to be a horribly ill-conceived idiom for looping through the elements of an array. The infinite loop
23 | terminates by throwing, catching, and ignoring an ArrayIndexOutOfBoundsException when it attempts to access the
24 | first array element outside the bounds of the array. It’s supposed to be equivalent to the standard idiom for looping
25 | through an array, which is instantly recognizable to any Java programmer:
26 | ```aidl
27 | for (Mountain m : range)
28 | m.climb();
29 | ```
30 | So why would anyone use the exception-based loop in preference to the tried and true? It’s a misguided attempt to
31 | improve performance based on the faulty reasoning that, since the VM checks the bounds of all array accesses, the
32 | normal loop termination test—hidden by the compiler but still present in the for-each loop—is redundant and should
33 | be avoided. There are three things wrong with this reasoning:
34 |
35 | 1. • Because exceptions are designed for exceptional circumstances, there is little incentive for JVM implementors
36 | to make them as fast as explicit tests.
37 |
38 | 2. • Placing code inside a try-catch block inhibits certain optimizations that JVM implementations might
39 | otherwise perform.
40 |
41 | 3. • The standard idiom for looping through an array doesn’t necessarily result in redundant checks. Many JVM
42 | implementations optimize them away.
43 | {Aaron notes: Above is an important design.}
44 |
45 | In fact, the exception-based idiom is far slower than the standard one. On my machine, the exception-based idiom
46 | is about twice as slow as the standard one for arrays of one hundred elements.
47 |
48 | Not only does the exception-based loop obfuscate the purpose of the code and reduce its performance, but it’s
49 | not guaranteed to work. If there is a bug in the loop, the use of exceptions for flow control can mask the bug,
50 | greatly complicating the debugging process. Suppose the computation in the body of the loop invokes a method
51 | that performs an out-of-bounds access to some unrelated array. If a reasonable loop idiom were used, the bug
52 | would generate an uncaught exception, resulting in immediate thread termination with a full stack trace. If
53 | the misguided exception-based loop were used, the bug-related exception would be caught and misinterpreted
54 | as a normal loop termination.
55 |
56 | The moral of this story is simple: Exceptions are, as their name implies, to be used only for exceptional
57 | conditions; they should never be used for ordinary control flow. More generally, use standard, easily recognizable
58 | idioms in preference to overly clever techniques that purport to offer better performance. Even if the performance
59 | advantage is real, it may not remain in the face of steadily improving platform implementations. The subtle bugs
60 | and maintenance headaches that come from overly clever techniques, however, are sure to remain.
61 |
62 | This principle also has implications for API design. A well-designed API must not force its clients to use
63 | exceptions for ordinary control flow. A class with a “state-dependent” method that can be invoked only under certain
64 | unpredictable conditions should generally have a separate “state-testing” method indicating whether it is appropriate
65 | to invoke the state-dependent method. For example, the Iterator interface has the state-dependent method next and
66 | the corresponding state-testing method hasNext. This enables the standard idiom for iterating over a collection
67 | with a traditional for loop (as well as the for-each loop, where the hasNext method is used internally):
68 | ```aidl
69 | for (Iterator i = collection.iterator(); i.hasNext(); ) {
70 | Foo foo = i.next();
71 | ...
72 | }
73 | ```
74 | {Aaron notes: Above is an important design.}
75 |
76 | If Iterator lacked the hasNext method, clients would be forced to do this instead:
77 | ```aidl
78 | // Do not use this hideous code for iteration over a collection!
79 | try {
80 | Iterator i = collection.iterator();
81 | while(true) {
82 | Foo foo = i.next();
83 | ...
84 | }
85 | } catch (NoSuchElementException e) {
86 | }
87 | ```
88 | This should look very familiar after the array iteration example that began this item. In addition to being wordy
89 | and misleading, the exception-based loop is likely to perform poorly and can mask bugs in unrelated parts of the
90 | system.
91 |
92 | An alternative to providing a separate state-testing method is to have the state-dependent method return an empty
93 | optional (Item 55) or a distinguished value such as null if it cannot perform the desired computation.
94 |
95 | Here are some guidelines to help you choose between a state-testing method and an optional or distinguished
96 | return value. If an object is to be accessed concurrently without external synchronization or is subject to
97 | externally induced state transitions, you must use an optional or distinguished return value, as the object’s state
98 | could change in the interval between the invocation of a state-testing method and its state-dependent method.
99 | Performance concerns may dictate that an optional or distinguished return value be used if a separate state-testing
100 | method would duplicate the work of the state-dependent method. All other things being equal, a state-testing
101 | method is mildly preferable to a distinguished return value. It offers slightly better readability, and incorrect
102 | use may be easier to detect: if you forget to call a state-testing method, the state-dependent method will throw
103 | an exception, making the bug obvious; if you forget to check for a distinguished return value, the bug may be
104 | subtle. This is not an issue for optional return values.
105 |
106 | ### In summary, exceptions are designed for exceptional conditions. Don’t use them for ordinary control flow, and don’t write APIs that force others to do so.
107 |
108 | ## ITEM 70: USE CHECKED EXCEPTIONS FOR RECOVERABLE CONDITIONS AND RUNTIME EXCEPTIONS FOR PROGRAMMING ERRORS
109 |
110 | Java provides three kinds of throwables: checked exceptions, runtime exceptions, and errors. There is some confusion
111 | among programmers as to when it is appropriate to use each kind of throwable. While the decision is not always
112 | clear-cut, there are some general rules that provide strong guidance.
113 |
114 | The cardinal rule in deciding whether to use a checked or an unchecked exception is this: use checked exceptions for
115 | conditions from which the caller can reasonably be expected to recover. By throwing a checked exception, you force
116 | the caller to handle the exception in a catch clause or to propagate it outward. Each checked exception that a method
117 | is declared to throw is therefore a potent indication to the API user that the associated condition is a possible
118 | outcome of invoking the method.
119 | {Aaron notes: Above is an important design.}
120 |
121 | By confronting the user with a checked exception, the API designer presents a mandate to recover from the condition.
122 | The user can disregard the mandate by catching the exception and ignoring it, but this is usually a bad idea (Item 77).
123 |
124 | There are two kinds of unchecked throwables: runtime exceptions and errors. They are identical in their behavior:
125 | both are throwables that needn’t, and generally shouldn’t, be caught. If a program throws an unchecked exception or an
126 | error, it is generally the case that recovery is impossible and continued execution would do more harm than good. If a
127 | program does not catch such a throwable, it will cause the current thread to halt with an appropriate error message.
128 |
129 | Use runtime exceptions to indicate programming errors. The great majority of runtime exceptions indicate precondition
130 | violations. A precondition violation is simply a failure by the client of an API to adhere to the contract established
131 | by the API specification. For example, the contract for array access specifies that the array index must be between
132 | zero and the array length minus one, inclusive. ArrayIndexOutOfBoundsException indicates that this precondition was
133 | violated.
134 |
135 | One problem with this advice is that it is not always clear whether you’re dealing with a recoverable conditions or a
136 | programming error. For example, consider the case of resource exhaustion, which can be caused by a programming error
137 | such as allocating an unreasonably large array, or by a genuine shortage of resources. If resource exhaustion is caused
138 | by a temporary shortage or by temporarily heightened demand, the condition may well be recoverable. It is a matter
139 | of judgment on the part of the API designer whether a given instance of resource exhaustion is likely to allow for
140 | recovery. If you believe a condition is likely to allow for recovery, use a checked exception; if not, use a runtime
141 | exception. If it isn’t clear whether recovery is possible, you’re probably better off using an unchecked exception,
142 | for reasons discussed in Item 71.
143 |
144 | While the Java Language Specification does not require it, there is a strong convention that errors are reserved for
145 | use by the JVM to indicate resource deficiencies, invariant failures, or other conditions that make it impossible to
146 | continue execution. Given the almost universal acceptance of this convention, it’s best not to implement any new
147 | Error subclasses. Therefore, all of the unchecked throwables you implement should subclass RuntimeException (directly
148 | or indirectly). Not only shouldn’t you define Error subclasses, but with the exception of AssertionError, you
149 | shouldn’t throw them either.
150 |
151 | It is possible to define a throwable that is not a subclass of Exception, RuntimeException, or Error. The JLS doesn’t
152 | address such throwables directly but specifies implicitly that they behave as ordinary checked exceptions (which are
153 | subclasses of Exception but not RuntimeException). So when should you use such a beast? In a word, never. They have
154 | no benefits over ordinary checked exceptions and would serve merely to confuse the user of your API.
155 |
156 | API designers often forget that exceptions are full-fledged objects on which arbitrary methods can be defined. The
157 | primary use of such methods is to provide code that catches the exception with additional information concerning
158 | the condition that caused the exception to be thrown. In the absence of such methods, programmers have been known
159 | to parse the string representation of an exception to ferret out additional information. This is extremely bad
160 | practice (Item 12). Throwable classes seldom specify the details of their string representations, so string
161 | representations can differ from implementation to implementation and release to release. Therefore, code that parses
162 | the string representation of an exception is likely to be nonportable and fragile.
163 |
164 | Because checked exceptions generally indicate recoverable conditions, it’s especially important for them to provide
165 | methods that furnish information to help the caller recover from the exceptional condition. For example, suppose a
166 | checked exception is thrown when an attempt to make a purchase with a gift card fails due to insufficient funds.
167 | The exception should provide an accessor method to query the amount of the shortfall. This will enable the caller
168 | to relay the amount to the shopper. See Item 75 for more on this topic.
169 |
170 | ### To summarize, throw checked exceptions for recoverable conditions and unchecked exceptions for programming errors. When in doubt, throw unchecked exceptions. Don’t define any throwables that are neither checked exceptions nor runtime exceptions. Provide methods on your checked exceptions to aid in recovery.
171 |
172 | ## ITEM 71: AVOID UNNECESSARY USE OF CHECKED EXCEPTIONS
173 |
174 | Many Java programmers dislike checked exceptions, but used properly, they can improve APIs and programs. Unlike return
175 | codes and unchecked exceptions, they force programmers to deal with problems, enhancing reliability. That said,
176 | overuse of checked exceptions in APIs can make them far less pleasant to use. If a method throws checked exceptions,
177 | the code that invokes it must handle them in one or more catch blocks, or declare that it throws them and let them
178 | propagate outward. Either way, it places a burden on the user of the API. The burden increased in Java 8, as methods
179 | throwing checked exceptions can’t be used directly in streams (Items 45–48).
180 |
181 | This burden may be justified if the exceptional condition cannot be prevented by proper use of the API and the
182 | programmer using the API can take some useful action once confronted with the exception. Unless both of these
183 | conditions are met, an unchecked exception is appropriate. As a litmus test, ask yourself how the programmer will
184 | handle the exception. Is this the best that can be done?
185 |
186 | ```aidl
187 | } catch (TheCheckedException e) {
188 | throw new AssertionError(); // Can't happen!
189 | }
190 | ```
191 | Or this?
192 | ```aidl
193 | } catch (TheCheckedException e) {
194 | e.printStackTrace(); // Oh well, we lose.
195 | System.exit(1);
196 | }
197 | ```
198 | If the programmer can do no better, an unchecked exception is called for.
199 |
200 | The additional burden on the programmer caused by a checked exception is substantially higher if it is the sole checked
201 | exception thrown by a method. If there are others, the method must already appear in a try block, and this exception
202 | requires, at most, another catch block. If a method throws a single checked exception, this exception is the sole reason
203 | the method must appear in a try block and can’t be used directly in streams. Under these circumstances, it pays to ask
204 | yourself if there is a way to avoid the checked exception.
205 |
206 | The easiest way to eliminate a checked exception is to return an optional of the desired result type (Item 55). Instead
207 | of throwing a checked exception, the method simply returns an empty optional. The disadvantage of this technique is that
208 | the method can’t return any additional information detailing its inability to perform the desired computation. Exceptions,
209 | by contrast, have descriptive types, and can export methods to provide additional information (Item 70).
210 | {Aaron notes: Above is an important design.}
211 |
212 | You can also turn a checked exception into an unchecked exception by breaking the method that throws the exception into
213 | two methods, the first of which returns a boolean indicating whether the exception would be thrown. This API refactoring
214 | transforms the calling sequence from this:
215 | ```aidl
216 | // Invocation with checked exception
217 | try {
218 | obj.action(args);
219 | } catch (TheCheckedException e) {
220 | ... // Handle exceptional condition
221 | }
222 | ```
223 | into this:
224 | ```aidl
225 | // Invocation with state-testing method and unchecked exception
226 | if (obj.actionPermitted(args)) {
227 | obj.action(args);
228 | } else {
229 | ... // Handle exceptional condition
230 | }
231 | ```
232 | This refactoring is not always appropriate, but where it is, it can make an API more pleasant to use. While the latter
233 | calling sequence is no prettier than the former, the refactored API is more flexible. If the programmer knows the call
234 | will succeed, or is content to let the thread terminate if it fails, the refactoring also allows this trivial calling
235 | sequence:
236 | ```aidl
237 | obj.action(args);
238 | ```
239 | If you suspect that the trivial calling sequence will be the norm, then the API refactoring may be appropriate. The
240 | resulting API is essentially the state-testing method API in Item 69 and the same caveats apply: if an object is to
241 | be accessed concurrently without external synchronization or it is subject to externally induced state transitions,
242 | this refactoring is inappropriate because the object’s state may change between the calls to actionPermitted and
243 | action. If a separate actionPermitted method would duplicate the work of the action method, the refactoring may be
244 | ruled out on performance grounds.
245 |
246 | ### In summary, when used sparingly, checked exceptions can increase the reliability of programs; when overused, they make APIs painful to use. If callers won’t be able to recover from failures, throw unchecked exceptions. If recovery may be possible and you want to force callers to handle exceptional conditions, first consider returning an optional. Only if this would provide insufficient information in the case of failure should you throw a checked exception.
247 |
248 | ## ITEM 72: FAVOR THE USE OF STANDARD EXCEPTIONS
249 |
250 | An attribute that distinguishes expert programmers from less experienced ones is that experts strive for and usually
251 | achieve a high degree of code reuse. Exceptions are no exception to the rule that code reuse is a good thing. The Java
252 | libraries provide a set of exceptions that covers most of the exception-throwing needs of most APIs.
253 |
254 | Reusing standard exceptions has several benefits. Chief among them is that it makes your API easier to learn and use
255 | because it matches the established conventions that programmers are already familiar with. A close second is that
256 | programs using your API are easier to read because they aren’t cluttered with unfamiliar exceptions. Last (and least),
257 | fewer exception classes means a smaller memory footprint and less time spent loading classes.
258 |
259 | The most commonly reused exception type is IllegalArgumentException (Item 49). This is generally the exception to throw
260 | when the caller passes in an argument whose value is inappropriate. For example, this would be the exception to throw
261 | if the caller passed a negative number in a parameter representing the number of times some action was to be repeated.
262 |
263 | Another commonly reused exception is IllegalStateException. This is generally the exception to throw if the invocation
264 | is illegal because of the state of the receiving object. For example, this would be the exception to throw if the
265 | caller attempted to use some object before it had been properly initialized.
266 |
267 | Arguably, every erroneous method invocation boils down to an illegal argument or state, but other exceptions are
268 | standardly used for certain kinds of illegal arguments and states. If a caller passes null in some parameter for
269 | which null values are prohibited, convention dictates that NullPointerException be thrown rather than
270 | IllegalArgumentException. Similarly, if a caller passes an out-of-range value in a parameter representing an index
271 | into a sequence, IndexOutOfBoundsException should be thrown rather than IllegalArgumentException.
272 |
273 | Another reusable exception is ConcurrentModificationException. It should be thrown if an object that was designed
274 | for use by a single thread (or with external synchronization) detects that it is being modified concurrently. This
275 | exception is at best a hint because it is impossible to reliably detect concurrent modification.
276 |
277 | A last standard exception of note is UnsupportedOperationException. This is the exception to throw if an object
278 | does not support an attempted operation. Its use is rare because most objects support all of their methods. This
279 | exception is used by classes that fail to implement one or more optional operations defined by an interface they
280 | implement. For example, an append-only List implementation would throw this exception if someone tried to delete
281 | an element from the list.
282 |
283 | Do not reuse Exception, RuntimeException, Throwable, or Error directly. Treat these classes as if they were
284 | abstract. You can't reliably test for these exceptions because they are superclasses of other exceptions
285 | that a method may throw.
286 | {Aaron notes: Above is an important design.}
287 |
288 | This table summarizes the most commonly reused exceptions:
289 |
290 | Exception Occasion for Use
291 |
292 | 1.IllegalArgumentException Non-null parameter value is inappropriate
293 |
294 | 2.IllegalStateException Object state is inappropriate for method invocation
295 |
296 | 3.NullPointerException Parameter value is null where prohibited
297 |
298 | 4.IndexOutOfBoundsException Index parameter value is out of range
299 |
300 | 5.ConcurrentModificationException Concurrent modification of an object has been detected where it is prohibited
301 |
302 | 6.UnsupportedOperationException Object does not support method
303 | {Aaron notes: Above is an important design.}
304 |
305 | While these are by far the most commonly reused exceptions, others may be reused where circumstances warrant.
306 | For example, it would be appropriate to reuse ArithmeticException and NumberFormatException if you were implementing
307 | arithmetic objects such as complex numbers or rational numbers. If an exception fits your needs, go ahead and use it,
308 | but only if the conditions under which you would throw it are consistent with the exception’s documentation: reuse
309 | must be based on documented semantics, not just on name. Also, feel free to subclass a standard exception if you want
310 | to add more detail (Item 75), but remember that exceptions are serializable (Chapter 12). That alone is reason not to
311 | write your own exception class without good reason.
312 |
313 | ### Choosing which exception to reuse can be tricky because the “occasions for use” in the table above do not appear to be mutually exclusive. Consider the case of an object representing a deck of cards, and suppose there were a method to deal a hand from the deck that took as an argument the size of the hand. If the caller passed a value larger than the number of cards remaining in the deck, it could be construed as an IllegalArgumentException (the handSize parameter value is too high) or an IllegalStateException (the deck contains too few cards). Under these circumstances, the rule is to throw IllegalStateException if no argument values would have worked, otherwise throw IllegalArgumentException.
314 |
315 | ## ITEM 73: THROW EXCEPTIONS APPROPRIATE TO THE ABSTRACTION
316 |
317 | It is disconcerting when a method throws an exception that has no apparent connection to the task that it performs.
318 | This often happens when a method propagates an exception thrown by a lower-level abstraction. Not only is it
319 | disconcerting, but it pollutes the API of the higher layer with implementation details. If the implementation of
320 | the higher layer changes in a later release, the exceptions it throws will change too, potentially breaking existing
321 | client programs.
322 |
323 | To avoid this problem, higher layers should catch lower-level exceptions and, in their place, throw exceptions that
324 | can be explained in terms of the higher-level abstraction. This idiom is known as exception translation:
325 | ```aidl
326 | // Exception Translation
327 | try {
328 | ... // Use lower-level abstraction to do our bidding
329 | } catch (LowerLevelException e) {
330 | throw new HigherLevelException(...);
331 | }
332 | ```
333 |
334 | Here is an example of exception translation taken from the AbstractSequentialList class, which is a skeletal
335 | implementation (Item 20) of the List interface. In this example, exception translation is mandated by the specification
336 | of the get method in the List interface:
337 |
338 | ```aidl
339 | /**
340 | * Returns the element at the specified position in this list.
341 | * @throws IndexOutOfBoundsException if the index is out of range
342 | * ({@code index < 0 || index >= size()}).
343 | */
344 | public E get(int index) {
345 |
346 | ListIterator i = listIterator(index);
347 | try {
348 | return i.next();
349 | } catch (NoSuchElementException e) {
350 | throw new IndexOutOfBoundsException("Index: " + index);
351 | }
352 | }
353 | ```
354 |
355 | A special form of exception translation called exception chaining is called for in cases where the lower-level exception
356 | might be helpful to someone debugging the problem that caused the higher-level exception. The lower-level exception
357 | (the cause) is passed to the higher-level exception, which provides an accessor method (Throwable’s getCause method)
358 | to retrieve the lower-level exception:
359 |
360 | ```aidl
361 | // Exception Chaining
362 | try {
363 | ... // Use lower-level abstraction to do our bidding
364 | } catch (LowerLevelException cause) {
365 | throw new HigherLevelException(cause);
366 | }
367 | ```
368 |
369 | The higher-level exception’s constructor passes the cause to a chaining-aware superclass constructor, so it is
370 | ultimately passed to one of Throwable’s chaining-aware constructors, such as Throwable(Throwable):
371 |
372 | ```aidl
373 | // Exception with chaining-aware constructor
374 | class HigherLevelException extends Exception {
375 | HigherLevelException(Throwable cause) {
376 | super(cause);
377 | }
378 | }
379 | ```
380 |
381 | Most standard exceptions have chaining-aware constructors. For exceptions that don’t, you can set the cause using
382 | Throwable’s initCause method. Not only does exception chaining let you access the cause programmatically
383 | (with getCause), but it integrates the cause’s stack trace into that of the higher-level exception.
384 |
385 | While exception translation is superior to mindless propagation of exceptions from lower layers, it should not
386 | be overused. Where possible, the best way to deal with exceptions from lower layers is to avoid them, by ensuring
387 | that lower-level methods succeed. Sometimes you can do this by checking the validity of the higher-level method’s
388 | parameters before passing them on to lower layers.
389 | {Aaron notes: Above is an important design.}
390 |
391 | If it is impossible to prevent exceptions from lower layers, the next best thing is to have the higher layer silently
392 | work around these exceptions, insulating the caller of the higher-level method from lower-level problems. Under
393 | these circumstances, it may be appropriate to log the exception using some appropriate logging facility such as
394 | java.util.logging. This allows programmers to investigate the problem, while insulating client code and the
395 | users from it.
396 | {Aaron notes: Above is an important design.}
397 |
398 | ### In summary, if it isn’t feasible to prevent or to handle exceptions from lower layers, use exception translation, unless the lower-level method happens to guarantee that all of its exceptions are appropriate to the higher level. Chaining provides the best of both worlds: it allows you to throw an appropriate higher-level exception, while capturing the underlying cause for failure analysis (Item 75).
399 | {Aaron notes: Above is an important design.}
400 |
401 | ## ITEM 74: DOCUMENT ALL EXCEPTIONS THROWN BY EACH METHOD
402 |
403 | A description of the exceptions thrown by a method is an important part of the documentation required to use the method
404 | properly. Therefore, it is critically important that you take the time to carefully document all of the exceptions
405 | thrown by each method (Item 56).
406 |
407 | Always declare checked exceptions individually, and document precisely the conditions under which each one is
408 | thrown using the Javadoc @throws tag. Don’t take the shortcut of declaring that a method throws some superclass of
409 | multiple exception classes that it can throw. As an extreme example, don’t declare that a public method throws
410 | Exception or, worse, throws Throwable. In addition to denying any guidance to the method’s user concerning the
411 | exceptions it is capable of throwing, such a declaration greatly hinders the use of the method because it effectively
412 | obscures any other exception that may be thrown in the same context. One exception to this advice is the main method,
413 | which can safely be declared to throw Exception because it is called only by VM.
414 | {Aaron notes: Above is an important design.}
415 |
416 | While the language does not require programmers to declare the unchecked exceptions that a method is capable of
417 | throwing, it is wise to document them as carefully as the checked exceptions. Unchecked exceptions generally represent
418 | programming errors (Item 70), and familiarizing programmers with all of the errors they can make helps them avoid
419 | making these errors. A well-documented list of the unchecked exceptions that a method can throw effectively describes
420 | the preconditions for its successful execution. It is essential that every public method’s documentation describe its
421 | preconditions (Item 56), and documenting its unchecked exceptions is the best way to satisfy this requirement.
422 |
423 | It is particularly important that methods in interfaces document the unchecked exceptions they may throw. This
424 | documentation forms a part of the interface’s general contract and enables common behavior among multiple
425 | implementations of the interface.
426 |
427 | Use the Javadoc @throws tag to document each exception that a method can throw, but do not use the throws keyword on
428 | unchecked exceptions. It is important that programmers using your API are aware of which exceptions are checked and
429 | which are unchecked because the programmers’ responsibilities differ in these two cases. The documentation generated
430 | by the Javadoc @throws tag without a corresponding throws clause in the method declaration provides a strong visual
431 | cue to the programmer that an exception is unchecked.
432 |
433 | It should be noted that documenting all of the unchecked exceptions that each method can throw is an ideal, not always
434 | achievable in the real world. When a class undergoes revision, it is not a violation of source or binary compatibility
435 | if an exported method is modified to throw additional unchecked exceptions. Suppose a class invokes a method from
436 | another, independently written class. The authors of the former class may carefully document all of the unchecked
437 | exceptions that each method throws, but if the latter class is revised to throw additional unchecked exceptions, it
438 | is quite likely that the former class (which has not undergone revision) will propagate the new unchecked exceptions
439 | even though it does not document them.
440 |
441 | If an exception is thrown by many methods in a class for the same reason, you can document the exception in the class’s
442 | documentation comment rather than documenting it individually for each method.I A common example is NullPointerException.
443 | It is fine for a class’s documentation comment to say, “All methods in this class throw a NullPointerException if a null
444 | object reference is passed in any parameter,” or words to that effect.
445 |
446 | ### In summary, document every exception that can be thrown by each method that you write. This is true for unchecked as well as checked exceptions, and for abstract as well as concrete methods. This documentation should take the form of @throws tags in doc comments. Declare each checked exception individually in a method’s throws clause, but do not declare unchecked exceptions. If you fail to document the exceptions that your methods can throw, it will be difficult or impossible for others to make effective use of your classes and interfaces.
447 |
448 | ## ITEM 75: INCLUDE FAILURE-CAPTURE INFORMATION IN DETAIL MESSAGES
449 |
450 | When a program fails due to an uncaught exception, the system automatically prints out the exception’s stack trace.
451 | The stack trace contains the exception’s string representation, the result of invoking its toString method. This
452 | typically consists of the exception’s class name followed by its detail message. Frequently this is the only
453 | information that programmers or site reliability engineers will have when investigating a software failure. If the
454 | failure is not easily reproducible, it may be difficult or impossible to get any more information. Therefore, it
455 | is critically important that the exception’s toString method return as much information as possible
456 | concerning the cause of the failure. In other words, the detail message of an exception should capture the
457 | failure for subsequent analysis.
458 | {Aaron notes: Above is an important design.}
459 |
460 | To capture a failure, the detail message of an exception should contain the values of all parameters and fields
461 | that contributed to the exception. For example, the detail message of an IndexOutOfBoundsException should
462 | contain the lower bound, the upper bound, and the index value that failed to lie between the bounds. This
463 | information tells a lot about the failure. Any or all of the three values could be wrong. The index could be one
464 | less than the lower bound or equal to the upper bound (a “fencepost error”), or it could be a wild value, far
465 | too low or high. The lower bound could be greater than the upper bound (a serious internal invariant failure).
466 | Each of these situations points to a different problem, and it greatly aids in the diagnosis if you know what
467 | sort of error you’re looking for.
468 | {Aaron notes: Above is an important design.}
469 |
470 | One caveat concerns security-sensitive information. Because stack traces may be seen by many people in the
471 | process of diagnosing and fixing software issues, do not include passwords, encryption keys, and the like in
472 | detail messages.
473 |
474 | While it is critical to include all of the pertinent data in the detail message of an exception, it is generally
475 | unimportant to include a lot of prose. The stack trace is intended to be analyzed in conjunction with the
476 | documentation and, if necessary, source code. It generally contains the exact file and line number from which the
477 | exception was thrown, as well as the files and line numbers of all other method invocations on the stack.
478 | Lengthy prose descriptions of the failure are superfluous; the information can be gleaned by reading the
479 | documentation and source code.
480 |
481 | The detail message of an exception should not be confused with a user-level error message, which must be
482 | intelligible to end users. Unlike a user-level error message, the detail message is primarily for the benefit of
483 | programmers or site reliability engineers, when analyzing a failure. Therefore, information content is far more
484 | important than readability. User-level error messages are often localized, whereas exception detail messages
485 | rarely are.
486 |
487 | One way to ensure that exceptions contain adequate failure-capture information in their detail messages is to
488 | require this information in their constructors instead of a string detail message. The detail message can then
489 | be generated automatically to include the information. For example, instead of a String constructor,
490 | IndexOutOfBoundsException could have had a constructor that looks like this:
491 | ```aidl
492 | /**
493 | * Constructs an IndexOutOfBoundsException.
494 | *
495 | * @param lowerBound the lowest legal index value
496 | * @param upperBound the highest legal index value plus one
497 | * @param index the actual index value
498 | */
499 |
500 | public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) {
501 |
502 | // Generate a detail message that captures the failure
503 | super(String.format( "Lower bound: %d, Upper bound: %d, Index: %d", lowerBound, upperBound, index));
504 |
505 | // Save failure information for programmatic access
506 | this.lowerBound = lowerBound;
507 | this.upperBound = upperBound;
508 | this.index = index;
509 | }
510 | ```
511 |
512 | As of Java 9, IndexOutOfBoundsException finally acquired a constructor that takes an int valued index parameter, but
513 | sadly it omits the lowerBound and upperBound parameters. More generally, the Java libraries don’t make heavy use
514 | of this idiom, but it is highly recommended. It makes it easy for the programmer throwing an exception to capture
515 | the failure. In fact, it makes it hard for the programmer not to capture the failure! In effect, the idiom
516 | centralizes the code to generate a high-quality detail message in the exception class, rather than requiring each
517 | user of the class to generate the detail message redundantly.
518 | {Aaron notes: Above is an important design.}
519 |
520 | ### As suggested in Item 70, it may be appropriate for an exception to provide accessor methods for its failure-capture information (lowerBound, upperBound, and index in the above example). It is more important to provide such accessor methods on checked exceptions than unchecked, because the failure-capture information could be useful in recovering from the failure. It is rare (although not inconceivable) that a programmer might want programmatic access to the details of an unchecked exception. Even for unchecked exceptions, however, it seems advisable to provide these accessors on general principle (Item 12, page 57).
521 |
522 | ## ITEM 76: STRIVE FOR FAILURE ATOMICITY
523 |
524 | After an object throws an exception, it is generally desirable that the object still be in a well-defined, usable state,
525 | even if the failure occurred in the midst of performing an operation. This is especially true for checked exceptions,
526 | from which the caller is expected to recover. Generally speaking, a failed method invocation should leave the object in
527 | the state that it was in prior to the invocation. A method with this property is said to be failure-atomic.
528 |
529 | There are several ways to achieve this effect. The simplest is to design immutable objects (Item 17).
530 |
531 | 0. If an object is immutable, failure atomicity is free. If an operation fails, it may prevent a new object from
532 | getting created, but it will never leave an existing object in an inconsistent state, because the state of each
533 | object is consistent when it is created and can’t be modified thereafter.
534 |
535 | 1. For methods that operate on mutable objects, the most common way to achieve failure atomicity is to check parameters
536 | for validity before performing the operation (Item 49). This causes most exceptions to get thrown before object
537 | modification commences. For example, consider the Stack.pop method in Item 7:
538 |
539 | ```aidl
540 | public Object pop() {
541 |
542 | if (size == 0)
543 | throw new EmptyStackException();
544 |
545 | Object result = elements[--size];
546 | elements[size] = null; // Eliminate obsolete reference
547 | return result;
548 | }
549 | ```
550 |
551 | If the initial size check were eliminated, the method would still throw an exception when it attempted to pop an
552 | element from an empty stack. It would, however, leave the size field in an inconsistent (negative) state, causing
553 | any future method invocations on the object to fail. Additionally, the ArrayIndexOutOfBoundsException thrown by the
554 | pop method would be inappropriate to the abstraction (Item 73).
555 | {Aaron notes: Above is an important design.}
556 |
557 | 2. A closely related approach to achieving failure atomicity is to order the computation so that any part that may
558 | fail takes place before any part that modifies the object. This approach is a natural extension of the previous
559 | one when arguments cannot be checked without performing a part of the computation. For example, consider the case
560 | of TreeMap, whose elements are sorted according to some ordering. In order to add an element to a TreeMap, the
561 | element must be of a type that can be compared using the TreeMap’s ordering. Attempting to add an incorrectly typed
562 | element will naturally fail with a ClassCastException as a result of searching for the element in the tree, before
563 | the tree has been modified in any way.
564 |
565 | 3. A third approach to achieving failure atomicity is to perform the operation on a temporary copy of the object and
566 | to replace the contents of the object with the temporary copy once the operation is complete. This approach occurs
567 | naturally when the computation can be performed more quickly once the data has been stored in a temporary data
568 | structure. For example, some sorting functions copy their input list into an array prior to sorting to reduce the cost
569 | of accessing elements in the inner loop of the sort. This is done for performance, but as an added benefit, it
570 | ensures that the input list will be untouched if the sort fails.
571 |
572 | 4. A last and far less common approach to achieving failure atomicity is to write recovery code that intercepts a
573 | failure that occurs in the midst of an operation, and causes the object to roll back its state to the point before
574 | the operation began. This approach is used mainly for durable (disk-based) data structures.
575 |
576 | While failure atomicity is generally desirable, it is not always achievable. For example, if two threads attempt
577 | to modify the same object concurrently without proper synchronization, the object may be left in an inconsistent
578 | state. It would therefore be wrong to assume that an object was still usable after catching a
579 | ConcurrentModificationException. Errors are unrecoverable, so you need not even attempt to preserve failure atomicity
580 | when throwing AssertionError.
581 | {Aaron notes: Above is an important design.}
582 |
583 | Even where failure atomicity is possible, it is not always desirable. For some operations, it would significantly
584 | increase the cost or complexity. That said, it is often both free and easy to achieve failure atomicity once you’re
585 | aware of the issue.
586 | {Aaron notes: Above is an important design.}
587 |
588 | ### In summary, as a rule, any generated exception that is part of a method’s specification should leave the object in the same state it was in prior to the method invocation. Where this rule is violated, the API documentation should clearly indicate what state the object will be left in. Unfortunately, plenty of existing API documentation fails to live up to this ideal.
589 | {Aaron notes: Above is an important design.}
590 |
591 | ## ITEM 77: DON’T IGNORE EXCEPTIONS
592 | While this advice may seem obvious, it is violated often enough that it bears repeating. When the designers of an API
593 | declare a method to throw an exception, they are trying to tell you something. Don’t ignore it! It is easy to ignore
594 | exceptions by surrounding a method invocation with a try statement whose catch block is empty:
595 |
596 | ```aidl
597 | // Empty catch block ignores exception - Highly suspect!
598 | try {
599 | ...
600 |
601 | } catch (SomeException e) {
602 |
603 | }
604 | ```
605 |
606 | An empty catch block defeats the purpose of exceptions, which is to force you to handle exceptional conditions.
607 | Ignoring an exception is analogous to ignoring a fire alarm—and turning it off so no one else gets a chance to see if
608 | there’s a real fire. You may get away with it, or the results may be disastrous. Whenever you see an empty catch block,
609 | alarm bells should go off in your head.
610 | {Aaron notes: Above is an important design.}
611 |
612 | There are situations where it is appropriate to ignore an exception. For example, it might be appropriate when closing
613 | a FileInputStream. You haven’t changed the state of the file, so there’s no need to perform any recovery action, and
614 | you’ve already read the information that you need from the file, so there’s no reason to abort the operation in
615 | progress. It may be wise to log the exception, so that you can investigate the matter if these exceptions happen often.
616 | If you choose to ignore an exception, the catch block should contain a comment explaining why it is appropriate to do
617 | so, and the variable should be named ignored:
618 |
619 | ```aidl
620 | Future f = exec.submit(planarMap::chromaticNumber);
621 | int numColors = 4; // Default; guaranteed sufficient for any map
622 |
623 | try {
624 | numColors = f.get(1L, TimeUnit.SECONDS);
625 | } catch (TimeoutException | ExecutionException ignored) {
626 | // Use default: minimal coloring is desirable, not required
627 | }
628 | ```
629 |
630 | ### In summary, the advice in this item applies equally to checked and unchecked exceptions. Whether an exception represents a predictable exceptional condition or a programming error, ignoring it with an empty catch block will result in a program that continues silently in the face of error. The program might then fail at an arbitrary time in the future, at a point in the code that bears no apparent relation to the source of the problem. Properly handling an exception can avert failure entirely. Merely letting an exception propagate outward can at least cause the program to fail swiftly, preserving information to aid in debugging the failure.
631 |
--------------------------------------------------------------------------------
/src/chapter12_Serialization/Serialization.md:
--------------------------------------------------------------------------------
1 | # Chapter 12. Serialization
2 |
3 | THIS chapter concerns object serialization, which is Java’s framework for encoding objects as byte streams (serializing)
4 | and reconstructing objects from their encodings (deserializing). Once an object has been serialized, its encoding can
5 | be sent from one VM to another or stored on disk for later deserialization. This chapter focuses on the dangers of
6 | serialization and how to minimize them.
7 |
8 | ## ITEM 85: PREFER ALTERNATIVES TO JAVA SERIALIZATION
9 |
10 | When serialization was added to Java in 1997, it was known to be somewhat risky. The approach had been tried in a
11 | research language (Modula-3) but never in a production language. While the promise of distributed objects with little
12 | effort on the part of the programmer was appealing, the price was invisible constructors and blurred lines between
13 | API and implementation, with the potential for problems with correctness, performance, security, and maintenance.
14 | Proponents believed the benefits outweighed the risks, but history has shown otherwise.
15 |
16 | The security issues described in previous editions of this book turned out to be every bit as serious as some
17 | had feared. The vulnerabilities discussed in the early 2000s were transformed into serious exploits over the next
18 | decade, famously including a ransomware attack on the San Francisco Metropolitan Transit Agency Municipal Railway
19 | (SFMTA Muni) that shut down the entire fare collection system for two days in November 2016 [Gallagher16].
20 |
21 | A fundamental problem with serialization is that its attack surface is too big to protect, and constantly
22 | growing: Object graphs are deserialized by invoking the readObject method on an ObjectInputStream. This method
23 | is essentially a magic constructor that can be made to instantiate objects of almost any type on the class path, so
24 | long as the type implements the Serializable interface. In the process of deserializing a byte stream, this method
25 | can execute code from any of these types, so the code for all of these types is part of the attack surface.
26 |
27 | The attack surface includes classes in the Java platform libraries, in third-party libraries such as Apache Commons
28 | Collections, and in the application itself. Even if you adhere to all of the relevant best practices and succeed in
29 | writing serializable classes that are invulnerable to attack, your application may still be vulnerable. To quote
30 | Robert Seacord, technical manager of the CERT Coordination Center:
31 |
32 | Java deserialization is a clear and present danger as it is widely used both directly by applications and indirectly
33 | by Java subsystems such as RMI (Remote Method Invocation), JMX (Java Management Extension), and JMS
34 | (Java Messaging System). Deserialization of untrusted streams can result in remote code execution (RCE),
35 | denial-of-service (DoS), and a range of other exploits. Applications can be vulnerable to these attacks even if they
36 | did nothing wrong. [Seacord17]
37 | {Aaron notes: Above is an important design.}
38 |
39 | Attackers and security researchers study the serializable types in the Java libraries and in commonly used third-party
40 | libraries, looking for methods invoked during deserialization that perform potentially dangerous activities. Such
41 | methods are known as gadgets. Multiple gadgets can be used in concert, to form a gadget chain. From time to time, a
42 | gadget chain is discovered that is sufficiently powerful to allow an attacker to execute arbitrary native code on
43 | the underlying hardware, given only the opportunity to submit a carefully crafted byte stream for deserialization. This
44 | is exactly what happened in the SFMTA Muni attack. This attack was not isolated. There have been others, and there
45 | will be more.
46 | {Aaron notes: Above is an important design.}
47 |
48 | Without using any gadgets, you can easily mount a denial-of-service attack by causing the deserialization of a short
49 | stream that requires a long time to deserialize. Such streams are known as deserialization bombs [Svoboda16]. Here’s an
50 | example by Wouter Coekaerts that uses only hash sets and a string [Coekaerts15]:
51 |
52 | ```aidl
53 | // Deserialization bomb - deserializing this stream takes forever
54 | static byte[] bomb() {
55 |
56 | Set