String is immutable for several reasons, here is a summary:
- Security: parameters are typically represented as
Stringin network connections, database connection urls, usernames/passwords etc. If it were mutable, these parameters could be easily changed. - Synchronization and concurrency: making String immutable automatically makes them thread safe thereby solving the synchronization issues.
- Caching: when compiler optimizes your String objects, it sees that if two objects have same value (a="test", and b="test") and thus you need only one string object (for both a and b, these two will point to the same object).
- Class loading:
Stringis used as arguments for class loading. If mutable, it could result in wrong class being loaded (because mutable objects change their state).
That being said, immutability of String only means you cannot change it using its public API. You can in fact bypass the normal API using reflection. See the answer here.
In your example, if String was mutable, then consider the following example:
String a="stack";
System.out.println(a);//prints stack
a.setValue("overflow");
System.out.println(a);//if mutable it would print overflow
Answer from user508434 on Stack OverflowString is immutable for several reasons, here is a summary:
- Security: parameters are typically represented as
Stringin network connections, database connection urls, usernames/passwords etc. If it were mutable, these parameters could be easily changed. - Synchronization and concurrency: making String immutable automatically makes them thread safe thereby solving the synchronization issues.
- Caching: when compiler optimizes your String objects, it sees that if two objects have same value (a="test", and b="test") and thus you need only one string object (for both a and b, these two will point to the same object).
- Class loading:
Stringis used as arguments for class loading. If mutable, it could result in wrong class being loaded (because mutable objects change their state).
That being said, immutability of String only means you cannot change it using its public API. You can in fact bypass the normal API using reflection. See the answer here.
In your example, if String was mutable, then consider the following example:
String a="stack";
System.out.println(a);//prints stack
a.setValue("overflow");
System.out.println(a);//if mutable it would print overflow
Java Developers decide Strings are immutable due to the following aspect design, efficiency, and security.
Design Strings are created in a special memory area in java heap known as "String Intern pool". While you creating new String (Not in the case of using String() constructor or any other String functions which internally use the String() constructor for creating a new String object; String() constructor always create new string constant in the pool unless we call the method intern()) variable it searches the pool to check whether is it already exist. If it is exist, then return reference of the existing String object. If the String is not immutable, changing the String with one reference will lead to the wrong value for the other references.
According to this article on DZone:
Security String is widely used as parameter for many java classes, e.g. network connection, opening files, etc. Were String not immutable, a connection or file would be changed and lead to serious security threat. Mutable strings could cause security problem in Reflection too, as the parameters are strings.
Efficiency The hashcode of string is frequently used in Java. For example, in a HashMap. Being immutable guarantees that hashcode will always the same, so that it can be cached without worrying the changes.That means, there is no need to calculate hashcode every time it is used.
So, I'm a little confused by this tutorial. It says that Strings are "immutable" and should only be used if they're going to be constant throughout the program. Otherwise, use StringBuilder/StringBuffer.
I don't understand. This concept might be too abstract for me to grasp yet.
Given a string String s = "foo"; I want to write a program that will append s to "foobar".
According to the tutorial, this method is no good because it doesn't change the original string s1.
public static void concat(String s){
s = s + "bar";
}Therefore, to change a string, I should use StringBuilder or StringBuffer
public static void concat(StringBuffer s){
s.append("bar");
}But why just do this?
public static String concat(String s){
return s + "bar";
}We are changing the value of the original string this way, so how is a String still "immutable"?
programming languages - Why is String immutable in Java? - Software Engineering Stack Exchange
java - String is immutable. What exactly is the meaning? - Stack Overflow
What does it mean when they say that a String is "immutable"?
What does 'Strings are immutable' mean?
Videos
Concurrency
Java was defined from the start with considerations of concurrency. As often been mentioned shared mutables are problematic. One thing can change another behind the back of another thread without that thread being aware of it.
There are a host of multithreaded C++ bugs that have croped up because of a shared string - where one module thought it was safe to change when another module in the code had saved a pointer to it and expected it to stay the same.
The 'solution' to this is that every class makes a defensive copy of the mutable objects that are passed to it. For mutable strings, this is O(n) to make the copy. For immutable strings, making a copy is O(1) because it isn't a copy, its the same object that can't change.
In a multithreaded environment, immutable objects can always be safely shared between each other. This leads to an overall reduction in memory usage and improves memory caching.
Security
Many times strings are passed around as arguments to constructors - network connections and protocals are the two that most easily come to mind. Being able to change this at an undetermined time later in the execution can lead to security issues (the function thought it was connecting to one machine, but was diverted to another, but everything in the object looks like it connected to the first... its even the same string).
Java lets one use reflection - and the parameters for this are strings. The danger of one passing a string that can get modified through the way to another method that reflects. This is very bad.
Keys to the Hash
The hash table is one of the most used data structures. The keys to the data structure are very often strings. Having immutable strings means that (as above) the hash table does not need to make a copy of the hash key each time. If strings were mutable, and the hash table didn't make this, it would be possible for something to change the hash key at a distance.
The way the Object in java works, is that everything has a hash key (accessed via the hashCode() method). Having an immutable string means that the hashCode can be cached. Considering how often Strings are used as keys to a hash, this provides a significant performance boost (rather than having to recalculate the hash code each time).
Substrings
By having the String be immutable, the underlying character array that backs the data structure is also immutable. This allows for certain optimizations on the substring method the be done (they aren't necessarily done - it also introduces the possibility of some memory leaks too).
If you do:
String foo = "smiles";
String bar = foo.substring(1,5);
The value of bar is 'mile'. However, both foo and bar can be backed by the same character array, reducing the instantiation of more character arrays or copying it - just using different start and end points within the string.
foo | | (0, 6)
v v
smiles
^ ^
bar | | (1, 5)
Now, the downside of that (the memory leak) is that if one had a 1k long string and took the substring of the first and second character, it would also be backed by the 1k long character array. This array would remain in memory even if the original string that had a value of the entire character array was garbage collected.
One can see this in String from JDK 6b14 (the following code is from a GPL v2 source and used as an example)
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.offset = 0;
this.count = count;
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
Note how the substring uses the package level String constructor that doesn't involve any copying of the array and would be much faster (at the expense of possibly keeping around some large arrays - though not duplicating large arrays either).
Do note that the above code is for Java 1.6. The way the substring constructor is implemented was changed with Java 1.7 as documented in Changes to String internal representation made in Java 1.7.0_06
- the issue bing that memory leak that I mentioned above. Java likely wasn't seen as being a language with lots of String manipulation and so the performance boost for a substring was a good thing. Now, with huge XML documents stored in strings that are never collected, this becomes an issue... and thus the change to the String not using the same underlying array with a substring, so that the larger character array may be collected more quickly.
Don't abuse the Stack
One could pass the value of the string around instead of the reference to the immutable string to avoid issues with mutability. However, with large strings, passing this on the stack would be... abusive to the system (putting entire xml documents as strings on the stack and then taking them off or continuing to pass them along...).
The possibility of deduplication
Granted, this wasn't an initial motivation for why Strings should be immutable, but when one is looking at the rational of why immutable Strings are a good thing, this is certainly something to consider.
Anyone who has worked with Strings a bit knows that they can suck memory. This is especially true when you're doing things like pulling data from databases that sticks around for awhile. Many times with these stings, they are the same string over and over again (once for each row).
Many large-scale Java applications are currently bottlenecked on memory. Measurements have shown that roughly 25% of the Java heap live data set in these types of applications is consumed by String objects. Further, roughly half of those String objects are duplicates, where duplicates means string1.equals(string2) is true. Having duplicate String objects on the heap is, essentially, just a waste of memory. ...
With Java 8 update 20, JEP 192 (motivation quoted above) is being implemented to address this. Without getting into the details of how string deduplication works, it is essential that the Strings themselves are immutable. You can't deduplicate StringBuilders because they can change and you don't want someone changing something from under you. Immutable Strings (related to that String pool) means that you can go through and if you find two strings that are the same, you can point one string reference to the other and let the garbage collector consume the newly unused one.
Other languages
Objective C (which predates Java) has NSString and NSMutableString.
C# and .NET made the same design choices of the default string being an immutable.
Lua strings are also immutable.
Python as well.
Historically, Lisp, Scheme, Smalltalk all intern the string and thus have it be immutable. More modern dynamic languages often use strings in some way that requires that they be immutable (it may not be a String, but it is immutable).
Conclusion
These design considerations have been made again and again in a multitude of languages. It is the general consensus that immutable strings, for all of their awkwardness, are better than the alternatives and lead to better code (fewer bugs) and faster executables overall.
Reasons I can recall :
String Pool facility without making string immutable is not possible at all because in case of string pool one string object/literal e.g. "XYZ" will be referenced by many reference variables , so if any one of them changes the value others will be automatically gets affected .
String has been widely used as parameter for many java classes e.g. for opening network connection , for opening database connection, opening files . If String is not immutable, this would lead to serious security threat .
Immutability allows String to cache its hashcode.
Makes it thread-safe .
Before proceeding further with the fuss of immutability, let's just take a look into the String class and its functionality a little before coming to any conclusion.
This is how String works:
String str = "knowledge";
This, as usual, creates a string containing "knowledge" and assigns it a reference str. Simple enough? Lets perform some more functions:
String s = str; // assigns a new reference to the same string "knowledge"
Lets see how the below statement works:
str = str.concat(" base");
This appends a string " base" to str. But wait, how is this possible, since String objects are immutable? Well to your surprise, it is.
When the above statement is executed, the VM takes the value of String str, i.e. "knowledge" and appends " base", giving us the value "knowledge base". Now, since Strings are immutable, the VM can't assign this value to str, so it creates a new String object, gives it a value "knowledge base", and gives it a reference str.
An important point to note here is that, while the String object is immutable, its reference variable is not. So that's why, in the above example, the reference was made to refer to a newly formed String object.
At this point in the example above, we have two String objects: the first one we created with value "knowledge", pointed to by s, and the second one "knowledge base", pointed to by str. But, technically, we have three String objects, the third one being the literal "base" in the concat statement.
Important Facts about String and Memory usage
What if we didn't have another reference s to "knowledge"? We would have lost that String. However, it still would have existed, but would be considered lost due to having no references.
Look at one more example below
String s1 = "java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1); // Yes, s1 still refers to "java"
What's happening:
- The first line is pretty straightforward: create a new
String"java"and refers1to it. - Next, the VM creates another new
String"java rules", but nothing refers to it. So, the secondStringis instantly lost. We can't reach it.
The reference variable s1 still refers to the original String "java".
Almost every method, applied to a String object in order to modify it, creates new String object. So, where do these String objects go? Well, these exist in memory, and one of the key goals of any programming language is to make efficient use of memory.
As applications grow, it's very common for String literals to occupy large area of memory, which can even cause redundancy. So, in order to make Java more efficient, the JVM sets aside a special area of memory called the "String constant pool".
When the compiler sees a String literal, it looks for the String in the pool. If a match is found, the reference to the new literal is directed to the existing String and no new String object is created. The existing String simply has one more reference. Here comes the point of making String objects immutable:
In the String constant pool, a String object is likely to have one or many references. If several references point to same String without even knowing it, it would be bad if one of the references modified that String value. That's why String objects are immutable.
Well, now you could say, what if someone overrides the functionality of String class? That's the reason that the String class is marked final so that nobody can override the behavior of its methods.
String is immutable means that you cannot change the object itself, but you can change the reference to the object.
When you execute a = "ty", you are actually changing the reference of a to a new object created by the String literal "ty".
Changing an object means to use its methods to change one of its fields (or the fields are public and not final, so that they can be updated from outside without accessing them via methods), for example:
Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"
While in an immutable class (declared as final, to prevent modification via inheritance)(its methods cannot modify its fields, and also the fields are always private and recommended to be final), for example String, you cannot change the current String but you can return a new String, i.e:
String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"