Ej Chpt#4 Final


Published on

My presentation at Apple so far, Effective Java revisit

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

  • Ej Chpt#4 Final

    1. 1. Effective Java (Second Edition) CHAPTER 4: Classes and Interfaces presented by Chandan Benjaram
    2. 2. Agenda Item 13: Minimize the accessibility of classes and members Item 14: In public classes, use accessor methods, not public fields Item 15: Minimize mutability Item 16: Favor composition over inheritance Item 17: Design and document for inheritance or else prohibit it Item 18: Prefer interfaces to abstract classes Item 19: Use interfaces only to define types Item 20: Prefer class hierarchies to tagged classes Item 21: Use function objects to represent strategies Item 22: Favor static member classes over non-static
    3. 3. Item-13: Minimize the accessibility of classes and members A well designed API should hide all of its implementation details(a.k.a, internals) and thus component inter-communication should happen through a well declared API standards (protocols). Thus in general, it should encourage highest possible cohesion and loose coupling, if any! Point-I: Make each class member as inaccessible as possible How you do it? ➡use package private/public on top-outer classes ➡use access modifiers for members (private, package private, protected, public) Leaks? ➡security can be leaked if class implements ‘Serializable’ Fix: ➡use ‘transient’ keyword
    4. 4. Point-II: Instance fields should never be public Problem: //Potential security hole! public static final Type[] VALUES = { ... }; Fix: private static final Type[] PRIVATE_VALUES = { ... }; public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES)); Point-III: Public classes should not contain any public fields with the exception of immutable public static final fields
    5. 5. Item-14: Public classes should encourage use of accessors/mutators instead of public fields ➡if a class is accessible outside its package, provide accessors ➡incase of package private/private nested classes, it is OK to expose fields through ‘public’ access modifiers
    6. 6. Item-15: Minimize mutability What is immutable class? ➡its a, very simple to write, class whose instance can not be modified once initialized ➡maintains a single state across all calls, thus thread safe by default How to make a class immutable? ➡avoid mutators (use functional approach instead!) ➡make it non-extendable ➡make all fields final ➡make all fields private ➡ensure exclusive access to any mutators, if any Ex: Use defensive copying techniques, readObject, etc. Note: beware of nested classes! (possible security hole)
    7. 7. Advantages of immutable classes: ➡each object belongs to a single state avoiding any complex state transformations ➡by default, they are thread-safe. thus no synchronization needed ➡effective pooling, caching can be performed with the aid of different techniques and patterns Ex: Factory pattern. Suggestion: ➡never provide a copy constructor/clone methods (String.copy() violates) Disadvantages: ➡each distinct value object requires its own object increasing memory footprint and GC demand ➡problem becomes more worse when working with complicated multistage operations on large objects
    8. 8. Solution: ➡memory footprint and GC demand problem can be limited by sharing class self internals. Ex: BigInteger (signum-magnitude) public BigInteger negate() Returns a BigInteger whose value is (-this). ➡nicely designed public companion classes can handle multistage operations problem very smoothly Ex: StringBuilder for immutable class, String finally: ➡classes should be immutable unless there is a precise reason to make mutable ➡make every field as final unless there is a precise reason to avoid ➡fully initialize object with all its required invariants either using constructor/static factories but not with any public helpers Hint: Builder pattern can save your life!
    9. 9. Item-16: Favor Composition over Inheritance But, why? ➡violates encapsulation ➡parent private fields can not be accessible if needed! Solution: ➡Use Composition pattern + Forwarding Methods, which may be seen as Decorator pattern (loosely speaking!)
    10. 10. but wait, there is a problem: ➡it may cause wrapped object blind in viewing wrapper object. thus Callback frameworks fails to function as expected. A ‘SELF problem’.
    11. 11. When to prefer inheritance then? ➡if you can precisely establish a ‘is-a’ relationship between sub-class and super-class then go for it! JDK violators- Properties (is-not-a HashTable), Stack (is-not-a Vector), etc. Finally: ➡read API docs thoroughly for any flaws, violations, limitations, etc., before implementing an interface
    12. 12. Item-17: Design and document for Inheritance or else prohibit it ➡class must document its self-use of override-able methods ➡parent private fields can not be accessible if needed! ➡a class designed for inheritance must be reviewed thoroughly. once shipped, it would be impossible to make changes without breaking own clients ➡constructors must not invoke override-able methods Example: a super class
    13. 13. a subclass Finally: ➡incase of no options other than self-use of override-able methods, use self specific code to private helpers
    14. 14. Item-18: Prefer interfaces to abstract classes ➡as java permits only single inheritance, a abstract class type definition is more constrained vs an interface definition ➡abstract class hierarchies may cause ‘combinatorial explosion’ ➡on the other hand, interfaces are ideal for mixins. thus adds more type definitions to primary type ➡existing classes can be easily retrofitted to implement new interface ➡design your interface with outmost case. once it is shipped & used, it can not be possible to change method signature or add more without breaking its clients ➡preferably, provide a ‘skeletal implementation’(abstract interface) of your interface to go along with it Ex: AbstractMap<K,V>, AbstractList<E>, etc. (many)
    15. 15. Item 19: Use interfaces only to define types ➡interfaces should be only used to define mixin type ➡avoid designing constant interfaces Why? -> you are entering into a client commitment -> pollutes inheritance hierarchy for namespaces // DONT DO THIS // CONSTANT INTERFACE package edu.ej.ch14; public interface Interface1{ static String NAME_PREFIX = "_"; } //CLASS IMPLEMENTING INTERFACE public class Class1 implements Interface1 { @Override public String toString() { return NAME_PREFIX + Class1.class.getName(); } } // A TEST HELPER class Tester1 { public static void main(String[] args) { Class1 clazz1 = new Class1(); System.out.printf("Class1#toString: %1$s", clazz1.toString()); } } // OUT PUT Class1#toString: _edu.ej.ch14.Class1
    16. 16. Contd... JDK violators? java.io.ObjectStreamConstants What to do with constants? -> use enum type constants -> use helper constant classes -> you can use ‘static import’ to avoid name qualifications JDK followers? java.lang.Integer, java.lang.Double, etc.
    17. 17. Item 20: Prefer class hierarchies to tagged classes ➡they provide a multi datatype benefit
    18. 18. Contd... ➡kinda verbose, error-prone, inefficient, and may violate inheritance ➡limits the use of type detectors (‘instanceof’/‘isassignablefrom’) ➡a simple fix can be replacing tagged class with class hierarchy as: // Class hierarchy replacement for a tagged class abstract class Figure { abstract double area(); } class Circle extends Figure { final double radius; Circle(double radius) { this.radius = radius; } double area() { return Math.PI * (radius * radius); } } class Rectangle extends Figure { final double length; final double width; Rectangle(double length, double width) { this.length = length; this.width = width; } double area() { return length * width; } }
    19. 19. Item 21: Use function objects to represent strategies ➡function object: an object which performs actions on other objects using self methods ➡primarily used to implement Strategy Pattern Strategy Pattern (GOF def): Define a family of algorithms, encapsulate each one, and make them interchangeable. [The] Strategy [pattern] lets the algorithm vary independently from clients that use it. ➡help to interchangeably operate generically
    20. 20. Contd... ➡how we do it? package edu.ej.ch14.item20; import java.io.Serializable; // DEFINE AN INTERFACE public interface CustomComparator<T> { int compare(T arg0, T arg1); } class Helper{ // STRING TYPE IMPLEMENTATION private static class StringComparator implements CustomComparator<String> { @Override public int compare(String arg0, String arg1) { // comparing lexicographically return arg0.compareTo(arg1); } } // BYTE TYPE IMPLEMENTATION private static class ByteComparator implements CustomComparator<Byte>, Serializable { @Override public int compare(Byte arg0, Byte arg1) { return arg0.compareTo(arg1); } } // CACHED IMPLEMENTATIONS WRAPPED AS INTERFACE TYPE public static final CustomComparator<String> STRING_COMP= new StringComparator(); public static final CustomComparator<Byte> BYTE_COMP= new ByteComparator(); }
    21. 21. Contd... ➡tester class Tester { public static void main(String[] args) { System.out.printf("STRING result: %1$d %nBYTE result: %2$d", Helper.STRING_COMP.compare("x", "x"), Helper.BYTE_COMP.compare(Byte.valueOf("1"), Byte.valueOf("3"))); } } // OUTPUT STRING result: 0 BYTE result: -2 (OBSERVER THIS) ➡how I did? ➡defined an interface for strategy (comparing) ➡created 2 separate concrete strategy implementations (StringComparator, ByteComparator) ➡I could have done anonymous implementation, but it limits my mixin types ➡encapsulated strategy implementations and exported as helper constants to strategy type.
    22. 22. Item 22: Favor static member classes over non- static ➡There are 4 types of nested classes: 1) static member classes 2) non-static member classes 3) anonymous classes 4) local classes What are they for? 1) static member classes: ➡a static class that’s declared inside other class(enclosing class) ➡has access to enclosing class’s members ➡obeys general contract as static members ➡generally used as public helpers (recall POJO Builder pattern!) 2) non-static member classes: -> each instance is associated with enclosing instance -> a non-modifiable association to enclosing class is established when member classes is created -> you can create instance of member class in 2 ways, a) calling constructor of member class from enclosing class instance member b)outerInstance.new InnerClass(...)
    23. 23. Contd... 2) non-static member classes (contd...): -> commonly used as Adaptors for enclosing class Ex: java.util.Map.values() -> member class instance always requires an enclosing class instance -> it forces you to allocate enclosing class instance even if you do not need it! -> always prefer static member classes incase you do not have to access instance members! 3) anonymous classes: -> has no name -> declared and instantiated at point of use -> limits your type checking capabilities -> clients can not invoke any functions -> can not support multiple types -> generally used to create function objects, process objects, within static factories Ex: new Comparator(compare()...omitted)
    24. 24. Contd... 4) local classes: -> same as local variables in terms of place and rules -> ideally, should be kept under fewer lines -> creates instances that are tied to enclosing class
    25. 25. have fun