This document summarizes key points from Chapter 4 of Effective Java on classes and interfaces. It discusses 19 items on best practices such as minimizing accessibility of classes and members, using accessor methods over public fields, favoring immutable classes, composition over inheritance, interfaces over abstract classes, and function objects to represent strategies. The document provides examples and explanations for each item.
1 of 25
Downloaded 22 times
More Related Content
Ej Chpt#4 Final
1. Effective Java (Second Edition)
CHAPTER 4: Classes and Interfaces
presented by
Chandan Benjaram
2. Agenda
Item 13: Minimize the accessibility of classes and members
Item 14: In public classes, use accessor methods, not public ?elds
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 de?ne 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. 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 modi?ers for members (private, package private,
protected, public)
Leaks?
?security can be leaked if class implements ¡®Serializable¡¯
Fix:
?use ¡®transient¡¯ keyword
4. Point-II: Instance ?elds should never be public
Problem:
//Potential security hole!
public static ?nal Type[] VALUES = { ... };
Fix:
private static ?nal Type[] PRIVATE_VALUES = { ... };
public static ?nal List VALUES = Collections.unmodi?ableList(Arrays.asList(PRIVATE_VALUES));
Point-III: Public classes should not contain any public ?elds with the exception of
immutable public static ?nal ?elds
5. Item-14: Public classes should encourage use of
accessors/mutators instead of public ?elds
?if a class is accessible outside its package, provide accessors
?incase of package private/private nested classes, it is OK to expose
?elds through ¡®public¡¯ access modi?ers
6. Item-15: Minimize mutability
What is immutable class?
?its a, very simple to write, class whose instance can not be
modi?ed 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 ?elds ?nal
?make all ?elds 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. 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. 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
?nally:
?classes should be immutable unless there is a precise reason to
make mutable
?make every ?eld as ?nal 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. Item-16: Favor Composition over Inheritance
But, why?
?violates encapsulation
?parent private ?elds can not be accessible if needed!
Solution:
?Use Composition pattern + Forwarding Methods, which may be seen
as Decorator pattern (loosely speaking!)
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. 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 ?aws, violations, limitations, etc.,
before implementing an interface
12. Item-17: Design and document for Inheritance or
else prohibit it
?class must document its self-use of override-able methods
?parent private ?elds 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. a subclass
Finally:
?incase of no options other than self-use of override-able methods,
use self speci?c code to private helpers
14. Item-18: Prefer interfaces to abstract classes
?as java permits only single inheritance, a abstract class type
de?nition is more constrained vs an interface de?nition
?abstract class hierarchies may cause ¡®combinatorial explosion¡¯
?on the other hand, interfaces are ideal for mixins. thus adds more
type de?nitions to primary type
?existing classes can be easily retro?tted 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. Item 19: Use interfaces only to de?ne types
?interfaces should be only used to de?ne 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. 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 quali?cations
JDK followers?
java.lang.Integer, java.lang.Double, etc.
17. Item 20: Prefer class hierarchies to tagged
classes
?they provide a multi datatype bene?t
18. Contd...
?kinda verbose, error-prone, inef?cient, and may violate inheritance
?limits the use of type detectors (¡®instanceof¡¯/¡®isassignablefrom¡¯)
?a simple ?x 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. 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):
De?ne 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. 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. 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?
?de?ned 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. 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-modi?able 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. 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. 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