├── LICENSE ├── README.md └── _config.yml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Erik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Effective Java - 3rd Edition Notes 2 | 3 | ### Chapter Index 4 | - [ ] 02 - Creating and Destroying Objects 5 | - [ ] 03 - Methods Common to All Objects 6 | - [ ] 04 - Classes and Interfaces 7 | - [ ] 05 - Generics 8 | - [ ] 06 - Enums and Annotations 9 | - [ ] 07 - Lambdas and Streams 10 | - [ ] 08 - Methods 11 | - [ ] 09 - General Programming 12 | - [ ] 10 - Exceptions 13 | - [ ] 11 - Concurrency 14 | - [ ] 12 - Serialization 15 | 16 | ### Chapter 02 - Creating and Destroying Objects 17 | 18 | #### Item 1 - Consider static factory methods instead of constructors 19 | - traditional vs. flexible way of object instantiation 20 | - example of static factory method: 21 | ```java 22 | public static Boolean valueOf(boolean b) { 23 | return b ? Boolean.TRUE : Boolean.FALSE; 24 | } 25 | ``` 26 | ##### Advantages and disadvantages: 27 | - (PRO) static factories have names, unlike constructors 28 | - (PRO) static factories are not required to create a new object on each invocation 29 | - such classes are called _instance controlled_ 30 | - enable singleton (Item 2) and non-instantiability (Item 3) guarantees 31 | - allows immutable value class to guarantee no two instances exist 32 | - forms the basis of [Flyweight](https://en.wikipedia.org/wiki/Flyweight_pattern#Example_in_Java) Pattern 33 | - Enum types provide this guarantee 34 | - (PRO) static methods can return an object of any subtype of their return type, unlike constructors 35 | - this can lead to compact APIs 36 | - lends itself to _interface-based frameworks_ (Item 20) 37 | - companion classes mostly obviated in Java 8 38 | - default methods 39 | - still some limitations which are dealt with in Java 9+ 40 | - (PRO) static factories allow the class of the returned object to vary from call to call as function of input params 41 | - example: ```EnumSet``` 42 | - backed by a ```long``` - ```RegularEnumSet``` 43 | - backed by a ```long[]``` - ```JumboEnumSet``` 44 | - (PRO) static factories do not require the class of returned object to exist when the class containing the method is written 45 | - form the basis of _service provider frameworks_ 46 | - example: JDBC 47 | - variants: 48 | - dependency-injection frameworks (i.e. Spring, Guice) 49 | - [Bridge](https://en.wikipedia.org/wiki/Bridge_pattern#Java) Pattern 50 | - (CON) classes without public/protected constructors cannot be subclassed 51 | - a blessing in disguise 52 | - encourages composition over inheritance 53 | - (CON) hard to find in documentation 54 | - current JavaDoc limitations 55 | 56 | ##### Some common names for static factory methods 57 | - ```from()``` 58 | - ```of()``` 59 | - ```valueOf()``` 60 | - ```instance()``` or ```getInstance()``` 61 | - ```getType()``` 62 | - ```newType()``` 63 | - ```type()``` 64 | 65 | ##### Conclusion 66 | Avoid the reflex to provide a public constructor and consider static methods/factories. 67 | 68 | #### Item 2 - Consider a builder when faced with many constructor params 69 | - static factories and constructors share a limitation: they scale poorly with the increase of (optional) params 70 | - traditional ways of dealing with this: 71 | - _telescoping constructor_ 72 | - also scales poorly: hard to write with many params and even harder to read 73 | - _JavaBeans_ pattern 74 | - allows inconsistency 75 | - precludes immutability (Item 17) 76 | - a better way: [Builder](https://en.wikipedia.org/wiki/Builder_pattern#Java) pattern 77 | - typically a static member class (Item 24) 78 | - the client code is easy to write and, more importantly, easy to read 79 | - easy to incorporate validity checks 80 | - check on object fields after copying params from the builder (Item 50) 81 | - failing check will throw an ```IllegalArgumentException``` (Item 72) with exception details (Item 75) 82 | - well suited to class hierarchies 83 | - generic builder with recursive type parameters (Item 30) can construct any subclass 84 | - abstract ```self()``` simulates self-type which, combined with covariant return typing, obviates need for casting 85 | - flexible 86 | - disadvantages: 87 | - cost of creating a builder 88 | - more verbose than a telescoping constructor 89 | - conclusion: 90 | - almost always start with a builder in the first place 91 | - especially so if we have more than a handful params 92 | - client code much easier to read and write than telescoping constructors 93 | - builder are much safer than JavaBeans 94 | 95 | #### Item 3 - Enforce the singleton property when a private constructor or enum type 96 | - _singleton_ is a class that is instantiated exactly once 97 | - making a class a singleton can make it difficult to test 98 | - three common ways of implementing it: 99 | - with ```public final``` field 100 | - with static factory 101 | - with a single-element enum (preferred) 102 | - conclusion: 103 | - if a singleton is indeed warranted, create it as a single-element enum 104 | - well-defended against reflection 105 | - solves serialization problems 106 | 107 | #### Item 4 - Enforce non-instantiability with a private constructor 108 | - occasionally, we want to write a class that is simply a grouping of static methods and static fields 109 | - such _utility classes_ have acquired a bad reputation due to their abuse in avoiding thinking in terms of objects but they have valid uses: 110 | - group related methods on primitive values or arrays 111 | - examples: ```java.util.Math``` or ```java.util.Arrays``` 112 | - group static methods, including factories (Item 1) 113 | - default methods are also available (providing we own the interface) 114 | - group methods on a final class, since we can't put them in a subclass 115 | - make such classes non-instantiable 116 | - provide an explanatory comment 117 | - throw an ```AssertionError``` from constructor instead of empty one, to guard against accidental constructions from within the class 118 | - as a side-effect, this class is now effectively final 119 | - the class cannot be subclassed as there are no available constructors 120 | - still, it is good to document this a make the class itself ```final``` 121 | 122 | #### Item 5 - Prefer dependency injection to hard-wiring resources 123 | - do not use static utility methods or singletons to handle creations of class' resources 124 | - these yield inflexible and untestable classes 125 | - favour dependency injection by supplying the required resource parametrically 126 | - we inject (pass) the dependency (resource) into the class that requires it 127 | - testable 128 | - flexible (esp. with [Factory Method](https://en.wikipedia.org/wiki/Factory_method_pattern#Java) pattern) 129 | - ```Supplier``` is perfectly suited for representing factories 130 | - methods that take this interface should typically constrain the factory's type parameter with a bounded wildcard type (Item 31) 131 | - the client should be able to pass in a factory that requires any subtype of a specified type 132 | - the manual dependency injection can be automatised with frameworks 133 | 134 | #### Item 6 - Avoid creating unnecessary objects 135 | - creating unnecessary objects can be avoided by using static factory methods (Item 1) 136 | - some object creations are much more expensive than others 137 | - it may be advisable to cache such objects 138 | - example: regex matching 139 | - immutable objects can trivially be reused 140 | - other examples are [Adapter](https://en.wikipedia.org/wiki/Adapter_pattern#Java)s (a.k.a. _views_) 141 | - adapter is an object delegating to a backing object, providing an alternative interface 142 | - has not state beyond the backing object thus provides a view of it 143 | - example: ```keySet()``` in ```Map``` interface 144 | - autoboxing can often subtly create unnecessary objects 145 | - almost never create own _object pools_ 146 | - JVM gc will almost always outperform such pools 147 | - exception to this: very expensive objects 148 | - example: database connection objects 149 | - counterpoint to this is _defencive copying_ (Item 50) 150 | 151 | #### Item 7 - Eliminate obsolete object references 152 | - when relying on automatic gc, be wary of leaks 153 | - example: a resizing-array stack that doesn't null out its references on ```pop()``` 154 | - common sources of leaks 155 | - classes that manage their own memory 156 | - caches 157 | - can be mitigated with ```WeakHashMap``` 158 | - sophisticated caches might need to use ```java.lang.ref``` directly 159 | - listeners and other callbacks 160 | - APIs that register callbacks but don't deregister them explicitly 161 | - can be mitigated with ```WeakHashMap``` 162 | - conclusion: it very desirable to learn to anticipate such problems before they occur as they can be very costly to fix 163 | 164 | #### Item 8 - Avoid finalizers and cleaners 165 | - _finalizers_ and _cleaners_ are used to reclaim non-memory resources 166 | - example: input/output streams, files, etc. 167 | - they are not analogues of C++ destructors 168 | - finalizers are unpredictable, dangerous and generally unnecessary 169 | - cleaners are less dangerous than finalizers but still slow, unpredicatble and generally unnecessary 170 | - disadvantages: 171 | - spec makes no guarantee when they'll be executed 172 | - their execution is a function of GC algorithm, thus JVM implementation 173 | - never do anything time-critical in a finalizer or cleaner 174 | - providing a finalizer may arbitrarily delay reclamation of class' instances 175 | - cleaners are a bit better but still run under the control of GC so still the same applies 176 | - any existing methods that _claim_ to trigger finalization are decade-old traps 177 | - examples: ```System.runFinalizerOnExit``` or ```Runtim.runFinalizerOnExit``` 178 | - uncaught exception thrown during finalization is ignored and finalization of that object terminates 179 | - object is potentially left in corrupted state 180 | - normally, uncaught exception terminates the executing thread and dumps stacktrace but not if it occurs in finalizer 181 | - cleaners do not suffer from this problem 182 | - there is a _severe_ performance GC penalty for using finalizers and cleaners 183 | - finalizers: ~50x slower reclamation 184 | - cleaners: ~5x slower reclamation, equal to finalizers if they're used to clean all instance of the class 185 | - finalizers open up classes to finalizer attacks 186 | - if an exception is thrown during finalization, the finalizer leaves the class unreclaimed 187 | - attackers can exploit this and run code that shouldnt've existed 188 | - to protect non-final classes against it - write a ```final finalize()``` that does nothing 189 | - instead of using finalizers or classes simply use ```AutoCloseable``` 190 | - require clients to invoke ```close()``` whenever instance is not required 191 | - legitimate uses: 192 | - act as a safety net for closeables 193 | - think long and hard before doing so 194 | - reclaim native peer objects 195 | - conclusion: don't use cleaners, or in releases prior to Java 9, finalizers - except as a safety net or to terminate non-critical native resources. Even then, beware the indeterminacy and performance consequences 196 | 197 | #### Item 9 - Prefer ```try-with-resources``` to ```try-finally``` 198 | - Java libraries include many resources that must be closed manually by invoking ```close()``` 199 | - examples: ```InputStream```, ```OutputStream```, ```java.sql.Connection```, etc. 200 | - closing objects is often overlooked by clients 201 | - many use finalizers as safety net, with dire performance consequences (Item 8) 202 | - historically, ```try-finally``` was the best way to guarantee a resource would be closed properly, even when facing exception or return 203 | - while it doesn't look bad for a single resource, it doesn't scale well with the increase of resources required to be closed 204 | - nested ```try-finally``` blocks stick out like a sore thumb 205 | - it's tricky to get it right, even in JDK 206 | - nested ```finally``` block complicate debugging 207 | - ```try-with-resources``` suffers none of this issues 208 | - example: 209 | ```java 210 | // try-with-resources on multiple resources - short and sweet 211 | static void copy(String src, String dst) throws IOException { 212 | try (InputStream in = new FileInputStream(src); 213 | OutputStream out = new FileOutputStream(dst)) { 214 | byte[] buf = new byte[BUFFER_SIZE]; 215 | int n; 216 | while ((n = in.read(buf)) >= 0) 217 | out.write(buf, 0, n); 218 | } 219 | } catch (IOException e) { 220 | // do something here 221 | } 222 | ``` 223 | - shorter, more readable than ```try-finally``` 224 | - provides far better diagnostics 225 | - no exceptions are suppressed 226 | - conclusion: always use ```try-with-resources``` when working with resources that must be closed 227 | 228 | ### Chapter 03 - Methods Common to All Objects 229 | 230 | #### Item 10 - Obey the general contract when overriding ```equals()``` 231 | - overriding the ```equals()``` seems simple but there are many pitfalls and consequences can be dire 232 | - easiest way to avoid problems is not override the method at all 233 | - then, we fall back to object identity only - each object is equal only to itself 234 | - do *not* override the method if: 235 | - each instance of the class is inherently unique 236 | - example: ```java.util.thread.Thread``` 237 | - there is no need for the class to provide 'logical equality' test 238 | - example: ```java.util.regex.Pattern``` 239 | - superclass is already overriding ```equals()``` and superclass' behaviour is appropriate for the subclass 240 | - example: most root classes from ```java.util.collection``` and subclasses of ```java.util.Map``` inherit ```equals()``` behaviour from their abstract implementations 241 | - the class is (package-)private and we're certain ```equals()``` will never be invoked 242 | - the risk-averse may throw an exception in the subclass if ```equals()``` is called 243 | - the class is *instance controlled* (Item 1) 244 | - example: enum types 245 | - *do* override the method if a class has a notion of **logical equality** that differs from mere object identity 246 | - this is generally the case for *value classes* 247 | - examples: ```java.util.Integer``` or ```java.util.String``` 248 | - overriding the ```equals()``` implies adhering to its general contract of *equivalence relation*: 249 | - (*reflexivity*) ```x.equals(x) == true```, for x != null 250 | - hard to violate unintentionally 251 | - (*symmetry*) ```x.equals(y) == y.equals(x)```, for x, y != null 252 | - example: compare ordinary and case insensitive strings 253 | - (*transitivity*) ```x.equals(y) == y.equals(z) == x.equals(z)```, for x, y, z != null 254 | - examples: subclass adds a new value component; ```java.util.Date``` and ```java.util.Timestamp``` 255 | - easier to violate when using inheritance 256 | - once this property is violated, subsequent fixes are likely to violate other properties 257 | - fundamental problem of equivalence relations in OO languages => there is no way to extend an instantiable class and add a value component whilst preserving the relation! 258 | - workaround: favour composition over inheritance 259 | - (*consistency*) ```x.equals(y) == x.equals(y)```, for x, y != null 260 | - example: 'java.util.URL' 261 | - do not write ```equals()``` that depend on unreliable resources 262 | - (*non-nullity*) ```x.equals(null) == false```, for x != null 263 | - hard to violate unintenionally, unless an exception is thrown instead of returning ```false``` 264 | - violation of this contract means it is **uncertain how other objects will behave when confronted with our object** 265 | - conclusions: 266 | - rely on IDEs to generate the ```equals()``` 267 | - if manual tuning is really necessary, pay attention to equivalence relation violation (write tests!) and performance 268 | 269 | #### Item 11 - Always override ```hashCode()``` when overriding ```equals()``` 270 | - violating this rule will violate the general contract for ```hashCode()``` 271 | - it prevents proper functioning of hash-based collections 272 | - general ```hashCode()``` contract: 273 | - (*consistency*) ```x.hashCode() == x.hashCode()```, for x != null 274 | - (*equality*) ```x.equals(y) => (x.hashCode() == y.hashCode())```, for x, y != null 275 | - worst possible hash-code implementation is returning the same number 276 | - degrades performance horrifically 277 | - conclusions: 278 | - it is mandatory to override ```hashCode()``` each time ```equals()``` is overridden 279 | - failure to do so precludes correct functioning of the program (fallback on Object) 280 | - obey the general ```hashCode()``` contract 281 | - rely on the ```Object.hashCode(...)``` to compute the hash-code unless performance is very important 282 | 283 | #### Item 12 - Always override ```toString()``` 284 | - makes systems using the class easier to debug 285 | - disadvantage: once specified, it's for-life 286 | - clearly document intentions 287 | - don't override ```toString()``` on 288 | - static utility class (Item 4) 289 | - enum types (Item 34) 290 | - rely on IDE to create a good ```toString()``` implementation 291 | 292 | #### Item 13 - Override ```clone()``` judiciously 293 | - conclusions: 294 | - do not use ```clone()``` 295 | - use static factory to copy objects whenever possible 296 | 297 | #### Item 14 - Consider implementing ```Comparable``` 298 | - isn't inherited from ```Object``` type 299 | - located in functional interface ```Comparable``` 300 | - similar to ```equals()``` except it permits order comparisons in addition to simple equality comparisons 301 | - implementing ```Comparable```, class indicates its instances follow *natural ordering* 302 | - it also makes it easy to apply various searching, sorting and extreme values computations on such a class 303 | - example: ```java.util.String``` 304 | - class automatically interoperates with a variety of generic algorithms and collection implementations 305 | - small effort and code footprint to leverage existing (vast) capabilites 306 | - general contract of ```compareTo()``` is very similar to ```equals```: 307 | - (*reflexivity*) ```(x.compareTo(y) == 0) => (sgn(x.compareTo(z) == sgn(y.compareTo(z))```, for x, y, z != null 308 | - (*symmetry*) ```sgn(x.compareTo(y)) == -sgn(y.compareTo(x))```, for x, y != null 309 | - helps imposing total order 310 | - (*transitivity*) ```(x.compareTo(y) && y.compareTo(z)) > 0 => (x.compareTo(z)) > 0```, for x, y, z != null 311 | - helps imposing total order 312 | - (*optional consistency with equals*) ```(x.compareTo(y) == 0) <=> (x.equals(y))```, for x, y != null 313 | - if violated, still will yield valid comparisons but will generally not guarantee obeying the general contract for collections and maps 314 | - examples: ```java.util.BigDecimal``` in ```HashSet``` and ```TreeSet``` 315 | - to compare object ref fields, invoke ```compareTo()``` recursively 316 | - do not use relational operators in ```compareTo()``` 317 | - use ```compare()``` on boxed primitive types 318 | - alternately, use comparator fluent construction methods in ```Comparator``` interface 319 | - do not use hashCode arithmetics-based comparisons 320 | - though somewhat more performant, they are fraught with danger from integer overflow and FP arithmetic artifacts 321 | - use the same techniques as in the bullet point above 322 | - generally, same limitations and workarounds as for the ```equals()``` apply here 323 | - exceptions may be thrown, however, without violating the contract 324 | - conclusions: 325 | - whenever a value class has sensible ordering, ```Comparable``` should be implemented 326 | - easy sorting, searching and usage in comparison-based collections 327 | - do not use relational comparison operators to determine the result of comparing two elements 328 | - rely on static ```compare()``` in the boxed primitive types 329 | - alternately, use comparator construction methods in ```Comparator``` interface 330 | 331 | ### Chapter 04 - Classes and Interfaces 332 | 333 | #### Item 15 - Minimise the accesibility of classes and members 334 | - well-designed components: 335 | - hide their internal data and other implementation details from other components 336 | - thus, they cleanly separate their API from its implementation 337 | - components are then oblivios to each other's workings 338 | - this is *encapsulation* (information hiding) -> a fundamental tenet of software design 339 | - importance of encapsulation: 340 | - *decouples* the components comprising a system 341 | - this allows for development/optimisation/usage/reasoning/modification *in isolation* 342 | - speeds up development (parallelisation) 343 | - reduces maintenance costs (easier reasoning/debugging/replacement) 344 | - makes for effective performance tuning (isolation -> does not influence correctness of others) 345 | - increases reuse (decoupled components usually provide use in contexts beyond original design) 346 | - de-risks development (individual components may prove successful even if the system does not) 347 | - Java encapsulation facilities: 348 | - access control mechanism (```private```, ```protected```, ```public``` keywords + default access) 349 | - encapsulation rule of thumb: *make each class/member as inaccessible as possible* 350 | - after carefully designing a class' public API, the reflex should be to *make all other members private* 351 | - change design if you find yourself opening up the API too frequently 352 | - there may be a better decomposition with higher decoupling 353 | - some fields may leak into the exported API if the class implements ```Serializable``` interface 354 | - huge increase in visibility when going from default to ```protected``` 355 | - becomes a part of exported API (has to be supported forever) 356 | - should be relatively rare 357 | - overridden methods cannot have restrictive access level in the subclass than it is in the superclass 358 | - fields a compile-time error 359 | - a consequence of *Liskov substition principle* 360 | - special rule -> if a class implements an interface, all implemented methods *must* be public 361 | - opening up a class to facilitate testing is acceptable (to a degree) 362 | - the less restrictive access must not be any higher than *default* access 363 | - it is fine to make the code "worse" in order to cover it with tests (M. Feathers, "Working Effectively With Legacy Code") 364 | - instance fields of public classes should rarely be public 365 | - gives up : 366 | - the ability to enforce invariants on the field 367 | - the flexibility to change data structure 368 | - not thread-safe 369 | - same applies for ```static``` fields, except if they are also ```final``` 370 | - exception: it's always wrong to expose a mutable data structure as ```public static final``` (e.g. Arrays, Lists...) 371 | - for such instances make an accessor which defencively copies the data structure and make the field ```private``` 372 | - Java 9 modules: 373 | - module is a *group of packages*, much like a pakcage is group of classes 374 | - it may explicitly *export* some of its packages (via export declarations in its module declaration ```module-info.java```) 375 | - public/protected members of unexported packages in a module are inaccessible outside the module 376 | - within, they work as before 377 | - using the module system allows us to share classes among packages within a module without making them visible to the entire world 378 | - the need for this kind of sharing is relatively rar and can often be eliminated by rearranging classes within a package 379 | - it is unclear if it will achieve widespread use outside of the JDK itself (where it's strictly enforced) 380 | - summary: 381 | - reduce accebility of program elements as much as possible 382 | - do not expose mutable types as ```public static final``` fields 383 | 384 | #### Item 16 - Favour accessors over public fields in public classes 385 | 386 | - occasionaly, degenerate classes are rolled out such as this one: 387 | ```java 388 | class Point { 389 | public double x; 390 | public double y 391 | } 392 | ``` 393 | - if confined to package-private or private access modifier, they can be very useful in reducing visual clutter and overhead 394 | - making them more accessible would be dangerous and is not advised 395 | - there are examples in JDK that violate this rule (```java.awt.Point```, ```java.awt.Dimension```) 396 | 397 | #### Item 17 - Minimise mutability 398 | 399 | - immutable classes are classes whose instances cannot be modified 400 | - all of the data in the object is fixed for the lifetime of the object 401 | - e.g. ```java.lang.String```, the boxed primitive classes, ```BigInteger``` and ```BigDecimal``` 402 | - many reasons to use immutable classes -> easier to design, implement and use than mutable classes 403 | - to make a class immutable, follow these 5 rules: 404 | - don't provide mutators 405 | - ensure that the class cannot be extended 406 | - make all fields final 407 | - make all fields private 408 | - ensure exclusive access to any mutable components 409 | - immutable classes are easier to realise using *functional*, rather than *imperative* approach 410 | - immutable objects are *simple* 411 | - has always exactly *one* state - the state in which it was created 412 | - they are easier to use reliably 413 | - immutable object are inherently *thread-safe* (they require no synchronisation) 414 | - thus can be shared freely, promoting reuse 415 | - no defencive copies necessary 416 | - their internals can be shared freely 417 | - immutable objects make great building blocks for other objects 418 | - they also make great map keys or set elements 419 | - immutable object provide atomicity for free 420 | - the one disadvantage -> they require a separate object for each distinct value 421 | - the problem is exacerbated if the object is a part of multistep transformation 422 | - one way to solve this issue is by providing mutable 'companion classes' 423 | - no method may produce an *externally visible* change in the object's state 424 | - consider using *lazy initialisation* technique 425 | - summary: 426 | - classes should be immutable unless there is a very good reason to make them mutable 427 | - if a class cannot be made immutable, limit its mutability as much as possible 428 | - declare every field ```private final``` unless there is a good reason to do so otherwise 429 | - constructors should create fully initialised objects with all their invariants established 430 | - e.g. ```CountDownLatch``` 431 | 432 | #### Item 18 - Favour composition over inheritance 433 | 434 | - this chapter applies to *implementation* inheritance, not *interface* inheritance 435 | - inheritance is a powerful way to achieve code reuse 436 | - can lead to fragile software if employed inappropriately 437 | - safe to use: 438 | - within a package (where sub- and super-class are under control of the same programmers) 439 | - if a class specifically is designed and documented for inheritance 440 | - inheritance violates encapsulation 441 | - subclass depends on implementation details of the superclass 442 | - both must evolve in tandem 443 | - e.g. ```HashSet``` extension 444 | - depending on superclass' method to implement your own can lead to fragility - as the superclass evolves, your code may break without any changes 445 | - related cause of fragility is that their superclass can acquire new methods in subsequent releases 446 | - e.g. ```Hashtable``` and ```Vector``` classes had to had their security holes fixed before being retrofitted to participate in Collections framework 447 | - solution to these issues is the application of *composition* 448 | - existing class becomes a component of the new one 449 | - new class is free to *forward* calls to the old class where appropriate (*forwarding methods*) 450 | - resulting classes are then rock solid: 451 | - they don't depend on the implementation details of the existing class 452 | - the forwarder-wrapper pattern is also known as the [Decorator](https://en.wikipedia.org/wiki/Decorator_pattern#Java) pattern 453 | - this combination of composition and forwarding is also informally defined as *delegation* 454 | - disadvantages of wrapper classes are few: 455 | - not suited for use in callback frameworks (callbacks elude the wrapper - SELF problem) 456 | - theoretical performance and memory impacts 457 | - tedious to write forwarding classes 458 | - inheritance is only appropriate for classes that pass the "is-a" test 459 | - answer truthfully to question "If B extended A, is B really an A?" 460 | - a number of obvious violations in JDK 461 | - ```Stack``` extends ```Vector``` 462 | - ```Properties``` extends ```Hashtable``` 463 | - does the class contemplated to extends has any flaws in its API? 464 | - summary: 465 | - inheritance is powerful but problematic as it violates encapsulation 466 | - appropriate *only* when a genuine subtype relationship exists between the sub- and super-class 467 | - inheritance may lead to fragility 468 | - use composition and forwarding instead to avoid this fragility 469 | - wrapper classes are more robust and powerful than subclasses 470 | 471 | #### Item 19 - Design and document for inheritance or else prohibit it 472 | - what does it mean to design/document for inheritance? 473 | - the class must document its self-use of overridable methods 474 | - this is one special case where it's ok to document implementation detail (unfortunate side-effect of inheritance violating encapsulation) 475 | - the class may have to provide hooks into its internal workings 476 | - careful choosing of protected methods 477 | - enables programmers to write efficient subclasses without undue pain 478 | - the only way to test a class designed for inheritance is to write subclasses 479 | - test before releasing the class 480 | - constructors *must not* invoke overridable methods (directly or indirectly) 481 | - safe to invoke private/final/static methods, none of which are overridable 482 | - ```Cloneable``` or ```Serializable``` interfaces are especially difficult to design for inheritance 483 | - use neither in such classes 484 | - designing a class for inheritance requires great effort and places substantial limitations on the class 485 | - occasionaly, it is clearly the right thing to do (e.g. abstract classes, interfaces or skeletal implementations) 486 | - the opposite also holds (e.g. immutable classes) 487 | - best approach is to prohibit subclassing in classes that are not designed and documented for safe subclassing 488 | - prohibit inheritance on classes implementing an interface that captures its essence 489 | - for other classes, ensure at least that the class never invokes any of its overridable methods and document this 490 | - summary: 491 | - designing a class for inheritance is hard 492 | - document all self-use patterns 493 | - export one or more protected methods 494 | - strongly consider prohibiting inheritance altogether 495 | 496 | #### Item 20 - Prefer interfaces to abstract classes 497 | 498 | - two mechanisms to define a type that permits multiple implementations: interfaces and abstract classes 499 | - existing classes can easily be retrofitted to implement a new interface 500 | - they cannot, in general, be retrofitted with a new abstract class without doing collateral damage to the type hierarchy 501 | - interfaces are ideal for defining *mixins* 502 | - a mixin is a type thtat a class implements additionally to its 'primary type' 503 | - e.g. ```Comparable``` 504 | - abstract classes cannot be used to define mixins 505 | - interfaces allow for the construction of non-hierarchical type frameworks 506 | - they can prevent *combinatorial explosion* produced by abstract classes 507 | - interfaces enable safe, powerful functionality enhancements 508 | - wrapper class idiom 509 | 510 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate --------------------------------------------------------------------------------