Chapter 3 - Methods Common to All Objects
- Item 8: Obey the general congract when overriding equals - page 33
- If you decide to implement equals, make sure it is
- reflexive: for all x, x.equals(x)
- symmetric: for all x & y, x.equals(y) iff y.equals(x)
- transitive: for all x, y, z, if x.equals(y) and y.equals(z), then x.equals(z) must be true
- consistent: for all x & y, multiple invocations of x.equals(y) return the same result provided nothing used in equality is changed in either x or y
- for all x, x.equals(null) must return false
- Item 9: Always override hashCode when you override equals
- Item 10: Always override toString
- Item 11: Override clone judiciously
- Item 12: Consider implementing Comparable
Chapter 4 - Classes and Interfaces
- Item 13: Minimize the accessibility of classes and members
- accessibilities
- private
- package-private (default)
- protected
- public
- classes with public mutable fields are not thread-safe
- Item 14: In public classes, use accessor methods, not public fields
- if a class is accessible outside its package, provide accessor methods to preserve flexibility
- if a class is package-private there is nothing inherently wrong with exposing its data fields
- Item 15: Minimize mutability
- to make a class immutable:
- Don't provide any methods that modify the object's state
- Ensure that the class can't be extended
- Make all fields final
- Make all fields private
- Ensure exclusive access to any mutable components
- immutable objects are simple, inherently thread-safe and can be shared freely
- Item 16: Favor composition over inheritance
- Inheritance violates encapsulation
- Inheriting from another class propagates any flaws that were in the superclass
- Use composition and forwarding instead
- Item 17: Design and document for inheritance or else prohibit it
- If a class is meant to be inherited from, the class must document it's self-use of overridable methods
- state in a method comment, which overridable methods it invokes
- The only way to test a class designed for inheritance is to write subclasses
- therefore you must test your class by writing subclasses before releasing it
- constructors must not invoke an overridable method - pg. 90
- It's best to prohibit subclassing in classes that are not designed and documented to be safely subclassed
- either make the class final
- or make all the constructors private or package-private
- Item 18: Prefer interfaces to abstract classes
- A class can only extend 1 abstract class, but can implement multiple interfaces
- Existing classes can be easily retrofitted to implement a new interface
- Interfaces are ideal for defining mixins, abstract classes cannot
- mixin: a type that a class can implement in addition to it's primary type, to declare it has some optional functionality
- Interfaces allow for the construction of nonhierarchical type frameworks
- Interfaces enable safe, powerful functionality enhancements
- via the wrapper class idiom
- You can combine the virtues of abstract classes with interfaces by providing an abstract skeletal implementation class to go wit heach nontrivial interface that you export
- by convention, skeletal implementations are called AbstractInterface (e.g. AbstractSet, AbstractCollection, etc.)
- because skeletal implementations are designed for inheritance, obey the rules of Item 17
- example page 95
- simulated multiple inheritance : create a skeletal implementation of an interface, then create another class that has an instance of a private innerclass that extends that skeletal implementation
- 1 major advantage of abstract classes : they are far easier to evolve than interfaces
- to add a method to an abstract class, just add it with a reasonable default implementation - then the inheriting classes can override it in due time
- interfaces, however can never have a method added without breaking pre-existing implementations
- because of this, the programmer must get it right the first time, before it's released into the wild
- Interfaces are generally the best way to go
- the exception is when ease of evolution is deemed more important than flexibility and power
- Item 19: Use interfaces only to define types
- The constant interface anti-pattern is a poor use of interfaces
- it is an implementation detail that becomes visible to clients
- subsequent releases of a class that may no longer need the constants must continue implementing the interface to ensure binary compatibility
- Item 20: Prefer class hierarchies to tagged classes
- tagged classes(example pg. 100) are verbose, error-prone and inefficient
- a tagged class is just a pallid imitation of a class hierarchy
- Item 21: Use function objects to represent strategies
- function object: an instance of a class whose methods perform operations on other objects (e.g. comparator)
- a primary use of function pointers/objects is to implement the Strategy Pattern
- Item 22: Favor static member classes over nonstatic
- a nested class should exist only to serve its enclosing class - if it's useful outside that class, it should be a top-level class
- 4 types: static member classes, nonstatic member classes, anonymous classes, local classes
- all but the 1st are inner classes
- each has it's use (page 108, end)
- If you declare a member class that does not require access to an enclosing instance, always put the static modifier in its declaration
- not doing so forces instances to store a reference to it's eclosing class, which wastes space and time
Chapter 5 - Generics (page 109)
- useful generics vocabulary chart on page 115
- Item 23: Don't use raw types in new code
- generics are safe, raw types are not
- this is because the compiler will tell you if you're using a type where you shouldn't be rather than finding out at runtime
- Set<?> can contain objects of some unknown type (safe)
- Set<Object> can contain anything (unsafe)
- Item 24: Eliminate unchecked warnings
- Eliminate all unchecked warnings if you can
- If you can't eliminate a warning, and you can prove that the code is typesafe, then and only then, suppress the warning with an @suppressWarnings("unchecked") annotation
- Always use suppressWarnings on the smallest scope possible
- Always add a comment saying why you used it
- Item 25: Prefer lists to arrays
- Arrays are covariant(Object[] is a supertype of String[]) , Lists are invariant(better - can't add objects of typeA to a list of typeB - compile time error
- Arrays are reified (enforce types at runtime and not at compile time) and generics are implemented by erasure (enforce types at compile time but not at runtime - allows for backwards compatibility with older Java version code)
- Better to enforce and find out of issues at compile time
- Item 26: Favor generic types
- Fewer errors discovered at runtime - they'll be discovered at compile time
- If using arrays, can't generically type them, so might need to use type casting (pg126 example)
- Item 27: Favor generic methods
- generic methods use type inference to figure out the type of the invocation
- generic static factory method (pg131)
- type parameters can be bounded by an expression that involves that type parameter itself
- e.g. <T extends Comparable <T>>
- this reads 'for every type T that can be compared to itself'
- pg 133
- Item 28: Use bounded wildcards to increase API flexibility
- for maximum flexibility, use wildcard types on input parameters that represent producers or consumers
- if a type is both a producer and consumer, wildcards are useless
- PECS - producer-extends, consumer-super
- use wildcards so that you can use any subtype of a certain type in a list
- e.g. stack.pushAll(Iterable<? extends E> src) { for(E e: src)...}
- pg. 135
- use wildcards so that you can require a method parameter to be able to store a generic type
- e.g. stack.popAll(Collection<? extends E> dst) { ...dst.add(pop())}
- pg. 136
- do not use wildcard types as return types - it only causes the client code to have to use wildcard types and provides no additional flexibility
- properly used, wildcard types are nearly invisible to a class' users
- rarely, explicit type parameters are necessary
- e.g. Set<Number> numbers = Union.<Number>union(integers, doubles);
- Comparables and Comparators are always consumers (pg. 138)
- always use Comparable<? super T> in preference to Comparable<T>
- always use Comparator<? super T> in preference to Comparator<T>
- e.g. public static <T extends Comparable<? super T>> T maxOf(List>? extends T> list)
- Item 29: Consider typesafe heterogeneous containers
- The Class class has a generic method for casting safely
- public class Class<T> { T cast(Object obj); }
- The Class class has a method to cast to a subclass
- someClassObj.asSubclass(Annotation.class);
lolz
ReplyDelete