欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Item 15: Minimize mutability

程序员文章站 2022-07-13 09:14:36
...

1.  The Java platform libraries contain many immutable classes, including String, the boxed primitive classes, and BigInteger and BigDecimal.

 

2.  Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.

 

3.  To make a class immutable:
    a)  Don’t provide any methods that modify the object’s state (known as mutators).
    b)  Ensure that the class can’t be extended.
    c)  Make all fields final.
    d)  Make all fields private.
    e)  Ensure exclusive access to any mutable components. Make defensive copies in constructors, accessors, and readObject methods for those fields that refer to mutable objects.

Commented By Sean: Why readObject ? If all others accesses are exclusive , is it possible to have multiple reference to the same mutable components serialized in the stream?

 

4.  Immutable objects are simple. An immutable object can be in exactly one state, the state in which it was created.


5.  Immutable objects are inherently thread-safe; they require no synchronization and can be shared freely.

 

6.  An immutable class can provide static factories that cache frequently requested instances to avoid creating new instances when existing ones would do. All the boxed primitive classes and BigInteger do this.

 

7.  Opting for static factories in place of public constructors when designing a new class gives you the flexibility to add caching later, without modifying clients.

 

8.  You never have to make defensive copies. Therefore, you need not and should not provide a clone method or copy constructor on an immutable class.

 

9.  Not only can you share immutable objects, but you can share their internals. i.e. BigInteger.negate shares its internal magnitude representation ( int array) and String.substring shares its internal char array.

 

10.  Immutable objects make great building blocks for other objects. It’s much easier to maintain the invariants of a complex object if you know that its component objects will not change underneath it. (i.e. map keys and set elements).


11.  The only real disadvantage of immutable classes is that they require a separate object for each distinct value. Creating these objects can be costly, especially if they are large.

 

12.  The performance problem is magnified if you perform a multistep operation that generates a new object at every step, eventually discarding all objects except the final result. The approach is to guess which multistep operations will be commonly required and provide them as primitives. If a multistep operation is provided as a primitive, the immutable class does not have to create a separate object at each step. Or you can provide a public mutable companion class.(i.e. StringBuilder for String and BitSet for BigInteger)

 

13.  The alternative to making an immutable class final is to make all of its constructors private or package-private, and to add public static factories in place of the public constructors.

 

14.  If you write a class whose security depends on the immutability of a BigInteger or BigDecimal argument from an untrusted client, you must check to see that the argument is a “real” BigInteger or BigDecimal, rather than an instance of an untrusted subclass. If it is the latter, you must defensively copy it under the assumption that it might be mutable, because they are not final.

 

15.  In truth, no method may produce an externally visible change in the object’s state. Some immutable classes have one or more non-final fields in which they cache the results of expensive computations the first time they are needed. (i.e. the hash field of String)

 

16.  If you choose to have your immutable class implement Serializable and it contains one or more fields that refer to mutable objects, you must provide an explicit readObject or readResolve method, or use the ObjectOutputStream.writeUnshared and ObjectInputStream.readUnshared methods, even if the default serialized form is acceptable. Otherwise an attacker could create a mutable instance of your not quite-immutable class.

 

17.  In summary, classes should be immutable unless there’s a very good reason to make them mutable. Immutable classes provide many advantages, and their only disadvantage is the potential for performance problems under certain circumstances. If a class cannot be made immutable, limit its mutability as much as possible. Make every field final unless there is a compelling reason to make it non-final.