• Post Reply Bookmark Topic Watch Topic
  • New Topic

Enhanced For loops - is it possible to modify as we traverse  RSS feed

 
Ranch Hand
Posts: 41
Eclipse IDE Firefox Browser Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi

I have been using foreach loops for quite some time now. I have yet again been humbled by how little I know. Consider the code.


After this the contents of the array did not change. A normal for loop would have required me to use "arr[0]+=1" and yes, that would obviously have changed the contents. So is it that we cannot modify anything using these advanced loops. I mean i know "s" here is a block scoped variable. But still, somehow I am not able to give myself a solid explanation. Is it because it is an array of primitives and "copy of" value from the array is in "s". I used the String array too.


Since Strings are objects, shouldn't the first loop have changed the contents.
Can someone please clear this. It's discomforting to have such huge conceptual flaws in head. Thanks.
 
Ranch Hand
Posts: 256
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
When you are doing arr[0]+=1 you are manipulating the actual value in the array.
But when you are using you are actually assigning the value in the array to another variable 's' and manipulating it, which will not have any impact on the array. This is similar to
 
Rajat Sharmanaive
Ranch Hand
Posts: 41
Eclipse IDE Firefox Browser Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Bhanu

Thanks for the reply. I got that. What you said is fine for primitives. But shouldn't String Objects be changed. I pasted the snippet where i tried with strings but result was similar to that in case of an array of primitives. Has it got anything to do with String immutability or is it the expected behavior. I tried it with an Object array. It worked as expected.

I know the value in "s" in every iteration is the reference of the actual respective Dog Object. And hence the changes are reflected. Why not Strings then? Here is the code again. This time with constructors.

"s" is a reference variable. Why then changes made through it are not reflected. Please help.
 
Ranch Hand
Posts: 326
Android Firefox Browser Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The reason is that when ever you hit the top of the loop, the loop local variable named s is re-assigned. That means that every time you hit a bracket {, you get a "new" s.

If you want to concatenate the string values, you need to declare a variable outside of the loop.
 
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You appear to have two questions:
  • 1: Why can't I change the array elements in a for-each loop?
  • 2: Why am I not getting all my Strings catenated together?
  • Ove Lindström has already given you an answer for the second question.
    If you look in the Java Language Specification, you find that the value in the array is copied into a local variable, and that local variable is used in the loop. that means you can re-assign to the local variable (unless it is marked final), but that re-assignment is not reflected in the original array. [The same applies to Iterables.] That point is not clearly made in the Java Tutorials. You are calling that local variable s in your more recent examples.
    You can manipulate an object reference in that element to do anything with it which you can do to that object. In the case of the Dog you can rename it. (Actually your example shows poor design; it would be better to say Dog.setName("Fido");). You cannot, however, replace the array element with a different Dog. That would mean dog[3] = new Dog("Rover"); and you can do that with an old-style for loop.

    To recap: you can change the state of an object in an array or Iterable using any of the object's public interface. [Or protected interface, or package-private.] So you know how many methods there are in the String class' public interface to change its state? Go and count them. You can find them here, and you can recognise them because they have void instead of their return type and tell you what they change. And how many did you find?
    I'll continue the discussion when you have counted them.
     
    Rajat Sharmanaive
    Ranch Hand
    Posts: 41
    Eclipse IDE Firefox Browser Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Ove

    Fair enough. So does this mean that we can never modify array elements (string array elements, to be precise) using this for loop. If you can see in the earlier message, i was able to modify the contents of an array of Dog objects.

    If the address of each array element(which is a Dog object) can come into the loop variable s upon every iteration, why does something similar does not happen in case of Strings. Has it got anything to do with immutability.
     
    Bartender
    Posts: 4568
    9
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Rajat Sharmanaive wrote:Has it got anything to do with immutability.

    Spot on. You can call methods on the elements, which means that if the objects are mutable then they can be modified. But Strings are immutable. And so to get the effect you want you need to replace the element with a new object, which isn't possible using an enhanced for loop.
     
    Campbell Ritchie
    Marshal
    Posts: 56600
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Matthew Brown wrote: . . .
    Spot on. . . .
    Agree. When you counted the void methods which alter Strings, you didn't find any. There are two void methods, but those put part of the String into a buffer, so they don't change the String either. All the other methods which create a new String have String as their return type. Which would all lead you to believe String is immutable . . . if you didn't see
    Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. . . .
    which is the second line of the description part of the String documentation. You can write things like s.concat("Campbell") but you can't use = so the catenated String vanishes into cyber-Limbo never to be seen again.
     
    Rajat Sharmanaive
    Ranch Hand
    Posts: 41
    Eclipse IDE Firefox Browser Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Campbell, Matthew

    Thanks for you replies. I now understand that the answer to my question lies both in the working of the advanced for loop (The value of the array element gets copied into the local block scoped variable, that value could be a reference, in case of array of Objects) and the fact that Strings are immutable.
    you can change the state of an object in an array or Iterable using any of the object's public interface.
    This is very insightful. Never noticed.
    As far as immutability is concerned, this is what i know of it:
    Similarly, in every iteration, s is a local variable which points to the same String Object as sa[i]. Whatever changes i made to s will at max lead s to point to the "changed" value and have no affect on sa[i]. So the array remains intact.
    Please confirm/correct this.
    Also,
    (Actually your example shows poor design; it would be better to say Dog.setName("Fido")
    Indeed Campbell. It is sinful to expose variables like this. Didn't pay attention.
    Thanks once again
     
    Campbell Ritchie
    Marshal
    Posts: 56600
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Agree. All correct
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!