3

I know that by default, String varaibles are immutable in Java. But is there some way to set a String variable, or some special way (when passing said String variable) to make it mutable?

Or at least temporarily allow that Stirng to be changed?

I realize that I can change the value of a String by just assigning the modified immutable variable to the original variable, like show:

String A = "Test";
A.toUpperCase(); //will make A upper case, but not save the new upper case string to a variable
Sring A = A.toUpperCase; //will give me TEST and save it to A, replacing A

Is there some way to tell Java "Hey, for this one String specifically, treat it as mutable"?

  • 1
    `A.toUpperCase` isn't valid Java, you need `()` for method calls. – kviiri Aug 13 '14 at 19:47
  • Depending on your exact requirements, you could just use char arrays which are mutable. – Micah Smith Aug 13 '14 at 19:47
  • 1
    If you could, String wouldn't be immutable anymore, and you would thus lose all the guarantees that an immutable String offers. – JB Nizet Aug 13 '14 at 19:47
  • 1
    See http://stackoverflow.com/questions/11146255/create-a-mutable-java-lang-string – Pankaj Sharma Aug 13 '14 at 19:47
  • Even if that was possible, how do you expect to change the string inside the function? – tcooc Aug 13 '14 at 19:48
  • @KashifNazar: no, you can't. String is final. – JB Nizet Aug 13 '14 at 19:48
  • @JB Nizet Sorry to be nitpicky, but is `final` *completely* interchangable with the term `immutable`? –  Aug 13 '14 at 20:01
  • final doesn't guarantee immutability, but if all fields are final and no setters are exposed, then the class is final then the object is immutable. in the case of string, it is immutable. – Jeff Storey Aug 13 '14 at 20:04
  • No. There isn't any way to do that. You cannot change the behavior of String's methods and cannot even overwrite those. Why do you need to do that? – Kashif Nazar Aug 13 '14 at 20:05
  • @JBNizet - Thanks for correcting. That was a typo. – Kashif Nazar Aug 13 '14 at 20:06
  • @AdamJ: not at all. A final class may be mutable. The comment of Kashif initially said (it was a typo) that you could overwrite (i.e. override) the methods of String. And that is not possible because String is final. – JB Nizet Aug 13 '14 at 20:44
  • Ahh thanks for that clarification @Jeff Storey –  Aug 13 '14 at 20:45

6 Answers6

8

No. Strings are immutable.

You should either create your own mutable structure that wraps a string or a char array if you need to, or using something like a StringBuilder if that will suit your needs.

Jeff Storey
  • 56,312
  • 72
  • 233
  • 406
  • So an Array of Strings is in fact mutable? So, for example, if I have a `String [][] A`, asssuming it's filled with great Strings detailing the meaning of life, can I perform `a[0].toUpperCase()`, and permanantly change the value of a[0] from whatever it was set to, to all caps? –  Aug 13 '14 at 19:51
  • @AdamJ You can do `a[0] = a[0].toUpperCase();` which would replace the String in a[0]. – Powerlord Aug 13 '14 at 19:53
  • 1
    No. You would need to reassign `a[0] = a[0].toUpperCase();` – Jeff Storey Aug 13 '14 at 19:53
  • I'm sorry, I don't how is that different form my original example? It appears to me that the String at index 0 of the Array is still immutable, if I have to reassign the upper case value to overwrite the previous value and essentialy "save my changes" –  Aug 13 '14 at 19:59
  • Yes, you are correct. You would need another structure that wraps either a string or a char array and that would do the assignment internally so a client could call toUpperCase on your object, but the strings will still be immutable. – Jeff Storey Aug 13 '14 at 20:03
  • Thanks for all your help @Jeff Storey. One last request though: could you add a very basic example of using StringBuilder to your answer? –  Aug 13 '14 at 20:47
  • No problem. give it a try on your own first with string builder. Have a look at the setCharAt method that lets you modify the characters http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html#setCharAt(int,%20char) – Jeff Storey Aug 13 '14 at 20:52
4

Nope, the class String is immutable in java. In order to do this you can create class:

public class MutableString {

    private String str;

    public MutableString(String str) {
        this.str = str;
    }

    public void toUpperCase() {
        str = str.toUpperCase();
    }

    public String toString() {
        return str;
    }

}

The feasibility of this technique depends on the number of methods you need from String.

enrico.bacis
  • 30,497
  • 10
  • 86
  • 115
4

String variables are mutable in Java. String objects are not mutable.

However, method arguments are passed by value, not by reference. So you can't return a value for a String through a reference parameter.

For example, you can do this, because a is a mutable variable -- pointing first to one immutable String object, then another.

 String a = "Test";
 a = a.toUpperCase(); 

And you can do this:

  public void myfunction( String a ) {
     a = a.toUppercase
  }

But this caller will not observe a change to its own variable, because the actual and formal arguments are two different variables.

  public void mycaller() {
      String actual = "test";
      myfunction( actual );
      System.out.println( actual ); // Prints "test"
  }

What you could do is:

  • Return the String from the method.
  • Return from the method a results object that includes the String.
  • Make your own class MyMutableString, which contains a mutable reference to a String.
  • Pass a String[] array with one element.

If you have multiple values to return, consider the second option - return an object that encapsulates the method results. If you have a single value to return, just return it. The other options are less frequently useful.

Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
2

No, there is no way to make a String in Java mutable. The class doesn't expose its inner character array, and offers no methods that can alter it. If you want mutable Strings, you've got a few options, though:

  • StringBuilder and its synchronized variant StringBuffer are essentially mutable Strings, although slightly more cumbersome in code.
  • char arrays are mutable - you can use toCharArray() to get a mutable copy of a String's internal char array, for example.
  • Create your own class with an internal char array and methods that offer the manipulation features you want and toString() that allows you to use it as you intend.
kviiri
  • 3,282
  • 1
  • 21
  • 30
1

The short answer is no, you cannot mutate java.lang.String objects.

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. (The existing String simply has an additional reference.) Now we can start to see why making String objects immutable is such a good idea. If several reference variables refer to the same String without even knowing it, it would be very bad if any of them could change the String's value.

You might say, "Well that's all well and good, but what if someone overrides the String class functionality; couldn't that cause problems in the pool?" That's one of the main reasons that the String class is marked final.

Nobody can override the behaviors of any of the String methods, so you can rest assured that the String objects you are counting on to be immutable will, in fact, be immutable.

Reference: SCJP Sun Certified Programmer for Java 6 - Study Guide Exam (310-065) - Kathy Sierra & Bert Bates

ericbn
  • 10,163
  • 3
  • 47
  • 55
Felipe Pereira
  • 1,368
  • 16
  • 26
0

You can replace the reference (!) to a String as often as you like:

String A = "Test";
A = A.toUpperCase(); //will make A upper case
A = A.substring( 1 ); 

and so on. Excess usage of this may not be the best approach - it depends on the context.

Since some people seem to think that this can't be done with a String passed through a method:

String modify( String x ){
    x = x.toLowerCasae();
    x = x.substring( 1 );
    return x;
}

and the call must, of course replace the original String reference.

String tomod = "abc";
tomod = modify( tomod );

Three are, of course, classes better suited to this kind of String modification.

laune
  • 31,114
  • 3
  • 29
  • 42
  • 2
    Note the title to the question addresses passing a String to a method. – Andy Thomas Aug 13 '14 at 20:01
  • You can do the same with the String reference as a parameter, only it won't be changed after return, See the updaten answer. @AndyThomas is your imagination as narrow that you didn't realize that? – laune Aug 14 '14 at 05:04
  • This is stackoverflow. Personal attacks are out of place here. Your original answer did not address the question. Your updated answer does. – Andy Thomas Aug 14 '14 at 12:59