# Effective Java Notes [On Hold] [ToC] ## Introduction These are my ongoing notes for Effective Java. **Note-taking is currently on hold to prioritize other reading material for work.** ## Chapter 2: Creating and Destroying Objects ### Item 1: Consider static factory methods instead of constructors **Static factory method** = static method that returns an instance of a class Naming Convention * `from`: type conversion, takes parameter and returns corresponding instance of parameter * `to`: aggregation method, takes multiple parameters and returns instance type that incorporates them * `valueOf`: verbose alternative to `to` and `from` * `instance`/`getInstance`: returns instance that is described by parameters * `create`/`newInstance`: same as above, but returns a new instance * `getType`: `getInstance` when factory method is in a different class * `newType`: `newInstance` when factory method is in a different class * `type`: concise alternative to `getType` and `newType` **Advantages** * names, which are more intuitive and easier to read than construtors * new object is not created when invoked * immutable classes can cache and re-use preconstructued instances, which can improve performance * instance-controlled class: class that controls its number of instances * return any object that is a subtype of the return type * interface-based frameworks: interfaces provide natural return types for static factory methods * class of returned object can vary based on parameters * hides implementation -> concise API * class of returned object does not need to exist when class containing the method is written * service-provider frameworks: system that has providers implement a service and has the service make implementations available to clients * service interface: implementation * provider registration API: register implementation * service access API: clients to obtain instances of services * service provider interface: produces instances of service interface; optional **Disadvantages** * classes without public or protected constructors cannot be subclassed * subclasses implicitly call the constructor of the superclass in their constructor; no access means this is impossible * hard for programmers to find * does not stand out in API documentation ### Item 2: Consider a builder when faced with many constructor parameters Traditionally, classes with many constructor parameters use: * **Telescoping constructor pattern**: provide a constructor with the necessary parameters, a contructor with one optional parameter, a constructor with two optional parameters, and so on until you get a constructor with all optional parameters * doesn't scale well * hard to read and write * **JavaBeans pattern**: parameterless constructor and setter methods to set parameters * more readable, but less safe * JavaBean may end up in an inconsistent state partway through construction since there is no way to enforce consistency by checking constructor parameters * cannot make a class immutable and harder to make thread-safe **An alternative approach:** **Builder pattern**: client calls constructor or static factory method with required parameters to get a builder object, calls builder's setter methods to set optional parameters, and paramaterless `build` method to generate a immutable object * best of both worlds * especially great for optional parameters or parameters with identical types * check validity of parameters in builder's constructor and setter methods * check invariants involving parameters in the constructor invoked by `build` after copying parameters from builder; failed check should throw `IllegalArgumentException` * great for hierarchial structure * *simulated self-type idiom*: method chaining in subclasses without casting * *covariant return typing*: subclass method returns a subtype of the return type declared in the superclass; lets clients use builders without casting * Advantages * multiple varargs parameters * aggregate parameters from multiple calls into a single field * build multiple objects * tweak parameters of builder between invocations of `build` * fill in fields automatically on object creation * Disadvantages * performance cost from creating builder * more verbose than telescoping constructor pattern; only use with 4 or more parameters or if you want to add more parameters in the future ### Item 3: Enforce the singleton property with a private constructor or an enum type **Singleton**: class that is instantiated exactly once * represent stateless object (e.x. a function) or a unique system component * difficult to test because of mock implementation substitution **Common implementations:** * private constructor that is called once to intialize a public static final field that holds the instance * To prevent an attack that invokes the private constructor reflectively, modify the constructor to throw an exception when creating a second instance * API makes it clear that the class is a singleton * same as above, except use a public static factory method to return the instance instead of a public field * simpler than first implementation * more flexibility to change class into a non-singleton implementation * generic singleton factory * method reference can be used as a supplier * declare a single-element enum * more concise than public field approach * serialization mechanism * best way to implement singleton * can't use if singleton extends a superclass other than `Enum` * Make a singleton class `Serializable` * implement `Serializable` * declare all instance fields `transient` * `readResolve` method (prevents new instances from being created when a serialized instance is deserialized) ### Item 4: Enforce noninstantiability with a private constructor **Static utility class** = only has static methods and fields * Use cases: group related methods on primitive values and arrays, objects that implement an interface, final class (cannot be subclasses) * should not be instantiated * making a class abstract for noninstantiability does not work because class can be subclasses and subclass instantiated * instead, make the constructor private, throw an assertion error inside the contructor to prevent it from being invoked in the class, and include a comment * prevents subclasses as constructor cannot be invoked ### Item 5: Prefer dependency injection to hardwiring resources * If the class relies on resources, use dependency injection pass the resource into the constructor when creating a new instance * preserves immutability * applicable to constructors, static factories, builders * Variant: pass in resource factory to constructor (Factory Method pattern) * `Supplier<T>` interface represents factories * type parameter should be bounded wildcard type to allow client to pass in a factory (`Mosaic create(Supplier<? extends Tile> tileFactory) { ... }`) * large projects with many dependencies should rely on a dependency injection framework such as Dagger, Guice, or Spring ### Item 6: Avoid creating unnecessary objects * reuse a single object instead of creating a functionally equivalent object every time * an immutable object can always be reused * use static factory methods over constructors for immutable classes * `Boolean.valueOf` vs `Boolean(string)` **Example** ``` // Performance can be greatly improved! static boolean isRomanNumeral(String s) { return s.matches("^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"); } ``` A new pattern instance is created every time this method is called. This is expensive since the regular expression will be compiled into a [finite state machine](https://stackoverflow.com/questions/525004/short-example-of-regular-expression-converted-to-a-state-machine). ``` // Reusing expensive object for improved performance public class RomanNumerals { private static final Pattern ROMAN = Pattern.compile( "^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"); static boolean isRomanNumeral(String s) { return ROMAN.matcher(s).matches(); } } ``` Instead, compile the pattern upon class initiatlization, cache it, and reuse the same instance over and over again. * Lazy initialization = initialize a field when it is first used * un-needed in the example because it is too complicated and has no measureable performance improvement * adapter/view = objects that delegates to a backing object, providing an alternate interface, * no need to create more than one instance of a given adapter to a given object * Example: `keySet` method for `Map` * Autoboxing = mix primitive types and objects ``` // Hideously slow! Can you spot the object creation? private static long sum() { Long sum = 0L; for (long i = 0; i <= Integer.MAX_VALUE; i++) sum += i; return sum; } ``` The program above is slow because it constructs unnecessary `Long` instances. Changing `Long` to `long` greatly reduces runtime. * Takeaway: Prefer primitives to boxed primitives and watch out for unintentional autoboxing * Not a hard rule. Creating and reclaiming small objects with constructors that do little work is relatively cheap and can increase readability * Object pools are a bad idea unless the objects are extremely heavyweight * Example: database connection, makes sense to reuse object for connection cost * Drawbacks: code clutter, increased memory footprint, harms performance * defensive copying requires making a new object, penalty for not doing this is greater than making a duplicate object -> bugs and security holes vs style and performance ### Item 7: Eliminate obsolete object references In Java, objects are automatically re-claimed when you're done with them, but you still need to think about memory management **Example** ``` public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } /** * Ensure space for at least one more element, roughly * doubling the capacity each time the array needs to grow. */ private void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } } ``` * Code has a memory leak. Objects popped off stack will not be garbage collected, even if the program does not have references to them, because the stack maintains obsolete references * Results in performance decrease. Extreme cases cause disk paging + program failure **Solution:** ``` public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; // Eliminate obsolete reference return result; elements[size] = null; } ``` * Null out references once they become obsolete * Benefit is that an error will be caught if the references were de-refereneced by accident * Nulling out every object reference clutters up the program unnecessarily * Practice should be the exception, not the norm * Best way is to let the variable that contained the reference to fall out of scope * Whenever a class manages its own memory, look for memory leaks * Example: `Stack` class has storage pool for elements of the `elements` array. Active portion elements are allocated and remainder of free, but garbage collector cannot differentiate between the two. Therefore, programmer must null free references. * Cache = common source of memory leak * Solutions * Represent cache as `WeakHashMap` = entries removed after becoming obsolete, desired lifetime of entires determined by external references to key, not value * If cache entry lifetime is not well defined + entries are less valuable over time = cleanse cache of unused entries using a background thread or when adding new entries to cache * Listeners and other callbacks = another source of memory leak * store only weak references to callbacks such as cache entries in a `WeakHashMap` * heap profilers can be used to identify memory leaks ### Item 8: Avoid finalizers and cleaners * Finalizers and Cleaners: release resources used by objects before they're removed from memory * finalizers are dangerous, unpredictable, unnecessary * finalizers [deprecated](https://bugs.openjdk.java.net/browse/JDK-8165641) in Java 9 for cleaners, which are less dangerous, but still unpredictable and unncessary ### Item 9: Prefer try-with-resources to try-finally * Libraries have resources that must be manually closed using a `close` method: `InputStream`, `OutputStream`, etc. * Historically, try-finally statments were used, but they have deficiencies and are messy Example: ``` static void copy(String src, String dst) throws IOException { InputStream in = new FileInputStream(src); try { OutputStream out = new FileOutputStream(dst); try { byte[] buf = new byte[BUFFER_SIZE]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } finally { out.close(); } } finally { in.close(); } } ``` * try-with-resource statement must have resources that implement `AutoCloseable` interface (any resource that must be closed needs to implement this) * exceptions are also suppressed to get the original exception * shorter, cleaner code Example ``` static void copy(String src, String dst) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst)) { byte[] buf = new byte[BUFFER_SIZE]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } } ``` ## Chapter 3: Methods Common to All Objects ### Item 10: Obey the general contract with overriding equals * Don't override the equals method if each instance of the class is inherently unique * No need for a class to provide a logical equality test, superclass has overriden equals and superclass behavior is appropriate for this class, class is private/package-private and equals method will never be invoked **Equals Method** ``` @Override public boolean equals(Object o) { throw new AssertionError(); // Method is never called } ``` * Override equals when class has a different notion of logical equality and a superclass has not overriden equals * Occurs for value classes, which represent a value such as `Integer` and `String` * Exceptions are value classes that use instance control or enum types * The equals method implements an equivalence relation with these properties: * Reflexive: For any non-null reference value `x`, `x.equals(x)` returns true * Symmetric: For any non-null reference values x and y, `x.equals(y)` must return true if and only if `y.equals(x)` returns true. * Transitive: For any non-null reference values `x`,`y`,`z`,if `x.equals(y)` returns true and `y.equals(z)` returns true, then `x.equals(z)` must return true. * Consistent: For any non-null reference values `x` and `y`, multiple invocations of `x.equals(y)` must consistently return true or consistently return false, provided no information used in equals comparisons is modified. * For any non-null reference value `x`,`x.equals(null)` must return false. **Final notes:** * Always override hashcode when overriding equals * Don't substitute another type for object in the equals declaration ### Item 11: Always override `hashcode` when you override `equals` * Not overriding `hashCode` will prevent it from working in collections such as `HashMap` and `HashSet` because equal objects must have equal hashcodes * Good hash code produces unequal hashcodes for unequal instances * If class is immutable and cost of calculating hashcode is significant, consider caching it or lazily initialize the first time `hashCode` is called * Don't exclude significant fields from hashcode to improve performance * Don't provide detailed specifications for value returned by hashcode so there's more flexibility to change it ### Item 12: Always override `toString` * a good `toString` implementation makes class more pleasant to use and easier to debug * `toString` method should return all interesting information contained in object * specifying format of return value in documentation ### Item 13: Override `clone` judiciously * `Cloneable` meant to be mixin interface, but it works counterintuitively because it has no methods, meaning it lacks a `clone` method. Object's `clone` method is protected. * If a class implements `Cloneable`, Object's `clone` method returns a field-by-field copy of the object * In practice, a class implementing Cloneable is expected to provide a properly functioning public clone method * immutable classes should not provide a `clone` method * new interfaces and classes should not extend `Cloneable` * less harmful for final classes, but only do so for justified reasons ### Item 14: Consider implementing `Comparable` * `compareTo` method is available in `Comparable` and is not declared in `Object` * used for order comparisions * returns negative value for less than, 0 for equal, and positive value for greater than * throws `ClassCastException` when objects are of different type * implementing `Comparable` implies that instances of a class have a natural ordering * all value classes + enums implement `Comparable` * When writing `compareTo` methods for integral primitive fields, use `compare` method instead of relational operators because the latter is considered verbose and error-prone * `Comparator` interface has comparator construction methods, which is more concise, but has a minor performance cost ## Chapter 4: Classes and Interfaces TBD ## Sources Effective Java by Joshua Bloch