Effective Java

  1. Introduction
    • most of the rules derive from a few fundamental principles
      • clarity and simplicity are of paramount importance
      • user should not be surprised by component behavior
      • code should be reused rather than copied
      • dependencies between components should be kept to a minimum
      • errors should be detected as soon as possible
    • for the most part, this book is not about performance
  2. Creating and Destroying Objects
    • Item 1: Consider static factory methods instead of constructors
      • pros
        • they have names
        • not required to create a new object each time they’re invoked (e.g. for immutable classes, singletons)
        • they can return an object of any subtype
          • clients can focus on API of interface
        • class of returned object can vary from call to call based on input parameters
        • class of returned object need not exist when the class containing the method is written
      • cons
        • classes without public or protected constructors cannot be subclassed
          • good since it encourages composition
          • required for immutable classes
        • static factory methods may be hard to find
          • draw attention to in documentation and adhere to common naming conventions
          • from, of, valueOf, instance, getInstance, create, newInstance, getType, newType, type
      • often preferable to public constructors
    • Item 2: Consider a builder when faced with many constructor parameters
      • steps
        • client calls a constructor or static factory with required parameters and gets a builder object
        • client calls setter-like methods for optional parameters
        • finally, use a parameterless build method to generate an object (typically immutable)
      • pros
        • simulates named optional parameters
        • check invariants
        • well suited for class hierarchies
          • abstract builders for abstract classes and concrete builders for concrete classes
      • cons
        • this may be an issue in performance-critical situations
        • more verbose and should be used when enough parameters (4+), but often add more so often better to start with a builder
      • The builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters
    • Item 3: Enforce the singleton property with a private constructor or an enum type
      • 1) field method: e.g. INSTANCE
        • clear and simpler
      • 2) static factory method: e.g. getInstance
        • advantages
          • can change your mind about being a singleton and keep API
          • can write a generic singleton factory
          • a method reference can be used as a supplier e.g. Elvis::instance
        • unless one of these advantages is relevant, use field
      • a privileged client could call private constructor reflectively if you need to protect, modify the constructor to throw an exception if it’s asked to create a second instance
      • to make serializable must declare all instance fields transient and provide a readResolve method otherwise new instance created when deserialized
      • 3) declare a single-element enum
        • provides serialization machinery for free
        • ironclad guarantee against multiple instantiations in the face of sophisticated serialization or reflection
      • a single-element enum type is often the best way to implement a singleton
        • can’t use this approach if your singleton must extend a superclass other than Enum
        • enums can implement an interface however
    • Item 4: Enforce noninstantiability with a private constructor
      • e.g. may want a grouping of static methods and static fields
      • include a private constructor
        • default is only generated if no constructor
      • can throw an AssertionError to prevent it from being called within the class
      • also prevents subclassing
    • Item 5: Prefer dependency injection in hardwiring resources
      • static utility classes and singletons are inappropriate for classes whose behavior is parameterized by an underlying resource
      • pass the resource into the constructor when creating a new instance
      • a useful variant is to pass a resource factory into the constructor
        • Supplier<T> interface (added in Java 8) is perfect for representing factories
        • constrain type parameter with bounded wildcard type
      • dependency injection adds clutter for large projects but can be addressed by using a dependency injection framework
    • Item 6: Avoid creating unnecessary objects
      • an object can always be reused if it is immutable or mutable (but won’t be modified)
      • can often avoid by using a static factory method
      • if you use a constructor a new object will be created
      • if you need an “expensive object” may be advisable to cache e.g. regex pattern
      • adapters are immutable so only need to create one to a given object
      • autoboxing may result in unnecessary object creation e.g. long and Long
        • prefer primitives to boxed primitives and watch out for unintentional autoboxing
      • you should generally avoid maintaining your own object pool unless objects are extremely heavyweight e.g. database connections
    • Item 7: Eliminate obsolete object references
      • whenever a class manages its own memory, the programmer should be alert for memory leaks e.g. stack
        • object references should be nulled out
      • caches
        • use WeakHashMap if entry is relevant exactly as long as there are references to its key outside of the cache
        • if the lifetime of entry is not well-defined can clean with a background thread or remove the oldest entry
      • listeners and other callbacks
        • registered callbacks can accumulate
        • can store as only keys in a WeakHashMap
      • often only discovered with careful code inspection or heap profiler so desireable to prevent them from happening
    • Item 8: Avoid finalizers and cleaners
      • no guarantees on when or if they will run
      • never do anything time-critical in a finalizer or cleaner
      • sever performance penalty
      • opens class up to attacks
        • protect by writing a final finalize method that does nothing
      • better to have your class implement AutoCloseable
      • legitimate uses
        • as a safety net
        • native peers (non-Java) objects the GC doesn’t know about assuming performance is acceptable
    • Item 9: Prefer try-with-resources to try-finally
      • using try-finally no longer the best way
        • nesting gets hairy and easy to make mistakes
        • exceptions in close may cover the initial exception and complicate debugging
      • always favor try-with-resources
        • the resources must implement AutoCloseable
        • shorter and more readable
        • exceptions thrown in closed are suppressed improving diagnostics
  3. Methods Common to All Objects
    • Item 10: Obey the general contract when overriding equals
      • the easiest way to avoid the problem is not to override
        • if each instance is inherently unique e.g. threads
        • there is no need to provide “logical equality” e.g. regex pattern
        • a superclass has already overridden equals and its appropriate for this class
        • class is private and you are certain it will never be invoked
          • can override and throw assertion to be extra safe
      • override when
        • logical equality differs from object equality and superclass has not already overridden e.g. value classes
        • enables instances to serve as map keys or set elements
      • equivalence relation contract for Object
        • reflexive
          • x.equals(x)
        • symmetric
          • x.equals(y) and y.equals(x)
        • transitive
          • x.equals(y)
          • y.equals((z)
          • x.equals(z)
        • consistent
          • x always equals y
        • non-nullity
          • if not null, x.equals(null) always returns false
      • many classes depend on equals e.g. collection classes
      • there is no way to extend an instantiable class and add a value component while preserving the equals contract (you can for abstract classes)
        • use composition, create a class that has the class as a private member
      • do not write equals that depend on unreliable resources
      • recipe for high equality equals
        • use the == operator to check if the argument is a reference to this object
        • use the instanceof operator to check if correct type
        • cast the argument to the correct type
        • check each significant field
          • == for primitive types (except float and double)
          • equals for mobjects
          • Float.compare, Double.compare for float and doubles
          • Array.equals
        • ask yourself if it is symmetric, transitive, consistent? and test
        • always override hashCode
        • don’t be too clever
        • don’t substitute another type or it won’t override
    • Item 11: Always override hashCode when you override equals
      • otherwise won’t function properly for HashMap or HashSet
      • must consistently return the same value if the object is not modified
      • two equal objects must return the same hash code
      • good hash function produces unequal hash codes for unequal instances
      • simple recipe
        • initialize int result with hash code of first significant field
        • combine hash codes using: result = 31 * result + c
        • write unit tests to verify
      • can use Objects.hash, but may not be most performant
      • can make it lazy if don’t expect to use a lot
      • do not exclude significant fields
      • do not provide any specifications for what value is returned so it can be changed
    • Item 12: Always override toString
      • concise but informative
      • makes it pleasant to use and easier for system debugging
      • if you fail to provide logs or test message is useless
      • should return all interesting information or a summary if too big
      • if you specify a format, clearly document and understand other people will depend on it
      • otherwise, clearly state it’s subject to change
      • provide accessors for relevant fields or else the string format becomes the API
      • override in every instantiable class you write, unless a superclass has already one so
    • Item 13: Override clone judiciously
      • a class implementing Cloneable needs to provide a properly functioning clone method
      • immutable classes should never provide a clone method
      • when designing a class for inheritance, the class should not implement Cloneable / let subclass decide if it wants to implement
      • clone method must be properly synchronized
      • if you clone you must:
        • override clone with a public method whose return type is the class itself
        • the method should first call super.clone
        • fix any fields that need fixing e.g. copying any mutable objects that comprise the internal “deep structure”
        • internal copies can usually be cloned recursively, but not always best (don’t need to if immutable or enums)
      • a better approach to object copying is to provide a copy constructor or copy factory
    • Item 14: Consider implementing Comparable
      • by implementing Comparable, allows your class to interoperate with many generic algorithms
      • contract: returns negative, zero, positive if object is less than, equal, r greater
      • provisions to compareTo
        • if you reverse the direction of comparison, expected thing happens
        • if one is greater than two and two is greater than three, one is greater than three
        • all objects that compare as equal must yield the same result when compared to any object object
      • must obey same restrictions imposed by equals: reflexivity, symmetry, and transitivity
      • can’t extend an instantiable class with a new value component while preserving compareTo contract so use composition
      • should generally return the same result as equals
      • recommended to NOT use relational operators like > or <
      • normal pattern to only allow comparison between the same types
      • Java 8 provides construction methods that can simplify
  4. Classes and Interfaces
    • Item 15: Minimize the accessibility of classes and members
      • the single most important factor that distinguishes well-designed components is the degree to which the component hides its internal data and other implementation details
      • this decouples the components of a system and increases software reuse
      • make each class or member as inaccessible as possible
      • anything you export you’re required to support to maintain compatibility
      • instance fields should rarely be public
      • ensure objects referenced by public static fields are immutable
    • Item 16: In public classes, use accessor methods, not public fields
      • breaks encapsulation
      • can’t change the representation without changing the API
      • if a class is package-private or a private nested class, there is nothing inherently wrong with exposing its data fields
      • less harmful if fields are immutable
    • Item 17: Minimize mutability
      • rules to ensure
        • don’t provide methods to modify object’s state
        • ensure that the class can’t be extended
        • make all fields final
        • make all fields private
        • if any fields refer to mutable objects, ensure clients cannot obtain a reference
      • they are simpler, thead-safe, and can be shared freely
      • classes should be immutable unless there is a good reason not to be
      • if class implements Serializable and contains one or more fields that refer to mutable objects, must provide an explicit readObject or readResolve mtehod or ObjectOutputStream.writeUnshared and ObjectInputStream.readUnshared
    • Item 18: Favor composition over inheritance
      • safe to use inheritance when extending classes specifically designed and documented for extension
      • inheritance violates encapsulation
      • composition with wrapper class or decorator pattern
    • Item 19: Design and document for inheritance or else prohibit it
      • the class must document its self-use of overridable methods
      • the class may have to provide hooks into its internal workings in the form of judiciously chosen protected methods
      • the only way to test a class designed for intheritance is to write subclasses
      • constructors must not invoke overridable methods because of fields may not be initialized
        • it is safe to invoke private methods, final methods and static methods, none of which are overridable from a constructor
      • designing a class for inheritance requires great effort and place substantial limitations on the class
      • the best solution is to prohibit subclassing in classes not designed and documented to be safely subcalssed
    • Item 20: Prefer interfaces to abstract classes
      • existing classes can easily be retrofitted to implement a new interface
      • can only extend one abstract calss
      • can combine advantages of interfaces and abstract classes by providing an abstract skeletal implementation class or AbstractInterfaces
        • create an abstract class that implements the interface
        • create a class that implements the interface and has an inner class that subclasses the abstract class
      • good documentation is absolutely essential in skeletal implementation
    • Item 21: Design interfaces for posterity
      • can add default methods in interfaces starting in Java 8
      • can’t always write default methods that maintain all invariants of every implementation
      • default methods may compile but can cause runtime errors
      • design interfaces with great care
      • test out multiple client programs
      • while may be possible to correct some interface flaws after an interface is released, you can’t count on it
    • Item 22: Use interfaces only to define types
      • do not use for constants
      • include constants in class if tightly associated
      • can include as enum or make a utility class
    • Item 23: Prefer class hierachies to tagged classes
      • the type is essentially defined in a member
      • multiple constructors for each “type”
      • tagged classes are verbose, error-prone and inefficent
      • use a class hierarchy
    • Item 24: Favor static member classes over nonstatic
      • 4 types: static member classes, nonstatic member classes, anonymous classes, local classes
      • non static member classes are implicitly associated with an enclosing instance which can harm GC and cause memory leak
      • on common use of nonstatic class is adapter
      • lambda preferred over anonymous classes now
    • Item 25: Limit source files to a single to-level class
      • never put multiple top-level classes or interfaces in a single source file
      • no benefits only risks
      • can override class definitions depending on how it was compiled
      • alternative is defining multiple static member classes instead
  5. Generics
    • Item 26: Don’t use raw types
      • you lose all the safety and expressiveness benefits of generics
      • e.g. List vs List<Object>
    • Item 27: Eliminate unchecked warnings
      • they are areas where you can get a ClassCastException at runtime
      • if you can’t eliminate it, but prove the code is correct supress it
      • suppress smallest scope possible and include rationale for why
    • Item 28: Prefer lists to arrays
      • arrays are reified (don’t lose type info at runtime) and covariant can result in type errors at runtime
      • generics types only at compile time at runtime type parameters are Objects
      • if you’re using generics, favor lists
    • Item 29: Favor generic types
      • if dealing with arrays, can use Object[] and cast to generic array type and suppress warning
      • e.g. elements = (E[]) new Object[LENGTH]
      • other approach is change the element type
      • e.g. E result = (E) elements[–size];
      • first is preferable
      • can also use bounded types
      • e.g. class DelayQueue<E extends Delayed> where E must be a subtype of Delayed
    • Item 30: Favor generic methods
      • if you just use <E> must all match exactly that type
      • use bounded wildcard to be more flexible
    • Item 31: Use bounded wildcards to increase AP flexibility
      • parameterized types are invariant e.g. List<Integer> is not a subtype of List<Number>
      • e.g. pushAll method of stack can use “Iterable<? extends E> src” (Iterable of some subtype of E)
        • the parameter src is a producer of E
      • if we have a popAll method that adds as popped elements to another collection want super type
        • public void popAll(Collection<? super E> dst)
        • dst must be some collection of super types of E
      • PECS: producers extend, consumer-super
      • do not use bounded wildcards as return types
      • if users has to think about wildcard types there is probably something wrong with its API
      • if type parameter appears only once ina method replace it with a wildcard
      • if you need to put something into a e.g. List<?>, create a private method that uses unbounded type parameter
    • Item 32: Combine generics and varargs judiciously
      • varargs build atop arrays and arrays have different type rules from generics
      • is allowed but take precautions
      • annotation with “safevarargs” annotation
      • safe if the method doesn’t store anything into the array and doesn’t allow a reference to the array to escape
      • alternatively use a List as a parameter
    • Item 33: Consider typesafe heterogeneous containers
      • can have collections hold multiple types by parameterizing the key
      • “Class” objects can be used as keys (type token)
      • or use custom keys e.g. DatabaseRow type can have a generic type Column<T> as it’s key
  6. Enums and Annotations
    • Item 34: Use enums instead of int constants
      • to associate data with enum constants declare field and pass into constructor
      • use when you need a set of constants whose members are known at compile time
    • Item 35: Use instance fields instead of ordinals
      • never derive a value associated with an enum from its ordinal
      • hard to update, brittle, may not match up with what you’re trying to represent
    • Item 36: Use EnumSet instead of bit fields
      • bit set harder to interpret
      • enumset combines conciseness with performance
    • Item 37: Use EnumMap instead of ordinal indexing
      • rarely appropriate to use ordinals to index into arrays
    • Item 38: Emulate extensible enums with interfaces
      • enums can implement arbitrary interfaces
      • while you cannot write an extensible enum type, you can emulate it by writing an interface to accomponay a basic enum type that implements the interface
    • Item 39: Prefer annotations to naming patterns
      • no reason to use naming patterns when you can use annotations instead
      • e.g. requiring “Test” in method name
    • Item 40: Consistently use the Override annotation
      • use Override annotation on every moethod that you believe to override a superclass declaration
      • easy to make mistakes
    • Item 41: Use marker interfaces to define types
      • marker interfaces define a type that is implemented by instances
      • marker interfaces can be targeted more precisely
      • chief advantage of marker annotations is that they are part of the larger annotation facility allowing for more consistency
      • must use annotation if applies to anything other than class or interface
      • otherwise, use interface since yo ucan use it as a type benefiting from compile time safety
      • marker interface if no methods
  7. Lambdas and Streams
    • Item 42:Prefer lambda to anonymous classes
      • omit type of lambda parameters unless makes clearer or required
      • if computation isn’t self-explanatory don’t use
      • should rarely, if ever, serialize a lambda
        • if you need to use an instance of a private static nested class
      • don’t use anonymous classes for function objects unless you have to create instances of types that aren’t functional interfaces
    • Item 43: Prefer method references to lambdas
      • method references usually shorter, clearer, and easier to document
      • sometimes lambda easier e.g. x -> x
      • use the one that is shorter and clearer
    • Item 44: Favor the use of standard functional interfaces
      • many existing ones provided
      • don’t be tempted to use with boxed primitives can be very bad for performance
      • can write your own under some circumstances
        • will be commonly used and could benefit from a descriptive name
        • has a strong contract associated with it
        • could benefit from custom default methods
      • always annotate your functional interfaces with @FunctionalInterface
    • Item 45: Use stream judiciously
      • overuse can make programs hard to read and maintain
      • without types, careful naming of lambda parameters is essential for readability
      • use helper methods
      • where you may want to use iterative
        • read or modify local variables
        • return, break, continue, or throw unchecked exception
      • where you may want to use stream
        • uniformly transform
        • filter
        • combine
        • accumulate
        • search
      • often down to personal and team preference
    • Item 46: Prefer side-effect-free functions in streams
      • forEach should only report the result
      • side-effects in streams is code smell
      • customary and wise to import all members of Collectors because it makes stream pipelines more readable
      • collectors provided for creating collections and resolving conflicts e.g. on Maps
    • Item 47: Prefer Collection to Stream as a return type
      • stream doesn’t extend iterable
      • provide interface users can stream or iterate on
      • Use Collection or an appropriate subtype
    • Item 48: Use caution when making streams parallel
      • unlikely to increase performance if source is from Stream.iterate or limit is used
      • Do not parallelize indiscriminately
      • performance gains from parallelism are best on streams over ArrayList, HashMap, HashSet, ConcurrentHashMap, arrays, int and long rages
        • can be accurately and cheaply split into subranges
        • good-to-excellent locality of reference
        • sequential element references are stored together in memory
      • pipeline operation also affects effectiveness
        • reductions are good e.g. min, max, count, sum
        • short-circuiting e.g. anyMatch, allMatch
        • collect method: not good, because overhead of combining collections
      • can also lead to incorrect results and incorrect behavior
        • accumulator and combiner must be associative, non-interfering, and stateless
      • must also be doing enough work to offset costs of paralleism
      • must test the performance before and after with realistic load
  8. Methods
    • Item 49: Check parameters for validity
      • most methods have restrictions
      • enforce at beginning
      • detect errors asap
      • use requireNonNull method to avoid manual null checks
      • use exception translation to throw correctly documented exception
      • document restrictions
    • Item 50: Make defensive copies when needed
      • careful around mutable objects
      • make copy before checks
      • return defensive copies for accessors
      • do not use clone of a parameter whose type is subclassable by untrusted parties
      • wherever possible use immutable objects
    • Item 51: Design method signatures correctly
      • chose names carefully
      • don’t go overboard in providing convenience methods
        • each method should pull its own weight
        • if in doubt, leave it out
      • avoid long parameter lists
        • long sequences of identical typed parameters are especially harmful
        • can break method up into multiple
        • create a helper class
        • use builder pattern
      • for parameter types, favor instances over classes
      • prefer two-element enums to booleans unless boolean meaning is clear
    • Item 52: Use overloading judiciously
      • choice of which overloading to invoke is made at compile time (vs runtime for overriding)
      • avoid confusing use of overloading
      • can always give methods different names
        • writeBoolean, writeInt, writeLong
      • when exporting overloadings with same number of parameters unlikely to confuse if types are “radically different”
      • do not overload methods to take different functional interfaces in the same argument position
    • Item 53: Use varargs judiciously
      • constructs and array and passes in at runtime
      • if you require at least one, use multiple parameters
      • consider array allocation and initialization for performance critical situations
    • Item 54: Return empty collections or arrays, not nulls
      • error-prone to return nulls
      • only optimize after measuring impace
    • Item 55: Return optionals judiciously
      • in spirit of checked exeption, client must know how to handle
      • if expensive to get default value, use supplier and orElseGet
      • returning optional that contains boxed primitive type is prohibitively expensive
      • never return an optional of a boxed primitive i.e. use OptionalInt, OptionalLong, etc
      • almost never appropriate to use as key, value or element in collection
    • Item 56: Write doc comments for all exposed API elements
      • document API properly, precede every exported class, interface, constructor, method, and field delcaration with doc comment
      • should be readable in source and generate documentation, but favor readability in generated documentation
      • no two members or constructors should have the same summary description
      • document type parameters for generics
      • document constants in enums
      • document members of annotation type
      • document thread-safety
      • document serialized form if serializable
  9. General Programming
    • Item 57: Minimize the scope of local variables
      • most powerful technique for minimizing scope of a local variable is to declare it where it is first used
      • prefer for loops to while loops
      • keep methods small and focused
    • Item 58: Prefer for-each loops to traditional for loops
      • e.g. (Element e: elements)
      • can’t use for loop if destructive filtering, transforming, parallel iteration
    • Item 59: Know and use the libraries
      • take advantage of the knowledge of experts who wrote it and the experience of people who’ve used it
      • e.g. use ThreadLocalRandom
      • numerous features are added so pay attention to these additions
      • every programmer should be famililar with the basics of java.lang, java.util and java.io
    • Item 60: A void float and double if exact answers are required
      • float and double are not exact do not use for monetary calculations
      • use BigDecimal, int, or long instead
    • Item 61: Prefer primitive types to boxed primitives
      • Applying the == operator to boxed primitives is almost always wrong
      • boxing/unboxing in a loop can have severe performance degradation
      • use boxed primitives for collections and type parameters
    • Item 62: Avoid strings where other types are more appropriate
      • strings a poor substitute for other values
      • commonly misued as primitives, enums, or aggregate types
    • Item 63: Beware the performance of string concatenation
      • repeatedly concatenating n strings requires time quadradic in n
      • don’t use with more than a few strings
      • use StringBuilder
    • Item 64: Refer to objects by their interfaces
      • program will be more flexible
      • use class if no appropriate interface exists
      • sometimes appropriate to use class if using a class-based framework
      • use concrete class if depending on some characteristic of that class  e.g. ordering of LinkedHashSet
      • if there is no appropriate interface, use th least specific clas that provides the required functionality
    • Item 65: Prefer interfaces to reflection
      • reflection can be flexible but at a cost:
        • lose compile-time checking
        • clumsy and verbose code
        • performance loss
      • can benefit by using in a very limited form
      • create instances reflectively and accesss them normally via interfaces or superclasses
    • Item 66: Use native methods judiciously
      • may need for accessing platform specific facilities
      • access to libraries that don’t exist in java
      • rarely advisable to use native methods for improved performance
      • disadvantages
        • no longer immune to memory corruption errors
        • glue code that is difficult to read and tedious to write
    • Item 67: Optimize judiciously
      • often produce software that is neither fast nore correct
      • strive to write good programs rather than fast ones
      • good programs embody principle of information hiding and localize design decisions
      • architectural flaws that limit performance can be impossible to fix
      • strive to avoid design decisions that limit performance
        • interactions between components and the outside world
      • consider the performance consequences of your API design decisions, wire-level protocols, and persistent data formats
      • measure performance before and after each attempted optimization
      • Java has a weaker performance model and bigger abstraction gap
        • need to measure optimization on different implementations and hardware platforms
        • the complexity of processors, VMs, libraries have grown over time
    • Item 68: Adhere to generally accepted naming conventions
      • refer to the Java Language Specification
      • don’t need to follow slavishly if conventions hold otherwise use common sense
  10. Exceptions
    • Item 69: Use exceptions only for exceptional conditions
      • because for exceptional cases, little incentive for jvm implementors to optimize
      • try/catch block inhibits certain optimizations
      • can obfuscate code and reduce performance
      • never use for ordinary control flow
      • well-designed API does not force clients to use exceptions for ordinary control flow
      • can provide a state-testing method (e.g. next and hasNext) or optional
      • mildy prefer state-testing, unless synchronization is an issue
    • Item 70: Use checked exceptions for recoverable condition and runtime exceptions for programming errors
      • only for cases where caller can reasonably recover from
      • runtime exceptions indicate programming error
        • all unchecked throwables should subclass RuntimeException
      • exceptions are just objects, include methods that furnish information
    • Item 71: Avoid unnecessary use of checked exceptions
      • can force programmers to deal with problems and enhance readability
      • overuse can make them less pleasant to use
      • can’t be used in streams
      • use sparingly
      • prefer optional unless you need to return information
    • Item 72: Favor the use of standard exceptions
      • strive for high degree of code reuse
      • most common: IllegalArgumentException, IllegalStateException, NullPointerException, IndexOutOfBoundsException, ConcurrentModificationException, UnsupportedOperationException
      • use only if conditions under which you throw are consistent with exception’s documentation
    • Item 73: Throw exceptions appropriate to the abstraction 
      • high layers should catch lower-level exceptions and throw exceptions that can be explained in terms of the higher level abstraction
      • use exception chaining to pass lower level exception, but don’t overuse
      • best way to deal with low level exceptions is to avoid them by ensuring lower-level methods succeed
      • If it is impossible to prevent them, have higher level silently work around, but log exceptions so programmers can investigate
    • Item 74: Document all exceptions thrown by each method
      • always declare checked exceptions individually, no supertype
      • wise to document unchecked and checked exceptions
      • every public method documentation should describe preconditions
      • Use @throws to document each exception, but not for unchecked exceptions
      • if an exception is thrown by many methods for the same reason, document at class level
    • Item 75: Include failure-capture information in detail messages
      • detail message should contain the values of all parameters and fields that contribute to the exception
      • do not include passwords or other sensitive information
      • stack trace intended to be analyzed along with documentation and source code so don’t need to be too verbose
      • can ensure exception captures correct information by including in constructor
      • not a highly used idiom, but highly recommended
      • allows programmatic access to information around failure cases
    • Item 76: Strive for failure atomicity
      • should leave object in state that it was in prior to invocation
      • 1) check parameters for validity prior to performing operations
      • 2) make a temporary copy first
      • 3) write recovery code
      • not always achievable or desirable
      • when rule is violated, API should clearly state what state the object will be left in
    • Item 77: Don’t ignore exceptions
      • empty catch defates the purpose of exceptions
      • if you ignore, add a comment explaining rationale in catch block and name the exception ignored
      • will result in a program that continues to fail silently
      • letting exception propagate can at lease cause program to fail swiftly and perserve information to aid in debugging
  11. Concurrency
    • Item 78: Synchronize access to shared mutable data
      • synchronized ensures only a single thread can execute a method or block at one time
      • guarantees no method will ever observe the object in an inconsistent state
      • without synchronization, changes may not be visisble to other threads
      • ensures threads see effects of all previous modifications
      • synchronization required for reliable communication between threads as well as for mutual exclusion
      • synchronization not guaranteed to work unless both read and write operations are synchronized
      • volatile keyword can be used to ensure communication effect
      • use synchronized to ensure multiple invocataions won’t be interleaved
      • don’t share mutable data if you can
      • confine mutable data to a single thread
    • Item 79: Avoid excessive synchronization
      • never cede control to the client within a synchronized method or block e.g an alien method
      • do as little work as possible inside synchronized regions
      • for mutable classes, either allow client to synchronize externally or make class threadsafe by synchronizing internally
      • only do internal, if you can achieve higher concurrency than you can with using client
    • Item 80: Prefer executors, tasks, and streams to threads
      • use executor framework
      • runnable or callable task
      • fork-join to steal work and increase utilization
    • Item 81: Prefer concurrency utilities to wait and notify
      • given difficulty of using wait and notify use higher-level concurrency utilities
      • e.g. Executor framework, concurrent collections, synchronizers
      • use concurrent implementation of data structures e.g. ConcurrentHashMap
    • Item 82: Document thread safety
      • synchronized is an implementation detail
      • immutable
      • unconditionally thread safe (don’t need synchronization) e.g. ConcurrentHashMap
      • conditionally thread-safe (some methods require external synchronization)
      • not thread-safe: clients must srround each method invocation with synchronization
      • thread-hostile: unsafe even with synchronization
      • lock fields should always be declared final
    • Item 83: Use lazy initialization judiciously
      • under most circumstances, normal initialziation is preferrable
      • if you use lazy initialization to break an initialization circularity, use synchronized accessor
      • if you need for performance on a static field, use the lazy initialization holder class idiom
      • if you need lazy init for performance on a instance field, use the double check idiom
    • Item 84: Don’t depend on the thread scheduler
      • program will not be portable
      • threads should not be run if they aren’t doing useful work
      • resist temptation to “fix” program by putting in calls to Thread.yield
      • Thread priorities are among the least portable features of Java
  12. Serialization
    • Item 85: Prefer alternatives to Java Serialization
      • allows attacker to do dangerous things
      • e.g. execute arbitrary native code on underlying hardware
      • e.g. denial-of-service attacks with deserialization bombs
      • best way is to never deserialize anything
      • use cross-platform structured data representations e.g. JSON or protobufs
      • don’t deserialize untrusted datat
      • if you do, use class whitelists
    • Item 86: Implement Serializabl with great caution
      • decreases flexibility to change a class’s implementation
      • byte-stream encoding becomes part of its exported API
      • increases liklihood of bugs and security holes
      • increases testing burden
      • classes designed for inheritance should rearely implement Serializable
    • Item 87: Consider using a custom serialized form
      • do not the default serialized form without first considering whether it is appropriate
      • even if default form is appropriate, must provide a readObject method to ensure invariants
      • before deciding to make a field nontransient, convince yourself that its value is part of the logical state of the object
      • declare an explicit serial version UID and do not change if you want to maintain compatibility
    • Item 88: Write readObject methods defensively
      • readObject is effectively another public constructor
      • when an object is deserialized it is critical to defensively copy any field containing an object reference that a client must not possess
      • when writing a public constructor do not assume that the byte stream reprsents an actual serialized instance
    • Item 89: For instance control prefer enum types to readResolve
      • Java guarantees there can be no instance besides the declared constants for enums
      • if you can’t use enums and class needs to be serializable and instance controlled, you must provide a readResolve method and ensure that all of the class’s instance fields are either primitive or transient
    • Item 90: Consider serialization proxies instead of serialized instances
      • design a private static nested class that concisely represents the logical state of an instance of the enclosing class
      • consider this pattern whenever you find yourself having to write a readObject or writeObject method on a class that is not extendable by its clients
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s