Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Mutable or immutable?

Techniques for defensive programming

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone

Page 2 of 2

Mutable class with a convert-to-immutable-version method

The previous pattern is suitable for read-only data whose usage is short-lived (e.g., scoped to a method). It trades efficiency for a weaker form of immutability: changes in the underlying data remain visible to the client code. For stronger immutability, I can do the following: create an immutable class with a toImmutable() method that locks in the data by returning a copy of it. Consider these two classes implementing a simplified version of a sorted int vector:

package vector;
public class SortedVector
{
    public SortedVector (int capacity)
    {
        m_data = new int [capacity];
    }
    
    // ACCESSORS: [all methods are final]
    
    public final int size ()
    {
        return m_size;
    }
    public final int get (int index)
    {
        return m_data [index];
    }
    
    // package-private constructor:    
    SortedVector (MutableSortedVector item)
    {
        // Note: 'm_data' array is not cloned here and is rather shared
        // by reference with the original MutableSortedVector until
        // the next MutableSortedVector mutator method is invoked [if ever]
        
        m_data = item.m_data;
        m_size = item.m_size;
    }
    
    int [] m_data;
    int m_size;
}
package vector;
public final class MutableSortedVector extends SortedVector
{
    public MutableSortedVector (int capacity)
    {
        super (capacity);
    }
    public SortedVector toImmutable ()
    {
        m_shared = true; // set 'shared' flag
        return new SortedVector (this);
    }
    
    // MUTATORS:
    // Add a new value; keep them in increasing order:
    public void add (int value)
    {
        // [This simple implementation is O(size) and is used for
        // illustrative purposes only]
        
        if (m_size == m_data.length)
            throw new IllegalStateException ("maximum capacity reached");
        // If the data array is shared, it must be cloned before we can
        // proceed [copy-on-write]:
        if (m_shared)
        {
            m_data = (int []) m_data.clone ();
            m_shared = false; // reset 'shared' flag
        }               
        
        // Insert the new value after a simple linear scan:        
        int position;    
        for (position = 0; position < m_size; ++ position)
        {
            if (m_data [position] > value) break;
        }
        
        if (position < m_size)
            System.arraycopy (m_data, position,
                              m_data, position + 1, m_size - position);
            
        m_data [position] = value;
        ++ m_size;
    }
    
    private boolean m_shared; // if 'true', next mutator call must clone data
}


Even though both classes are public, observe how toImmutable() relies on a special package-private constructor provided by SortedVector for MutableSortedVector and nobody else. Implementing such conversion methods usually implies extra data copying and extra performance hits. But if I know that the mutable instance will always be discarded right after it has been converted, I can simply pass pieces of the internal MutableSortedVector state to the SortedVector constructor by reference to reduce overhead. Being certain of this knowledge is generally difficult, however, so I handle the issue using a traditional compromise technique called copy-on-write. Observe carefully how the mutator and toImmutable() methods use the m_shared flag to copy data only when necessary.

The implementation technique outlined above is much like the one used by String and StringBuffer companion classes in the standard Java implementation, except that the mutable StringBuffer is not an extension of the immutable String.

About the author

Vladimir Roubtsov has programmed in a variety of languages for more than 12 years, including Java since 1995. Currently, he develops enterprise software as a senior developer for Trilogy in Austin, Texas.
  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources