20

Just found this SO question that happened to solve my problem with initializing a Boolean array initializing a boolean array in java. However, while it gave me code that will work, the asker wasn't trying the code that I was running that wasn't working, and I'd actually like to know why it doesn't work. This was the code I was trying:

Boolean[] array = new Boolean[5];
for(Boolean value : array) {
    value = false;
}

This is the functional code from that other question:

Boolean[] array = new Boolean[5];
Arrays.fill(array, Boolean.FALSE);

I'm just curious why the for loop approach doesn't work?

Community
  • 1
  • 1
sage88
  • 4,104
  • 4
  • 31
  • 41
  • 5
    This is an issue of Java references being passed by value. With each iteration, it will assign it into the `value` variable, but when you assign `value` to false, you are overwriting the reference, not the actual variable inside the array. For each *never* works when assigning into the array – Nathan Merrill Dec 06 '13 at 06:22
  • That's really good to know. Thanks @MrTi I'm amazed I didn't hit this problem sooner. – sage88 Dec 06 '13 at 06:36

8 Answers8

18
Boolean[] array = new Boolean[5];
for(Boolean value : array) {
    value = false;
}

The java enhanced for loop uses an iterator to go through the array. The iterator returns a reference to the object, but java passes the reference by value, so you are unable to change what the reference points to, which is what you are trying to do with value = false.

EDIT:
As it turns out, for a normal array, instead of converting to a List and using an iterator, java does the following:

for (int i = 0; i < array.length; i++) 
{
    Boolean value = array[i]; //here's how we get the value that's referred to 
    ...                       //in the enchanced for loop  
}

While we are not using an iterator, the fact that Java passes references by value still explains what's going on here.
END of EDIT

If this were an array of objects with certain instance members, you would be able change said members, but not what the object, itself, references.

As others have suggested, to get around this, simple use a regular for loop and manually assign values to indexed slots in the array, ie:

Boolean[] b_values = new Boolean[5];
for(int i = 0; i < b_values.length; i++) 
{
    b_values[i] = Boolean.FALSE; 
}
Steve P.
  • 14,489
  • 8
  • 42
  • 72
  • 4
    I just find the amount of answers here that don't really answer the question staggering. – Nathan Merrill Dec 06 '13 at 06:29
  • @MrTi Agreed. Recently, I've been seeing a ton of answers that provide correct, working code, but don't really attempt to address OP's problem. When I can, I try to actually answer what the OP is asking. – Steve P. Dec 06 '13 at 06:31
  • Yeah, this really gets at the right answer and I can see why now. I will be marking this correct, but if you could, for future users, post working code it might help someone. (I know everyone else has already posted working code, but it's nice to have it in one place) – sage88 Dec 06 '13 at 06:32
  • @sage88 Sure. Gimme a sec. – Steve P. Dec 06 '13 at 06:33
  • @SteveP Does java treats all Wrapper classes as objects itself , and not reference? I should have been able to `assign` if it were `Employee` object. – Satheesh Cheveri Dec 06 '13 at 06:34
  • @SatheeshCheveri You can change the values of members of an object, but you cannot change what said object points to. It's the same reason that you can pass an array to a method and change what's inside the array, but not change what the array references. – Steve P. Dec 06 '13 at 06:36
  • 1
    Technically, for arrays, Java does not use an iterator. – user2357112 Dec 06 '13 at 06:42
  • @user2357112 I can see that being the case, but what does it use, then? I assumed that it converted the array to a list and then used an iterator? – Steve P. Dec 06 '13 at 06:44
  • It just uses a regular for loop. `for (int i = 0; i < array.length; i++) {Boolean value = array[i]; ...}`. – user2357112 Dec 06 '13 at 06:45
  • @user2357112 Not saying you're wrong, but do you have a link for where that is in the documentation? – Steve P. Dec 06 '13 at 06:46
  • @user2357112 Arrays are by default iterable. – Suresh Atta Dec 06 '13 at 06:47
  • @SteveP.: [Here you go.](http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.14.2) Scroll down to the part starting with "Otherwise, the Expression necessarily has an array type". – user2357112 Dec 06 '13 at 06:49
  • @sᴜʀᴇsʜᴀᴛᴛᴀ: Nope. Arrays are not any sort of `Iterable`. You can iterate over them, but you cannot get an iterator for them. – user2357112 Dec 06 '13 at 06:49
  • Note that if the enhanced `for` did use an iterator for arrays, it would perform needless boxing and unboxing for primitive arrays, as well as incurring the overhead of creating the iterator and calling its methods. – user2357112 Dec 06 '13 at 06:50
  • @user2357112 Thanks for the information. Does my edit make sense? – Steve P. Dec 06 '13 at 06:54
  • It does. It could be better worked into the explanation, so it's clear why the code doesn't work even though Java isn't using an iterator, but there's nothing factually wrong about it. – user2357112 Dec 06 '13 at 06:55
  • @user2357112 Hey thanks for clarifying even more what's going on here. I think Steve's answer is better for it and now I know more about enhanced for loops :). – sage88 Dec 06 '13 at 06:59
  • @user2357112 Yes, agreed. Internally it may use collection. That doesn't matter IMHO :) – Suresh Atta Dec 06 '13 at 06:59
  • @sage88 If possible please go through :http://www.ensta-paristech.fr/~diam/java/online/notes-java/flow/loops/foreach.html – Suresh Atta Dec 06 '13 at 07:02
  • 1
    @sᴜʀᴇsʜᴀᴛᴛᴀ Just took a look, I knew most of the deficiencies of for-each loops that they list at the end, but apparently not the most important one. I must have tried this earlier and had it not work and just switched back to standard for loop without thinking about it. – sage88 Dec 06 '13 at 07:14
  • 1
    @sage88 A programmers life :) – Suresh Atta Dec 06 '13 at 07:15
4

The reason why the code wasn't running is because when you mentioned that

Boolean[] array = new Boolean[5];
for(Boolean value : array) {
    value = false;
}

You are actually creating a new reference type called "Array of Boolean" and it contains only references to the five objects of Boolean class but the object doesn't exists as you haven't created them.

While in the second code

Boolean[] array = new Boolean[5];
Arrays.fill(array, Boolean.FALSE);

You are using cached object of Boolean class and adding it to the array you created using java.util.Arrays class. Boolean is a wrapper class in java and as only two possible values can be possible either true and false to avoid the overhead in creating them java already creates them for you and make them available for ready use.

Bilbo Baggins
  • 2,899
  • 10
  • 52
  • 77
3

value = true; is internally value = new Boolean(true); i.e it is creating a new Object in the pool. The value object refers to that Boolean object.Wrapper classes are immutable.

enter image description here

Nishant Lakhara
  • 2,295
  • 4
  • 23
  • 46
2

Yes Boolean[] can be initialize at for loop. For that you need to set value with array index, instead of enhanced for loop. Have a look at following loop.

Boolean[] array = new Boolean[5];
for(int i=0;i<array.length;i++) {
    array[i] = Boolean.FALSE;
}
Masudul
  • 21,823
  • 5
  • 43
  • 58
1

Because value is a copy of an array element and not the actual element in array.

Boolean[] array = new Boolean[5];    
    for (int i = 0; i < array.length; i++) {
             array[i]= false;           
    }

Just for reference: How for each works

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
0

It's an array of Boolean references with no real object assigned. You need to do this.

Boolean[] array = new Boolean[5];
for(Boolean value : array) {
    value = new Boolean(false);
}

EDIT: This doesn't solve the problem. It's the same. In the for loop, the variable value is not a reference to the original array. That's why you need to do.

Boolean[] array = new Boolean[5];    
for (int i = 0; i < array.length; i++) {
    array[i]= false;           
}
John Eipe
  • 10,922
  • 24
  • 72
  • 114
0

To illustrate Changing the Reference and Changing the value of member if Reference, I tried with User defined class , posting here what I have tried and the observation -thanks @SteveP

//Case 1 Trying to Change Reference

    Boolean[] array1 = new Boolean[5];
    Arrays.fill(array1, Boolean.FALSE);
    for(Boolean value : array1) { // Warning here The value of the local variable value is not used
        value = Boolean.TRUE;
    }

    System.out.println(" Elements ==> "+array1[0]+" -  "+array1[1]);

this will print Elements ==> false - false , Reference will not be able to modify

Case 2 Trying to Change Reference with user defined class

        MyBool[] array3 = new MyBool[5];
    MyBool boolInst2=new MyBool( Boolean.FALSE);
    MyBool boolNew=new MyBool( Boolean.TRUE);

    Arrays.fill(array3,boolInst2 );
    for(MyBool value : array3) {  // Warning here The value of the local variable value is not used
        value = boolNew;
    }
    System.out.println(" Elements ==> "+array3[0].flag+" -  "+array3[1].flag);

this will print Elements ==> false - false, Reference will not be able to modify

Case 3 Changing the values of members of an object (MyBool.value),

            MyBool[] array2 = new MyBool[5];
    MyBool boolInst=new MyBool( Boolean.FALSE);
    Arrays.fill(array2,boolInst );
    for(MyBool value : array2) {
        value.flag = Boolean.TRUE;
    }
    System.out.println(" Elements ==> "+array2[0].flag+" -  "+array2[2].flag);

this will print Elements ==> true - true , Values are updated

class MyBool{
    public Boolean flag;
    public MyBool(Boolean flag){
        this.flag=flag;
    }
}
Satheesh Cheveri
  • 3,621
  • 3
  • 27
  • 46
0

In Short: While Enumerating the array using for loop, you cannot modify the element of collection you are iterating through. Consider it as read only.

Amit Mishra
  • 431
  • 5
  • 16