38
ITEM 1 Consider static factory methods instead of constructors

Creating and destroying objects

Embed Size (px)

DESCRIPTION

This is a presentation from Effective Java, Chapter 2 : Creating and Destroying Objects. This presentaiton was created by Nishant Puri.

Citation preview

Page 1: Creating and destroying objects

ITEM 1Consider static factory methods instead of

constructors

Page 2: Creating and destroying objects

Is simply a static method that returns an instance of the class

ADVANTAGES They have names. They are not required to create a new object each time they are

invoked. They can return an object of any subtype of their return type.

◦ Best example for this is : Collection API They reduce verbosity of creating parameterized type instances.

DISADVANTAGES When providing only static factory methods, classes without public or

protected constructors cannot be subclassed. They are not readily distinguishable from other static methods

static factory methods

Page 3: Creating and destroying objects

Example◦ Car Factory produces different Car objects◦ Ordinary

Different classes implement Car interface Directly instantiate car objects Need to modify client to change cars

◦ Using pattern Use carFactory class to produce car objects Can change cars by changing carFactory

Factory Pattern

Page 4: Creating and destroying objects

class 350Z implements Car; // fast carclass Ram implements Car; // truckclass Accord implements Car; // family carCar fast = new 350Z(); // returns fast car

public class carFactory { public static Car create(String type) { if (type.equals("fast")) return new 350Z(); if (type.equals("truck")) return new Ram(); else if (type.equals(“family”) return new Accord(); }}

Car fast = carFactory.create("fast"); // returns fast car

Factory Example

Page 5: Creating and destroying objects

By default, constructors should be preferred, because they are simpler to understand and write.

However, if you specifically need to decouple the construction niceties of an object from its semantic meaning as understood by the client code, you'd be better off using factories.

Constructors

Page 6: Creating and destroying objects

Use static factory methods for a more intuitive API, to improve performance via object-caching, to implement singletons, in interface-based frameworks, and to return objects of private classes.

Use constructors in classes designed for inheritance (there shouldn’t be many of these) and for greater visibility in API documentation (since they appear in a separate table in standard Javadocs).

The verdict?

Page 7: Creating and destroying objects

Item 2Consider a builder when faced with many

constructor parameters

Page 8: Creating and destroying objects

Telescoping Constructor Pattern

JavaBeans Pattern

Builder Pattern

Page 9: Creating and destroying objects

This method is the traditional way of dealing with the problem of many constructor parameters.

The problem being that but it is hard to write client code when there are many parameters, and harder still to read it.

Telescoping Constructor Pattern

Page 10: Creating and destroying objects

The approach is that we call the parameterless constructor to create the object and then call setter methods to set each required parameter and each optional parameter of interest.

Limitations Because construction is split across multiple

calls a JavaBean may be in an inconsistent state partway through its construction.

This pattern precludes the possibility of making a class immutable

JavaBeans Pattern

Page 11: Creating and destroying objects

The third alternative that combines the safety of the telescoping constructor pattern with the readability of the JavaBeans pattern is the builder pattern.

Instead of making the desired object directly, the client calls a constructor (or static factory) with all of the required parameters and gets a builder object. Then the client calls setter-like methods on the builder object to set each optional parameter of interest.

Builder Battern

Page 12: Creating and destroying objects

// Builder Pattern

public class NutritionFacts {private final int servingSize;private final int servings;private final int calories;private final int fat;private final int sodium;private final int carbohydrate;

public static class Builder {// Required parameters

private final int servingSize;private final int servings;

// Optional parameters-initialized to //default values

private int calories = 0;private int fat = 0;private int carbohydrate = 0;private int sodium = 0;

public Builder(int servingSize, int servings) {

this.servingSize = servingSize;this.servings = servings;

}

public Builder calories(int val) { calories = val; return this; }public Builder fat(int val) {

fat = val; return this; }public Builder carbohydrate(int val) {

carbohydrate = val; return this;

}public Builder sodium(int val) { sodium = val; return this; }public NutritionFacts build() {

return new NutritionFacts(this);}

}

private NutritionFacts(Builder builder) {servingSize = builder.servingSize;servings = builder.servings;calories = builder.calories;fat = builder.fat;sodium = builder.sodium;carbohydrate = builder.carbohydrate;

}

}

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).

calories(100).sodium(35).carbohydrate(27).build();

Page 13: Creating and destroying objects

Advantages It is flexible in the sense that a single builder can

be used to build multiple objects. The parameters of the builder can be tweaked

between object creations to vary the objects.Disadvantages

In order to create an object, you must first create its builder which could be a problem in some performance critical situations.

Also, the Builder pattern is more verbose than the telescoping constructor pattern, so it should be used only if there are enough parameters, say four or more

Page 14: Creating and destroying objects

The Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if most of those parameters are optional.

Client code is much easier to read and write with builders than with the traditional telescoping constructor pattern.

Builders are much safer than JavaBeans.

To Summarize

Page 15: Creating and destroying objects

Item 3Enforce the singleton property with a

privateconstructor or an enum type

Page 16: Creating and destroying objects

A singleton is simply a class that is instantiated exactly once Often in designing a system, we want to control how an

object is used, and prevent others (ourselves included) from making copies of it or creating new instances. Scenario/Use-Case

Consider a central configuration object that stores setup information. It should have one and one only instance - a global copy accessible from any part of the application, including any threads that are running. Creating a new configuration object and using it would be fairly useless, as other parts of the application might be looking at the old configuration object, and changes to application settings wouldn't always be acted upon. So this is one of the cases wherein we would need the concept of singleton.

singleton

Page 17: Creating and destroying objects

Prior to 1.5public class SingletonObject {

private static SingletonObject ref; private SingletonObject() {

// no code required }

public static SingletonObject getSingletonObject() { if (ref == null) ref = new SingletonObject(); return ref;

} }

Approaches for singleton

Page 18: Creating and destroying objects

Preventing thread problems with your singleton◦ public static synchronized SingletonObject getSingletonObject()

This is important because this would prevent two threads from calling the getSingletonObject() method at the same time. If one thread entered the method just after the other, you could end up calling the SingletonObject constructor twice and returning different values.

Another possible way to violate the design principles of the singleton is with the help of the clone() method which would create and return a copy of the singleton object.  So, to avoid this, we must add a clone() method of our own, and throw a CloneNotSupportedException.

Page 19: Creating and destroying objects

How does serialization affects singleton??

◦ it is not sufficient merely to add implements Serializable to its declaration. To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve() method. Otherwise, each time a serialized instance is deserialized, a new instance will be created.

Page 20: Creating and destroying objects

For example:

// readResolve for instance control -

private Object readResolve() {// Return the one true Elvis and let the garbage

collector take //care of the Elvis impersonator.

return ref;

}

This method ignores the deserialized object, returning the distinguished instance that was created when the class was initialized

Page 21: Creating and destroying objects

As of release 1.5

// Enum singleton - the preferred approachpublic enum Elvis {

INSTANCE;

public void leaveTheBuilding() { ... }}

This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.

Page 22: Creating and destroying objects

Item 4Enforce non-instantiability with a

private constructor

Page 23: Creating and destroying objects

Use case/ scenario

Creating a utility class which is just a collection of static maethods

Such utility classes are not designed to be instantiated because the class is just a grouping of static methods and static fields so an instance would be nonsensical.

Page 24: Creating and destroying objects

public class UtilityClass {//Suppress default constructor for noninstantiabilityprivate UtilityClass() {

throw new AssertionError();}

} The AssertionError provides insurance in

case the constructor is accidentally invoked from within the class.

Noninstantiable utility class

Page 25: Creating and destroying objects

Item 5Avoid creating unnecessary objects

Page 26: Creating and destroying objects

It is often appropriate to reuse a single object instead of creating a new functionally equivalent object each time it is needed. Reuse enhances performane as it is faster.

String s = new String(“nishant");//never do!

String s = “nishant"; This was the case of immutable objects but

even for mutable objects you should reuse them if you know they won’t be modified.

• Example :

Page 27: Creating and destroying objects

There’s a new way to create unnecessary objects in release 1.5. It is called autoboxing.

Examplepublic static void main(String[] args) {

Long sum = 0L;for (long i = 0; i < Integer.MAX_VALUE; i++) {

sum += i;}

System.out.println(sum);}

The variable sum is declared as a Long instead of a long, which means that the program constructs about 231 unnecessary Long instances.

The lesson is clear: prefer primitives to boxed primitives, and watch out for unintentional autoboxing.

Page 28: Creating and destroying objects

Item 6Eliminate obsolete object references

Page 29: Creating and destroying objects

An obsolete reference is simply a reference that will never be dereferenced again.

This can be explained with the help of the following example….◦ Stack example

What is an obsolete reference ?

Page 30: Creating and destroying objects

Whenever a class manages its own memory, the programmer should be alert for memory leaks.

◦ Simply put, it manages its own memory.◦ The elements in the active portion of the array are allocated,

and those in the remainder of the array are free. ◦ The garbage collector has no way of knowing this ◦ For the GC all of the object references in the elements

array are equally valid. ◦ Only the programmer knows that the inactive portion of the

array is unimportant. ◦ The programmer effectively communicates this fact to the

garbage collector by manually nulling out array elements as soon as they become part of the inactive portion.

So where is the problem ?

Page 31: Creating and destroying objects

Whenever an element is freed, any object references contained in the element should be nulled out.

Another common source of memory leaks is caches

When should you null out a reference ?

Page 32: Creating and destroying objects

Item 7Avoid finalizers

Page 33: Creating and destroying objects

In C++, destructors are the normal way to reclaim the resources associated with an object, a necessary counterpart to constructors.

In Java, the garbage collector reclaims the storage associated with an object when it becomes unreachable, requiring no special effort on the part of the programmer.

C++ destructors are also used to reclaim other nonmemory resources.

In Java, the try finally block is generally used for this purpose.

Page 34: Creating and destroying objects

There is no guarantee they’ll be executed promptly so never do anything time-critical in a finalizer.

The promptness with which finalizers are executed is primarily a function of the garbage collection algorithm, which varies widely from JVM to JVM

It is entirely possible, even likely, that a program terminates without executing finalizers on some objects that are no longer reachable. As a consequence, you should never depend on a finalizer to update critical persistent state

Limitations

Page 35: Creating and destroying objects

If an uncaught exception is thrown during finalization, the exception is ignored, and finalization of that object terminates. Uncaught exceptions can leave objects in a corrupt state. If another thread attempts to use such a corrupted object, arbitrary nondeterministic behavior may result. Normally, an uncaught exception will terminate the thread and print a stack trace, but not if it occurs in a finalizer.

There is a severe performance penalty for using finalizers. On my machine, the time to create and destroy a simple object is about 5.6 ns. Adding a finalizer increases the time to 2,400 ns

Contd.

Page 36: Creating and destroying objects

Explicit termination methods are typically used in combination with the try-finally construct to ensure termination

Examples: close method, cancel method

// try-finally block guarantees execution of termination method

Foo foo = new Foo(...);try {

// Do what must be done with foo...

} finally {

foo.terminate(); // Explicit termination //method}

Work-around

Page 37: Creating and destroying objects

They have 2 legitimate uses:

One is to act as a “safety net” in case the owner of an object forgets to call its explicit termination method

A second legitimate use of finalizers concerns objects with native peers. A native peer is a native object to which a normal object delegates via native methods.◦ Because a native peer is not a normal object, the garbage

collector doesn’t know about it and can’t reclaim it when its Java peer is reclaimed. A finalizer is an appropriate vehicle for performing this task, assuming the native peer holds nocritical resources

So what are the finalizers good for ?

Page 38: Creating and destroying objects

AWT uses native code (code specific to a single operating system) to display its components. Each implementation of the Jave Runtime Environment (JRE) must provide native implementations of Buttons, Labels, Panels, and all of the other AWT components.

Whenever you use an AWT component, if forwards all of its drawing requests to a piece of native code. This allows you to generically use an AWT Button in your application, but the Button appears as a Windows Button, a Motif Button, a Mac Button, or a real button on whatever platform you are running.

These pieces of native code are referred to as peers, as they share the responsibility for displaying a component.

Peer code includes native code to display components, as well as draw lines, determine platform specifics such as current screen size, and other native platform issues.