tags:

views:

2090

answers:

12

This could be the dumbest question ever asked but I think it is a total confusion for a newbie. Can somebody clarify what is meant by immutable? Why is a String immutable? What are the advantages/disadvantages of immutable objects? Why should a mutable object such as StringBuilder be preferred over String and vice-versa? A nice example (in Java) will be appreciated.

+1  A: 

Once instanciated, cannot be altered. Consider a class that an instance of might be used as the key for a hashtable or similar. Check out Java best practices.

stjohnroe
A: 

Immutable means that once the object is created, non of its members will change. String is immutable since you can not change its content. For example: String s1 = " abc "; String s2 = s1.trim(); In the code above, the string s1 did not change, another object (s2) was created using s1.

eishay
A: 

"immutable" means you cannot change value. If you have an instance of String class, any method you call which seems to modify the value, will actually create another String.

String foo = "Hello";
foo.substring(3);
<-- foo here still has the same value "Hello"

To preserve changes you should do something like this foo = foo.sustring(3);

Immutable vs mutable can be funny when you work with collections. Think about what will happen if you use mutable object as a key for map and then change the value (tip: think about equals and hasCode).

Georgy Bolyuba
+2  A: 

One meaning has to do with how the value is stored in the computer, For a .Net string for example, it means that the string in memory cannot be changed, When you think you're changing it, you are in fact creating a new string in memory and pointing the existing variable (which is just a pointer to the actual collection of characters somewhere else) to the new string.

Charles Bretana
+22  A: 

Immutable means that once an object of that Class has been created it can't be altered.

This is useful as it means you can pass references to the object around, without worrying that someone else is going to change it's contents.

e.g.

class Foo
{
     private String myvar;

     public Foo(String initialValue)
     {
         this.myvar = initialValue;
     }

     public String getValue()
     {
         return this.myvar;
     }
}

Foo doesn't have to worry that the caller to getValue() might change the text in the string.

If you imagine a similar class to Foo, but with a StringBuilder rather than a String as a member, you can see that a caller to getValue() would be able to alter the StringBuilder attribute of a Foo instance.

Edit:

Also beware of the different kinds of immutability you might find: Eric Lippert wrote a blog article about this. Basically you can have objects whose interface is immutable but behind the scenes actual mutables private state (and therefore can't be shared safely between threads).

Douglas Leeder
I think you should add a one arg constructor to assign value at least once. The point of current code is not clear since there is no value to change really :).
Georgy Bolyuba
You're right, I've added a constructor.
Douglas Leeder
You should make the field readonly. It makes it completely explicit that the field is immutable. Right now it's immutable by convention
JaredPar
This answer is good. But to clarify more, it doesn't mean that you can't set your variable to another instance of an immutable type (a-la const). It just means that the instance itself can't be modified.
OJ
The member myVar should be final for this to be truly immutable.
laz
I don't think final actually adds anything - from outside the class (even subclasses) the myVar can't be pointed at a different String, and String is itself immutable.
Douglas Leeder
You are correct that myVar isn't accessible outside of Foo. However, the presence of final indicates to anyone that may be modifying the class in the future that its value isn't meant to change. I tend to favor being as explicit as possible in such circumstances.
laz
IIRC using `final` has some advantages in the Java memory model as well (I don't have a source for this right now though).
Grundlefleck
+4  A: 

Immutable objects are objects that can't be changed programmatically. They're especially good for multi-threaded environments or other environments where more than one process is able to alter (mutate) the values in an object.

Just to clarify, however, StringBuilder is actually a mutable object, not an immutable one. A regular java String is immutable (meaning that once it's been created you cannot change the underlying string without changing the object).

For example, let's say that I have a class called ColoredString that has a String value and a String color:

public class ColoredString {

    private String color;
    private String string;

    public ColoredString(String color, String string) {
     this.color  = color;
     this.string = string;
    }

    public String getColor()  { return this.color;  }
    public String getString() { return this.string; }

    public void setColor(String newColor) {
     this.color = newColor;
    }

}

In this example, the ColoredString is said to be mutable because you can change (mutate) one of its key properties without creating a new ColoredString class. The reason why this may be bad is, for example, let's say you have a GUI application which has multiple threads and you are using ColoredStrings to print data to the window. If you have an instance of ColoredString which was created as

new ColoredString("Blue", "This is a blue string!");

Then you would expect the string to always be "Blue". If another thread, however, got ahold of this instance and called

blueString.setColor("Red");

You would suddenly, and probably unexpectedly, now have a "Red" string when you wanted a "Blue" one. Because of this, immutable objects are almost always preferred when passing instances of objects around. When you have a case where mutable objects are really necessary, then you would typically guard the objet by only passing copies out from your specific field of control.

To recap, in Java, java.lang.String is an immutable object (it cannot be changed once it's created) and java.lang.StringBuilder is a mutable object because it can be changed without creating a new instance.

Jason Coco
You should make the fields readonly. Right now your class is immutable by convention. There is no indication to future developers tha the immutable is intentional. Making the fields readonly will help clarify your intention to a future dev
JaredPar
@JaredPar - Actually, the class is not immutable at all... it's an example of a mutable class to demonstrate why it may be an issue.
Jason Coco
I'm an idiot. I got on a readonly rant :(
JaredPar
@JaredPar - Oh, that's totally okay :) I was gonna rewrite it a bit to be more clear, but Douglas's is already well written and seems to be the favorite, so I'll just leave mine as another example; but somebody did actually edit it to make the properties final which I thought was amusing :)
Jason Coco
+2  A: 

I really like the explaination from SCJP Sun Certified Programmer for Java 5 Study Guide.

To make Java more memory efficient, the JVM sets aside a special area of memory called the "String constant pool." When the compiler encounters a String literal, it checks the pool to see if an identical String already exists. If a match is found, the reference to the new literal is directed to the existing String, and no new String literal object is created.

logoin
It should be able to do this with any identical immutable objects, but I suppose that would take too much runtime.
Zan Lynx
A: 

An immutable object is the one you cannot modify after you create it. A typical example are string literals.

A D programming language, which becomes increasingly popular, has a notion of "immutability" through "invariant" keyword. Check this Dr.Dobb's article about it - http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=Invariant-Strings.html&amp;Itemid=29 . It explains the problem perfectly.

I do believe that as of D 2.020 the keyword was changed from invariant to immutable. I don't see a point, but it does say, "immutable now is implemented."http://digitalmars.com/d/2.0/changelog.html#new2_020
he_the_great
A: 

Instead of giving a programmers answer, here's some grammar

to mutate == to change

adding "im-" to a word means that it is not so or not possible

therefor: immutable === unchangeable.

an immutable string is a string of which you cannot modify the content.

in Java, this is done via the keyword final

e.g.: public final string HELLO = "hello";

trying this: HELLO = "bye"; will not compile.

Vordreller
This isn't really an explanation of an immutable object (although String is immutable in Java), it's a demonstration of a constant reference. You could do this with my mutable class example above and still have serious issues in a multi-threaded environment.
Jason Coco
A: 

Objects which are immutable can not have their state changed after they have been created.

There are three main reasons to use immutable objects whenever you can, all of which will help to reduce the number of bugs you introduce in your code:

  • It is much easier to reason about how your program works when you know that an object's state cannot be changed by another method
  • Immutable objects are automatically thread safe (assuming they are published safely) so will never be the cause of those hard-to-pin-down multithreading bugs
  • Immutable objects will always have the same Hash code, so they can be used as the keys in a HashMap (or similar). If the hash code of an element in a hash table was to change, the table entry would then effectively be lost, since attempts to find it in the table would end up looking in the wrong place. This is the main reason that String objects are immutable - they are frequently used as HashMap keys.

There are also some other optimisations you might be able to make in code when you know that the state of an object is immutable - caching the calculated hash, for example - but these are optimisations and therefore not nearly so interesting.

Bill Michell
+4  A: 

Actually String is not immutable if you use the wikipedia definition suggested above.

String's state does change post construction. Take a look at the hashcode() method. String caches the hashcode value in a local field but does not calculate it until the first call of hashcode(). This lazy evaluation of hashcode places String in an interesting position as an immutable object whose state changes, but it cannot be observed to have changed without using reflection.

So maybe the definition of immutable should be an object that cannot be observed to have changed.

If the state changes in an immutable object after it has been created but no-one can see it (without reflection) is the object still immutable?

Good idea - an object that cannot be observed to have changed, as well as, no way to change it from the outside. The private field for hashCode() is an internal change that is not material to the externally visible state of the object.
mparaz
Upvote for taoist saying.
Imagist
+3  A: 

An immutable object is an object where the internal fields (or at least, all the internal fields that affect its external behavior) cannot be changed.

There are a lot of advantages to immutable strings:

Performance: Take the following operation:

String substring = fullstring.substring(x,y);

The underlying C for the substring() method is probably something like this:

// Assume string is stored like this:
struct String { char* characters; unsigned int length; };

// Passing pointers because Java is pass-by-reference
struct String* substring(struct String* in, unsigned int begin, unsigned int end)
{
    struct String* out = malloc(sizeof(struct String));
    out->characters = in->characters + begin;
    out->length = end - begin;
    return out;
}

Note that none of the characters have to be copied! If the String object were mutable (the characters could change later) then you would have to copy all the characters, otherwise changes to characters in the substring would be reflected in the other string later.

Concurrency: If the internal structure of an immutable object is valid, it will always be valid. There's no chance that different threads can create an invalid state within that object.

Garbage collection: It's much easier for the garbage collector to make logical decisions about immutable objects.

However, there are also downsides to immutability:

Performance: Wait, I thought you said performance was an upside of immutability! Well, it is sometimes, but not always. Take the following code:

foo = foo.substring(0,4) + "a" + foo.substring(5);  // foo is a String
bar.replace(4,5,"a"); // bar is a StringBuilder

The two lines both replace the fourth character with the letter "a". Not only is the second piece of code more readable, it's faster. Look at how you would have to do the underlying code for foo. The substrings are easy, but now because there's already a character at space five and something else might be referencing foo, you can't just change it; you have to copy the whole string (of course some of this functionality is abstracted into functions in the real underlying C, but the point here is to show the code that gets executed all in one place).

struct String* concatenate(struct String* first, struct String* second)
{
    struct String* new = malloc(sizeof(struct String));
    new->length = first->length + second->length;

    new->characters = malloc(new->length);

    int i;

    for(i = 0; i < first->length; i++)
        new->characters[i] = first->characters[i];

    for(; i - first->length < second->length; i++)
        new->characters[i] = second->characters[i - first->length];

    return new;
}

// The code that executes
struct String* astring;
char a = 'a';
astring->characters = &a;
astring->length = 1;
foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length));

Note that concatenate gets called twice meaning that the entire string has to be looped through! Compare this to the C code for the bar operation:

bar->characters[4] = 'a';

The mutable string operation is obviously much faster.

In Conclusion: In most cases, you want an immutable string. But if you need to do a lot of appending and inserting into a string, you need the mutability for speed. If you want the concurrency safety and garbage collection benefits with it the key is to keep your mutable objects local to a method:

// This will have awful performance if you don't use mutable strings
String join(String[] strings, String separator)
{
    StringBuilder mutable;
    boolean first = true;

    for(int i = 0; i < strings.length; i++)
    {
        if(!first) first = false;
        else mutable.append(separator);

        mutable.append(strings[i]);
    }

    return mutable.toString();
}

Since the mutable object is a local reference, you don't have to worry about concurrency safety (only one thread ever touches it). And since it isn't referenced anywhere else, it is only allocated on the stack, so it is deallocated as soon as the function call is finished (you don't have to worry about garbage collection). And you get all the performance benefits of both mutability and immutability.

Imagist