0

I am writing a method that processes a string (to extract something):
public static String myProcessor (String myInput) {...

I want to have some String object inside this method, that I can apply my transformations on (workString = workString.replace(...)

However, I don't want to change the original string (via the reference given to my method, i.e.:
myProcessor(originalString)) - because there may be method calls after my method has been called, which also want to process/extract something from the original string, before my method call

I am still learning Java and, according to my book (Deitel & Deitel - "Java How To Program"):
~"primitive types are pass-by-value. Other variable types are for objects and those are pass-by-reference and therefore variable assignment of an object is passing the reference to the same object. A change in the object referenced by one variable can be seen when reading the other variable (if Object var2 = var1)"
(This isn't verbatim, just what I understood from it!)

So, I thought I'd try: String workString = new String(myInput); and this should create a new String object, using data from myInput, but I could manipulate workString anyway I want, without worrying I am making changes to an object which is used elsewhere.

IntelliJ suggested that this is redundant, and I can just do: String workString = myInput, which got me confused...

Is IntelliJ right here?
Actually, do I even need to create a local-scope workString, or references are "detached" once a variable "arrives" into a method? (i.e.: inside myProcessor, myInput is no longer holding a reference to the originalString from the call for myProcessor, but it creates a new String object?

Could you also please mention briefly if your answer is regarding just String objects or all objects?
I have a feeling that perhaps String is somewhere between a Primitive type and an Object type and has special rules applied to it...

DraxDomax
  • 1,008
  • 1
  • 9
  • 28
  • In Java, everything is pass-by-value: https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – M A Jan 21 '21 at 17:49
  • `String` is an object all the way. The only truly special thing about it is that you can create them with a string literal—and that's essentially just "compiler magic". There's also the [string pool](https://stackoverflow.com/questions/2486191/what-is-the-java-string-pool-and-how-is-s-different-from-new-strings). – Slaw Jan 21 '21 at 17:51
  • 2
    Moreover, `String` is immutable, so there is rarely anything to be gained by copying it. Any manipulation you do to `workString` doesn't change the original string, it creates a new one. – Andy Turner Jan 21 '21 at 17:52
  • @Slaw but you can do things like myString=myString.replace("x","y") - I guess replace() has some "detachment" going on inside? I mean, it takes the input, creates a new object, with the transformation, and then returns a reference to the new object? – DraxDomax Jan 21 '21 at 17:53
  • 1
    @DraxDomax that's not changing the string, it's creating a new one and reassigning the variable. – Andy Turner Jan 21 '21 at 17:53
  • As noted by Andy, `String` is immutable. Any method which seems like it's manipulating a string's contents is actually returning a new `String` instance and leaving the original instance alone. That's why you have to use the returned instance. – Slaw Jan 21 '21 at 17:54
  • I guess the way to look at it, is to understand that, the moment I do any transformation on the myInput variable that comes from the method signature, then whatever I assign the transformation into, will be a local variable, containing a reference to a new object, and therefore, returning that, even if it's still called myInput, will return a reference to a new object? So, I should be fine using myInput internally without worrying about changing data in a difference scope? – DraxDomax Jan 21 '21 at 17:57
  • 2
    When you do `myString = myString.replace("x","y")` you are creating a _new_ String as has been said, and replacing the reference that myString holds with a reference to that new String; the original string is unchanged. The caller of `myProcessor(originalString)` still sees the original reference to the original String object they passed so is unaffected by any of this. – Stephen P Jan 21 '21 at 17:57
  • 2
    I suggest reading the link by @MAnouti in the first comment. In Java, everything is _pass-by-value_. That includes objects and primitives. The nuance with regards to objects is that the "value" being passed is the reference to the object. That's why if you pass a `List` to a method, add an element to it, and then query the list in the caller of the method you'll see the changes; you've modified the object itself. But if that same method were to do `list = new ArrayList<>();` (where `list` is the parameter) that will not affect the caller of the method at all. – Slaw Jan 21 '21 at 18:01
  • I think I get it now, thanks! Oh... the power of hindsight... My question looks so embarrassing! – DraxDomax Jan 21 '21 at 18:03

2 Answers2

3

As mentionned by @AndyTurner, In Java String is immutable which means any operation on a String doesn't change the original String.

For instance:

myString = "Hello World"; // literal
myString = myString.replace("o", "-"); // not literal
myString = myString + " !"; // not literal

Hello World is placed in the String Pool and assigned to variable myString.
Hell- W-rld is placed in the String Pool and assigned to variable myString.
Hell- W-rld ! is placed in the String Pool and assigned to variable myString.

BUT ! As Hell- W-rld and Hell- W-rld ! are not literal (GC of String literals) and no more reachable, they are candidate for Garbage Collection.
In the end only two String will be in the pool: Hello World and ! (the two literals).

EDIT: "o" and "-" will stay in the pool as they are literals too

Could you also please mention briefly if your answer is regarding just String objects or all objects

It depends of the property, String is not a Primitive but is treated in some regards like one. Primitives are immutable and so are Strings.

To answer your title :

Is “new String(oldString)” necessary? (Is String a reference or a value?)

It allows to store the value in the String Pool but :

String s1 = "Hi";
String s2 = new String(s1); // Any other operation would assign a new reference as String is immutable
s1 == s2; // false
s1.equals(s2); // true

A String is passed by reference and new assign a new reference (to a same String in the pool). Both references are different (s1 and s2) but both points to the same value.

IQbrod
  • 2,060
  • 1
  • 6
  • 28
2

As the correct Answer by IQbrod says, String is immutable. So no need to worry about changing the text it contains.

If you did want to alter the container text, rather than using the String class, you would use another implementation of the interface CharSequence.

Here is a diagram I made to give you an overview of the various text related classes, and to help in selecting a class for specific purposes.

enter image description here

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154