0

This is probably the dumbest question, but I understand that Strings in Java are immutable. However, consider this code snippet which scans a typical file:

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String line;
    while ((line = br.readLine()) != null) {
      // The value of line appears to be reset after each iteration 
    }
}

Why is line here not retaining its value over the scanning process? Is it something to do with the readLine() method itself? I admit I haven't seen how that method is implemented, so I'm not exactly sure how it works.

Fiery Phoenix
  • 1,156
  • 2
  • 16
  • 30
  • 1
    I just updated my post to explain difference between `final` and `immutability`, hope this will help you. – Anthony Raymond Dec 30 '16 at 09:57
  • *"This is probably the dumbest question"* Well, it at least shows missing research. – Tom Dec 30 '16 at 10:09
  • Possible duplicate of [Immutability of Strings in Java](http://stackoverflow.com/questions/1552301/immutability-of-strings-in-java) – Tom Dec 30 '16 at 10:11
  • [What is meant by immutable?](//stackoverflow.com/q/279507) – Tom Dec 30 '16 at 10:14

4 Answers4

5

line is a reference to an immutable java.lang.String.

line = br.readLine() assigns the reference line to the String reference returned by br.readLine(). So line assumes that value in the body of the while loop.

But, line = br.readLine() is also an expression with a value of that reference. It is compared to null via the expression (line = br.readLine()) != null. The while conditional evaluates to false once this is null: i.e. all the input has been read.

In short, strings are immutable in Java, but you can use a reference variable to refer to different strings.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    "line = br.readLine() assigns the reference line to the String reference returned by br.readLine()" Why do you say it assigns the reference line to a reference ? Finally, it assigns the reference to a String **value** (pool of Strings or not) – davidxxx Dec 30 '16 at 09:47
0

You are missunderstanding the concept of Immutability.

An immutable object is an object with non-updatedable properties.

String line = "abcd";

What is not mutable is the char[] into the String object. But you can reasign line reference to another String later.


But there is also final references in java.

final String line = "abcd"

Final means you would never be able to change the reference of line. And in this case, since String is immutable as well, you won't be able to change the String value nor the String reference.

Immutable vs final

Immutable

Let's consider the following class.

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() { return this.name; }
}

As you can see, once a person instance has been initialized, there is no way to change his name, there is no setter, and a string value cannot be updated.

Owether, this code will work:

Person person = new Person("John");
person = new Person("Jack"); // of course, at this point John is lost
// But nothing prevent me from reassigning the person value.

When talking about immutablility, we are talker at the class level.

Final reference

Let's consider the following class.

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() { return this.name; }
    public String setName(String name) { this.name = name; }
}

As you can see, once a person instance has been initialized, is still can change his name.

But if i declare my person instance as final, i won't be able to assign a new perso to this reference.

final Person person = new Person("John");
person = new Person("Jack"); // THIS WILL FAIL !!
// But i can update my person name if i want to, since the class is not immutable.
person.setName("Alice");




I hope this might help you.

What happen in your case

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String line;
    while ((line = br.readLine()) != null) {
      // The value of line appears to be reset after each iteration 
    }
}

At each loop's round, you are reasigning the line reference, not the line value. This is why the text in line change at each round, because the reference is updated.

Anthony Raymond
  • 7,434
  • 6
  • 42
  • 59
0

Simple answer in layman's terms: line is like an envelope that can hold exactly one 1$ bill.

Now that envelope can either be empty (null); or hold exactly one String object/1$ bill. But of course, you can always remove that bill; and put in another one. But those 1$ bills; they always stay the same.

And that is what is happening here.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
0

When we say String is immutable, i means the particular object or instance of that object cannot be modified. It does not mean that is the variable referencing it will not point to new object. The funcationality you are expecting is provided by "final" keyword in java.

Here, it is similar to :-

String str = "abc";
 str = "xyz";

In this case, str is pointing to another object xyz, its not changing "abc" to "xyz".

Lets see this code :-

     String str = "abc";
     String str1 = str;
            str = "xyz";
    System.out.println(str1);

This will print "abc" as actual object is still being referenced by str1 and has value "abc".

Even if you do below:-

     String str = "abc";
     String str1 = str;
            str = str + "xyz";
    System.out.println(str1);
     System.out.println(str);

It will print "abc" for first print statment and other will print "abcxyz" as first object is same and concentantion is creating new object and assigning to str. But if you try same with some mutable object like StringBuilder, both will print "abcxyz".

alexbt
  • 16,415
  • 6
  • 78
  • 87
Panther
  • 3,312
  • 9
  • 27
  • 50