http://www.javapractices.com/topic/TopicAction.do?Id=66
Immutable objects
Immutable objects are simply objects whose state (the object's data) cannot change after construction. Examples of immutable objects from the JDK include String and Integer.Immutable objects greatly simplify your program, since they:
- are simple to construct, test, and use
- are automatically thread-safe and have no synchronization issues
- don't need a copy constructor
- don't need an implementation of clone
- allow hashCode to use lazy initialization, and to cache its return value
- don't need to be copied defensively when used as a field
- make good Map keys and Set elements (these objects must not change state while in the collection)
- have their class invariant established once upon construction, and it never needs to be checked again
- always have "failure atomicity" (a term used by Joshua Bloch): if an immutable object throws an exception, it's never left in an undesirable or indeterminate state
- ensure the class cannot be overridden - make the class final, or use static factories and keep constructors private
- make fields private and final
- force callers to construct an object completely in a single step, instead of using a no-argument constructor combined with subsequent calls to setXXX methods (that is, avoid the Java Beans convention)
- do not provide any methods which can change the state of the object in any way - not just setXXX methods, but any method which can change state
- if the class has any mutable object fields, then they must be defensively copied when they pass between the class and its caller
It's interesting to note that BigDecimal is technically not immutable, since it's not final.
Example
import java.util.Date; /** * Planet is an immutable class, since there is no way to change * its state after construction. */ public final class Planet { public Planet (double aMass, String aName, Date aDateOfDiscovery) { fMass = aMass; fName = aName; //make a private copy of aDateOfDiscovery //this is the only way to keep the fDateOfDiscovery //field private, and shields this class from any changes that //the caller may make to the original aDateOfDiscovery object fDateOfDiscovery = new Date(aDateOfDiscovery.getTime()); } /** * Returns a primitive value. * * The caller can do whatever they want with the return value, without * affecting the internals of this class. Why? Because this is a primitive * value. The caller sees its "own" double that simply has the * same value as fMass. */ public double getMass() { return fMass; } /** * Returns an immutable object. * * The caller gets a direct reference to the internal field. But this is not * dangerous, since String is immutable and cannot be changed. */ public String getName() { return fName; } // /** // * Returns a mutable object - likely bad style. // * // * The caller gets a direct reference to the internal field. This is usually dangerous, // * since the Date object state can be changed both by this class and its caller. // * That is, this class is no longer in complete control of fDate. // */ // public Date getDateOfDiscovery() { // return fDateOfDiscovery; // } /** * Returns a mutable object - good style. * * Returns a defensive copy of the field. * The caller of this method can do anything they want with the * returned Date object, without affecting the internals of this * class in any way. Why? Because they do not have a reference to * fDate. Rather, they are playing with a second Date that initially has the * same data as fDate. */ public Date getDateOfDiscovery() { return new Date(fDateOfDiscovery.getTime()); } // PRIVATE /** * Final primitive data is always immutable. */ private final double fMass; /** * An immutable object field. (String objects never change state.) */ private final String fName; /** * A mutable object field. In this case, the state of this mutable field * is to be changed only by this class. (In other cases, it makes perfect * sense to allow the state of a field to be changed outside the native * class; this is the case when a field acts as a "pointer" to an object * created elsewhere.) */ private final Date fDateOfDiscovery; }
How to create Immutable Class and Object in Java - Tutorial Example
Writing or creating immutable classes in Java is becoming popular day by day, because of concurrency and multithreading advantage provided by immutable objects. Immutable objects offers several benefits over conventional mutable object, especially while creating concurrent Java application. Immutable object not only guarantees safe publication of object’s state, but also can be shared among other threads without any external synchronization. In fact JDK itself contains several immutable classes like String, Integer and other wrapper classes. For those, who doesn’t know what is immutable class or object, Immutable objects are those, whose state can not be changed once created e.g.java.lang.String, once created can not be modified e.g. trim, uppercase, lowercase. All modification in String result in new object, see why String is immutable in Java for more details. In this Java programming tutorial, we will learn, how to write immutable class in Java or how to make a class immutable. By the way making a class immutable is not difficult on code level, but its the decision to make, which class mutable or immutable which makes difference. I also suggest reading, Java Concurrency in Practice to learn more about concurrency benefit offered by Immutable object.
What is immutable class in Java
As said earlier, Immutable classes are those class, whose object can not be modified once created, it means any modification on immutable object will result in another immutable object. best example to understand immutable and mutable objects are, String and StringBuffer. Since String is immutable class, any change on existing string object will result in another string e.g. replacing a character into String, creating substring from String, all result in a new objects. While in case of mutable object like StringBuffer, any modification is done on object itself and no new objects are created. Some times this immutability of String can also cause security hole, and that the reason why password should be stored on char array instead of String.
How to write immutable class in Java
Despite of few disadvantages, Immutable object still offers several benefits in multi-threaded programming and it’s a great choice to achieve thread safety in Java code. here are few rules, which helps to make a class immutable in Java :
1. State of immutable object can not be modified after construction, any modification should result in new immutable object.
2. All fields of Immutable class should be final.
3. Object must be properly constructed i.e. object reference must not leak during construction process.
4. Object should be final in order to restrict sub-class for altering immutability of parent class.
By the way, you can still create immutable object by violating few rules, like String has its hashcode in non final field, but its always guaranteed to be same. No matter how many times you calculate it, because it’s calculated from final fields, which is guaranteed to be same. This required a deep knowledge of Java memory model, and can create subtle race conditions if not addressed properly. In next section we will see simple example of writing immutable class in Java. By the way, if your Immutable class has lots of optional and mandatory fields, then you can also use Builder design pattern to make a class Immutable in Java.
Immutable Class Example in Java
Here is complete code example of writing immutable class in Java. We have followed simplest approach and all rules for making a class immutable, including it making class final to avoid putting immutability at risk due to Inheritance and Polymorphism.
public final class Contacts {
private final String name;
private final String mobile;
public Contacts(String name, String mobile) {
this.name = name;
this.mobile = mobile;
}
public String getName(){
return name;
}
public String getMobile(){
return mobile;
}
}
This Java class is immutable, because its state can not be changed once created. You can see that all of it’s fields are final. This is one of the most simple way of creating immutable class in Java, where all fields of class also remains immutable like String in above case. Some time you may need to write immutable class which includes mutable classes like java.util.Date, despite storing Date into final field it can be modified internally, if internal date is returned to the client. In order to preserve immutability in such cases, its advised to return copy of original object, which is also one of the Java best practice. here is another example of making a class immutable in Java, which includes mutable member variable.
public final class ImmutableReminder{
private final Date remindingDate;
public ImmutableReminder (Date remindingDate) {
if(remindingDate.getTime() < System.currentTimeMillis()){
throw new IllegalArgumentException("Can not set reminder” +
“ for past time: " + remindingDate);
}
this.remindingDate = new Date(remindingDate.getTime());
}
public Date getRemindingDate() {
return (Date) remindingDate.clone();
}
}
In above example of creating immutable class, Date is a mutable object. If getRemindingDate() returns actual Date object than despite remindingDate being final variable, internals of Date can be modified by client code. By returning clone() or copy of remindingDate, we avoid that danger and preserves immutability of class.
Benefits of Immutable Classes in Java
As I said earlier Immutable classes offers several benefits, here are few to mention:
1) Immutable objects are by default thread safe, can be shared without synchronization in concurrent environment.
2) Immutable object simplifies development, because its easier to share between multiple threads without external synchronization.
3) Immutable object boost performance of Java application by reducing synchronization in code.
4) Another important benefit of Immutable objects is reusability, you can cache Immutable object and reuse them, much like String literals and Integers. You can use static factory methods to provide methods like valueOf(), which can return an existing Immutable object from cache, instead of creating a new one.
4) Another important benefit of Immutable objects is reusability, you can cache Immutable object and reuse them, much like String literals and Integers. You can use static factory methods to provide methods like valueOf(), which can return an existing Immutable object from cache, instead of creating a new one.
Apart from above advantages, immutable object has disadvantage of creating garbage as well. Since immutable object can not be reused and they are just a use and throw. String being a prime example, which can create lot of garbage and can potentially slow down application due to heavy garbage collection, but again that's extreme case and if used properly Immutable object adds lot of value.
That's all on how to write immutable class in Java. we have seen rules of writing immutable classes, benefits offered by immutable objects and how we can create immutable class in Java which involves mutable fields. Don’t forget to read more about concurrency benefit offered by Immutable object in one of the best Java book recommended to Java programmers, Concurrency Practice in Java.
Read more: http://javarevisited.blogspot.com/2013/03/how-to-create-immutable-class-object-java-example-tutorial.html#ixzz3gh3HNXbc
--------------------------------
Copy constructors
Copy constructors:
- provide an attractive alternative to the rather pathological clone method
- are easily implemented
- simply extract the argument's data, and forward to a regular constructor
- are unnecessary for immutable objects
public final class Galaxy { /** * Regular constructor. */ public Galaxy(double aMass, String aName) { fMass = aMass; fName = aName; } /** * Copy constructor. */ public Galaxy(Galaxy aGalaxy) { this(aGalaxy.getMass(), aGalaxy.getName()); //no defensive copies are created here, since //there are no mutable object fields (String is immutable) } /** * Alternative style for a copy constructor, using a static newInstance * method. */ public static Galaxy newInstance(Galaxy aGalaxy) { return new Galaxy(aGalaxy.getMass(), aGalaxy.getName()); } public double getMass() { return fMass; } /** * This is the only method which changes the state of a Galaxy * object. If this method were removed, then a copy constructor * would not be provided either, since immutable objects do not * need a copy constructor. */ public void setMass(double aMass){ fMass = aMass; } public String getName() { return fName; } // PRIVATE private double fMass; private final String fName; /** Test harness. */ public static void main (String... aArguments){ Galaxy m101 = new Galaxy(15.0, "M101"); Galaxy m101CopyOne = new Galaxy(m101); m101CopyOne.setMass(25.0); System.out.println("M101 mass: " + m101.getMass()); System.out.println("M101Copy mass: " + m101CopyOne.getMass()); Galaxy m101CopyTwo = Galaxy.newInstance(m101); m101CopyTwo.setMass(35.0); System.out.println("M101 mass: " + m101.getMass()); System.out.println("M101CopyTwo mass: " + m101CopyTwo.getMass()); } }
Example run of this class:>java -cp . Galaxy
M101 mass: 15.0
M101Copy mass: 25.0
M101 mass: 15.0
M101CopyTwo mass: 35.0
Avoid clone
Avoid implementing clone.
- clone is very tricky to implement correctly in all circumstances, nearly to the point of being pathological
- the importance of copying objects will always remain, since object fields often need to be defensively copied
- copy constructors and static factory methods provide an alternative to clone, and are much easier to implement
This example shows a superclass with a typical implementation of clone, and a subclass which has disabled its clone method.
import java.util.Date; public abstract class Fruit implements Cloneable { public Fruit(String aColour, Date aBestBeforeDate) { super(); fColour = aColour; //defensive copy needed for this mutable object fBestBeforeDate = new Date(aBestBeforeDate.getTime()); } public abstract void ripen(); public String getColour() { return fColour; } public Date getBestBeforeDate() { //return defensive copy of this mutable object return new Date(fBestBeforeDate.getTime()); } /** * Implement clone as follows * <ul> * <li>the class declaration "implements Cloneable" (not needed if already * declared in superclass) * <li>declare clone method as public * <li>if the class is final, clone does not need to throw CloneNotSupportedException * <li>call super.clone and cast to this class * <li>as in defensive copying, ensure each mutable field has an independent copy * constructed, to avoid sharing internal state between objects * </ul> */ @Override public Object clone() throws CloneNotSupportedException { //get initial bit-by-bit copy, which handles all immutable fields Fruit result = (Fruit)super.clone(); //mutable fields need to be made independent of this object, for reasons //similar to those for defensive copies - to prevent unwanted access to //this object's internal state result.fBestBeforeDate = new Date(this.fBestBeforeDate.getTime()); return result; } // PRIVATE /** * Strings are always immutable. */ private String fColour; /** * Date is a mutable object. In this class, this object field is to be treated * as belonging entirely to this class, and no user of this class is * to be able to directly access and change this field's state. */ private Date fBestBeforeDate; }
Here is the subclass, with its clone method disabled.
import java.util.Date; public final class Apple extends Fruit { public Apple(String aColour, Date aBestBeforeDate) { super(aColour, aBestBeforeDate); } public void ripen() { //empty implementation of abstract method } /** * The Apple subclass does not support clone. */ @Override public final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }
Factory methodsFactory methods are static methods that return an instance of the native class. Examples in the JDK:
Factory methods:
- LogManager.getLogManager
- Pattern.compile
- Collections.unmodifiableCollection, Collections.synchronizeCollection , and so on
- Calendar.getInstance
Common names for factory methods include getInstance and valueOf. These names are not mandatory - choose whatever makes sense for each case.Example
- have names, unlike constructors, which can clarify code.
- do not need to create a new object upon each invocation - objects can be cached and reused, if necessary.
- can return a subtype of their return type - in particular, can return an object whose implementation class is unknown to the caller.This is a very valuable and widely used feature in many frameworks which use interfaces as the return type of static factory methods.
public final class ComplexNumber { /** * Static factory method returns an object of this class. */ public static ComplexNumber valueOf(float aReal, float aImaginary) { return new ComplexNumber(aReal, aImaginary); } /** * Caller cannot see this private constructor. * * The only way to build a ComplexNumber is by calling the static * factory method. */ private ComplexNumber(float aReal, float aImaginary) { fReal = aReal; fImaginary = aImaginary; } private float fReal; private float fImaginary; //..elided }
Avoid cloneAvoid implementing clone.If you need to extend a superclass that implements clone, then your subclass must implement clone as well. The quickest solution is for your subclass to simply throw an exception.Example
- clone is very tricky to implement correctly in all circumstances, nearly to the point of being pathological
- the importance of copying objects will always remain, since object fields often need to be defensively copied
- copy constructors and static factory methods provide an alternative to clone, and are much easier to implement
This example shows a superclass with a typical implementation of clone, and a subclass which has disabled its clone method.
import java.util.Date; public abstract class Fruit implements Cloneable { public Fruit(String aColour, Date aBestBeforeDate) { super(); fColour = aColour; //defensive copy needed for this mutable object fBestBeforeDate = new Date(aBestBeforeDate.getTime()); } public abstract void ripen(); public String getColour() { return fColour; } public Date getBestBeforeDate() { //return defensive copy of this mutable object return new Date(fBestBeforeDate.getTime()); } /** * Implement clone as follows * <ul> * <li>the class declaration "implements Cloneable" (not needed if already * declared in superclass) * <li>declare clone method as public * <li>if the class is final, clone does not need to throw CloneNotSupportedException * <li>call super.clone and cast to this class * <li>as in defensive copying, ensure each mutable field has an independent copy * constructed, to avoid sharing internal state between objects * </ul> */ @Override public Object clone() throws CloneNotSupportedException { //get initial bit-by-bit copy, which handles all immutable fields Fruit result = (Fruit)super.clone(); //mutable fields need to be made independent of this object, for reasons //similar to those for defensive copies - to prevent unwanted access to //this object's internal state result.fBestBeforeDate = new Date(this.fBestBeforeDate.getTime()); return result; } // PRIVATE /** * Strings are always immutable. */ private String fColour; /** * Date is a mutable object. In this class, this object field is to be treated * as belonging entirely to this class, and no user of this class is * to be able to directly access and change this field's state. */ private Date fBestBeforeDate; }Here is the subclass, with its clone method disabled.import java.util.Date; public final class Apple extends Fruit { public Apple(String aColour, Date aBestBeforeDate) { super(aColour, aBestBeforeDate); } public void ripen() { //empty implementation of abstract method } /** * The Apple subclass does not support clone. */ @Override public final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }
No comments:
Post a Comment