effective java: classes and interfaces

44
Effective Java: Classes and Interfaces Last Updated: Fall 2008

Upload: tehya

Post on 05-Jan-2016

47 views

Category:

Documents


0 download

DESCRIPTION

Effective Java: Classes and Interfaces. Last Updated: Fall 2008. Agenda. Material From Joshua Bloch Effective Java: Programming Language Guide Cover Items 13 through 22 Classes and Interfaces Was Items 12 through 18 in 1 st Edition Moral: Inheritance requires careful programming. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Effective Java:   Classes and Interfaces

Effective Java: Classes and Interfaces

Last Updated: Fall 2008

Page 2: Effective Java:   Classes and Interfaces

Classes and Interfaces2

Agenda Material From Joshua Bloch

Effective Java: Programming Language Guide

Cover Items 13 through 22 Classes and Interfaces Was Items 12 through 18 in 1st Edition

Moral: Inheritance requires careful

programming

Page 3: Effective Java:   Classes and Interfaces

Classes and Interfaces3

Item 13: Minimize Accessibility of Classes and Members

Standard advice for information hiding/encapsulation Decouples modules Allows isolated development and

maintenance Java has an access control

mechanism to accomplish this goal

Page 4: Effective Java:   Classes and Interfaces

Classes and Interfaces4

Make Each Class or Member as Inaccessible as Possible

Standard list of accessibility levels private package-private (aka package friendly) protected public

Huge difference between 2nd and 3rd

package-private: part of implementation protected: part of public API

Page 5: Effective Java:   Classes and Interfaces

Classes and Interfaces5

Exception: Exposing Constants

Public constants must contain either primitive values or references to immutable objects

Wrong – Potential Security Hole: public static final Type[] VALUES =

{…}; Problem:

VALUES is final; entries in VALUES are not!

Page 6: Effective Java:   Classes and Interfaces

Classes and Interfaces6

Exposing Constants - Solutions

Correct:private static final Type[] PRIVATE_VALUES =

{…};public static final List VALUES = Collections.unmodifiableList(Arrays.asList (PRIVATE_VALUES));

Also Correct:private static final Type[] PRIVATE_VALUES =

{…};public static final Type[] values() { return (Type[]) PRIVATE_VALUES.clone();}

Page 7: Effective Java:   Classes and Interfaces

Classes and Interfaces7

Item 14: In Public Classes, Use Accessors, Not Public Fields

Avoid code such as:Class Point { public double x; public double y; }

No possibility of encapsulation Use get/set methods instead:Public double getX() { return x; }Public void setX(double x) { this.x = x}

Advice holds for immutable fields as well Limits possible ways for class to evolve

Page 8: Effective Java:   Classes and Interfaces

Classes and Interfaces8

Item 15: Minimize Mutability

Reasons to make a class immutable: Easier to design Easier to implement Easier to use Less prone to error More secure Easier to share Thread safe

Page 9: Effective Java:   Classes and Interfaces

Classes and Interfaces9

5 Rules to Make a Class Immutable

Don’t provide any mutators Ensure that no methods can be

overridden (more detail…) Make all fields final (more detail…) Make all fields private Ensure exclusive access to any

mutable components (more detail…)

Page 10: Effective Java:   Classes and Interfaces

Classes and Interfaces10

Rule 2: No Overridden Methods

Prevents careless or malicious subclasses from compromising the immutable behavior of the class

How to implement Make class final (easiest) Make methods final (allows subclassing) Make all constructors private or package-

private Requires static factories, which are better

anyway

Page 11: Effective Java:   Classes and Interfaces

Classes and Interfaces11

Rule 3: Make All Fields Final

Clearly expresses intent System enforcement of immutability Issues with object instantiation and

thread access Sometimes, making fields final is too

strong Lazy initialization may be preferable

Page 12: Effective Java:   Classes and Interfaces

Classes and Interfaces12

Rule 5: Exclusive Access to Mutable Components

Never initialize a mutable field to a client provided reference

Never return a reference to a mutable field

Make defensive copies See Liskov – Exposing the rep

Page 13: Effective Java:   Classes and Interfaces

Classes and Interfaces13

Typical Transformation Typical method in mutable class Foo:

public void foo(T1 t1, T2, t2, …) {modify “this”} Immutable version of Foo:

public Foo foo(T1 t1, T2, t2, …) { Foo f = … … return f;}

Functional programming vs. procedural programming.

See Liskov’s Poly for an example

Page 14: Effective Java:   Classes and Interfaces

Classes and Interfaces14

Disadvantage: Performance

Typical approach: Provide immutable class Provide mutable companion class for situations

where performance is an issue Clients choose on performance needs Example in Java Library:

String (Immutable) StringBuilder (Companion Mutable Class)

Static factories can cache frequently used items More on this in Liskov 15

Page 15: Effective Java:   Classes and Interfaces

Classes and Interfaces15

Item 16: Favor Composition over Inheritance

Issue ONLY for implementation inheritance Interface inheritance does NOT have these

problems Inheritance breaks encapsulation!

Difficult to evolve superclass without breaking subclasses

Difficult for superclass to maintain invariants in face of malicious/careless subclass

Page 16: Effective Java:   Classes and Interfaces

Classes and Interfaces16

Example: Broken Subtypepublic class IHashSet extends HashSet private int addCount = 0; // add() calls public IHashSet() {} public IHashSet(Collection c) { super(c); } public boolean add(Object o) { addCount++; return super.add(o);} public boolean addAll(Collection c) { addCount += c.size(); return

super.addAll(c);}}

Page 17: Effective Java:   Classes and Interfaces

Classes and Interfaces17

Broken Example, continued

So, what’s the problem? IHashSet s = new IHashSet(); s.addAll(Arrays.asList(new String[] {“Snap”,

“Crackle”, “Pop”})); What does addCount() return?

3? 6?

Internally, HashSet’s addAll() is implemented on top of add(), which is overridden. Note that this is an implementation detail, so we can’t get it right in IHashSet

Page 18: Effective Java:   Classes and Interfaces

Classes and Interfaces18

Source of Difficulty: Overridden Methods

Overriding methods can be tricky May break the superclass invariant

Overridden method does not maintain invariant

May break subclass invariant New methods may be added to superclass What if new method matches subclass

method?

Also, recall problems with equals() and hashCode()

Page 19: Effective Java:   Classes and Interfaces

Classes and Interfaces19

Composition Fortunately, composition solves all of

these problems – even though it makes the programmer work harder

// Inheritance public Class Foo extends Fie {…} // Composition public class Foo { private Fie f = …; // Note: forwarded methods …}

Page 20: Effective Java:   Classes and Interfaces

Classes and Interfaces20

Revisiting the Examplepublic class ISet implements Set { private final Set s; private int addCount = 0; public ISet (Set s) { this.s = s} public boolean add(Object o) { addCount++; return s.add(o); } public boolean addAll (Collection c) { addCount += c.size(); return s.addAll(c); } // forwarded methods from Set interface

Page 21: Effective Java:   Classes and Interfaces

Classes and Interfaces21

A more elegant version (without generics – See Bloch for these)

// Reusable Forwarding Classpublic class ForwardingSet implements Set { private final Set s; public ForwardingSet (Set s) { this.s = s;} public void clear() { s.clear();} public boolean contains(Object o) { return s.contains(o);} // plus all the other methods}// Wrapper class – public class ISet extends ForwardingSet { private int addCount = 0; public ISet (Set s) { super(s);} @Override public boolean add(Object o) { addCount++; return super.add(e); } // other instrumented methods}

Page 22: Effective Java:   Classes and Interfaces

Classes and Interfaces22

This is Cool! Consider temporarily instrumenting a

Set Note that Set is an interfacestatic void f(Set s) { ISet myS = new ISet (s); // use myS instead of s // all changes are reflected in s!}

Page 23: Effective Java:   Classes and Interfaces

Classes and Interfaces23

A Variation That Doesn’t Work

public class ICollection implements Collection { private final Collection c; private int addCount = 0; public ICollection (Collection c) { this.c = c} public boolean add(Object o) {…} public boolean addAll (Collection c) {…} // forwarded methods from Collection interface public boolean equals(Object o) { return c.equals(o); } // Now, we’re dead!

Page 24: Effective Java:   Classes and Interfaces

Classes and Interfaces24

This is no longer Cool! Consider temporarily instrumenting a Set

Note: Set is a subtype of CollectionSet s = new HashSet();ICollection t = new ICollection(s);s.equals(t) // c is not a Set, so falset.equals(s) // t.c == s, so true

Issue: Set has a uniform equals contract; Collection does not (and should not…)

Keep this in mind when using this model.

Page 25: Effective Java:   Classes and Interfaces

Classes and Interfaces25

Item 17: Design and Document for Inheritance

Or else prohibit it. First, document effects of overriding

any method Document “self use”, as in IHashSet

example This is “implementation detail”, but

unavoidable, since subclass “sees” implementation.

Inheritance violates encapsulation!

Page 26: Effective Java:   Classes and Interfaces

Classes and Interfaces26

Efficiency May Require Hooks

protected methods may be required for efficient subclasses.

Example: protected removeRange() method in

AbstractList Not of interest to List clients Only of interest to implementers of

AbstractList – provides fast clear() operation

Alternative – O(n^2) clear operation

Page 27: Effective Java:   Classes and Interfaces

Classes and Interfaces27

Inheritance is Forever A commitment to allow inheritance is

part of public API If you provide a poor interface, you

(and all of the subclasses) are stuck with it.

You cannot change the interface in subsequent releases.

Page 28: Effective Java:   Classes and Interfaces

Classes and Interfaces28

Constructors Must Not Invoke Overridable Methods

// Problem – constructor invokes overridden m()public class Super { public Super() { m();} public void m() {…};}public class Sub extends Super { private final Date date; public Sub() {date = new Date();} public void m() { // access date variable}}

Page 29: Effective Java:   Classes and Interfaces

Classes and Interfaces29

What Is the Problem? Consider the code Sub s = new Sub(); The first thing that happens in Sub()

constructor is a call to constructor in Super()

The call to m() in Super() is overridden But date variable is not yet initialized! Further, initialization in Super m() never

happens! Yuk!

Page 30: Effective Java:   Classes and Interfaces

Classes and Interfaces30

Inheritance and Cloneable, Serializable

Since clone() and readObject() behave a lot like constructors, these methods cannot invoke overridable methods either.

Problem – access to uninitialized state For Serializable

readResolve(), writeReplace() must be protected, not private (or they will be ignored in subclass.)

Page 31: Effective Java:   Classes and Interfaces

Classes and Interfaces31

Bottom Line Be sure you want inheritance, and

design for it, or Prohibit inheritance

Make class final, or Make constructors private (or package-

private)

Page 32: Effective Java:   Classes and Interfaces

Classes and Interfaces32

Item 18: Prefer Interfaces to Abstract Classes

Existing classes can be easily retrofitted to implement a new interface Same is not true for abstract classes

due to single inheritance model in Java Interfaces are ideal for “mixins”

Example: Comparable interface Interfaces aren’t required to form a

hierarchy Some things aren’t hierarchical

Page 33: Effective Java:   Classes and Interfaces

Classes and Interfaces33

More Interfaces Wrapper idiom a potent combination

with interfaces See ISet example

Possible to provide skeletal implementations for interfaces java.util does this with

AbstractCollection, AbstractSet, AbstractList, and AbstractMap

Page 34: Effective Java:   Classes and Interfaces

Classes and Interfaces34

Example for AbstractListstatic List intArrayAsList(final int[] a) { if (a == null throw new NPE(…); return new AbstractList() { public Object get(int i) { return new Integer(a[i]);} public int size() { return a.length;} public Object set(int i, Object o) { int oldVal = a[i]; a[i] = ((Integer) o).intValue(); return new Integer(oldVal);}};}

Page 35: Effective Java:   Classes and Interfaces

Classes and Interfaces35

This Implementation Does a Lot!

The List interface includes many methods.

Only 3 of them are explicitly provided here.

This is an “anonymous class” example Certain methods are overridden

Note that it is possible to add a method to an abstract class in a new release It is not possible to add a method to an

interface

Page 36: Effective Java:   Classes and Interfaces

Classes and Interfaces36

Item 19: Use Interfaces Only to Define Types

Example that fails the test: “Constant” interface – avoidpublic interface PhysicalConstants { static final double AVOGADROS = ……}

Why is this bad? Users of a class that implements this interface

don’t care about these constants! Think about the client, not the

implementor

Page 37: Effective Java:   Classes and Interfaces

Classes and Interfaces37

Alternative to Constants in Interfaces

Constant utility class public class PhysicalConstants { public static final double

AVOGADROS = …}

Page 38: Effective Java:   Classes and Interfaces

Classes and Interfaces38

Item 20: Prefer Class Hierarchies to Tagged Classes

//Tagged Class – vastly inferior to a class hierarchyclass Figure { enum Shape { RECTANGLE, CIRCLE }; final Shape shape; // Tag field double length; double width; // for RECTANGLE double radius; // for CIRCLE Figure (double length, double width) {…} // RECTANGLE Figure (double radius) {…} // CIRCLE double area() { switch (shape) { case RECTANGLE: return length*width; case CIRCLE: return Math.PI*(radius * radius); default: throw new AssertionError(); }}

Page 39: Effective Java:   Classes and Interfaces

Classes and Interfaces39

Item 20 Continued: A much better solution

//Class hierarchy replacement for a tagged classabstract class Figure { // Note: NOT instantiable! abstract double area();}class Circle extends Figure { final double radius; Circle(double rad) { radius = rad; } double area() { return Math.PI*(radius*radius); }}class Rectangle extends Figure { final double length; final double width; Rectangle (double len; double wid) { length = len; width = wid; } double area() { return length*width; }}

Page 40: Effective Java:   Classes and Interfaces

Classes and Interfaces40

Item 21: Use Function Objects to Represent Strategies

In Java, can’t pass functions directly Only Objects can be arguments

So, pass Objects to pass functions Example: Instances of Comparator

We covered this in Liskov 8

Page 41: Effective Java:   Classes and Interfaces

Classes and Interfaces41

Item 22: Favor Static Member Classes Over Nonstatic

Nested classes Defined within another class

Four flavors Static member class Nonstatic member class (inner) Anonymous class (inner) Local class (inner)

Page 42: Effective Java:   Classes and Interfaces

Classes and Interfaces42

Static vs NonStatic Static requires no connection to

enclosing instance. Nonstatic always associated with

enclosing instance Possible performance issue Possible desire to create by itself

Hence recommendation to favor static See Iterator implementations

Page 43: Effective Java:   Classes and Interfaces

Classes and Interfaces43

Anonymous class – (another) example

// Typical use of an anonymous classArrays.sort (args, new Comparator() { public int compare(Object o1, Object o2)

{ return ((String) o1).length() – (String) o2).length(); }});

Question: Does this satisfy the compare() contract?

Page 44: Effective Java:   Classes and Interfaces

Classes and Interfaces44

Local classes Declared anywhere a local variable

may be declared Same scoping rules Have names like member classes May be static or nonstatic

(depending on whether context is static or nonstatic)