Can Boolean Arrays Be Initialized in a For Loop? - java

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?

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;
}

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.

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.

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;
}

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

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;
}

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;
}
}

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.

Related

Initializing an object in an array with a default value - java

Is there a way to define a default value for an object in array to be initialized with?
In the same way that primitive types are initialized when declaring an array of them:
int[] myIntArray = new int[5]; // we now have an array of 5 zeroes
char[] myCharArray = new char[2]; // an array in which all members are "\u0000"
etc.
I'd like to declare an array of objects of a type that I've defined, and have them automatically initialize in a similar fashion.
I suppose this would mean I'd like to run new myObject() for each index in the array (with the default constructor).
I haven't been able to find anything relevant online, the closest I got was to use Arrays.fill(myArray, new MyObject()) after initializing the array (which actually just creates one object and fills the array with pointers to it), or just using a loop to go over the array and initialize each cell.
thank you!
EDIT: I realized this is relevant not just to arrays, but for declaring objects in general and having them default to a value / initialize automatically.
The Java 8 way:
MyObject[] arr = Stream.generate(() -> new MyObject())
.limit(5)
.toArray(MyObject[]::new);
This will create an infinite Stream of objects produced by the supplier () -> new MyObject(), limit the stream to the total desired length, and collect it into an array.
If you wanted to set some properties on the object or something, you could have a more involved supplier:
() -> {
MyObject result = new MyObject();
result.setName("foo");
return result;
}
Do this so you can initialize the array when declaring it:
int[] myIntArray = {0, 0, 0,0,0};
char[] myCharArray = { 'x', 'p' };
you could of course do:
int[] myIntArray = new int[5];
and the in a for loop set all indexes to the initial value... but this can take a while if the array is bigger...
Edit:
for custom objects is the same just use an anonymous constructor in the init
Example:
public class SOFPointClass {
private int x;
private int y;
public SOFPointClass(int x, int y) {
this.x = x;
this.y = y;
}
// test
public static void main(String[] args) {
SOFPointClass[] pointsArray = { new SOFPointClass(0,0) , new SOFPointClass(1,1)};
}
}
I don't see a way that Java provides to do this.
My suggestion would be define a function to do it.
Object[] initialize(Class aClass, int number) throws IllegalAccessException, InstantiationException {
Object[] result = new Object[number];
for (int i = 0; i < number; ++i) {
result[i] = aClass.newInstance();
}
}
Then call it as Object[] arr = initialize(YourClass.class, 10)
In Java, the array is initialized with the default value of the type. For example, int default is 0. The default value for cells of an array of objects is null as the array cells only hold references to the memory slot contains the object itself. The default reference points to null. In order to fill it with another default value, you have to call Arrays.fill() as you mentioned.
Object[] arr=new Object[2];
Arrays.fill(arr, new Object());
As far as I know there is no way of doing what you want with just plain java (that is to say there may be an external library I don't know about).
I would take the hit and loop over the array. Something like this should work:
myObject[] array = new myObject[5];
for (int i = 0; i < array.length; i++) {
array[i] = new myObject();
}
You could also shorten this using lambdas, like Cardano mentioned in his answer.

for-each loop in java can't be used for assignments

Why for-each loop in java can't be used for assignments?
For eg I am trying the below example and not getting the expected result but compiles successfully:
int count = 0;
String[] obj = new String[3];
for (String ob : obj )
ob = new String("obj" + count++);
System.out.println(obj[0]); // null
ob is a local variable which is a copy of the reference in the array. You can alter it but it doesn't alter the array or collection it comes from.
Essentially, that is correct. The for-each loop is not usable for loops where you need to replace elements in a list or array as you traverse it
String[] obj = { "obj1", "obj2", "obj3" };
or
for (int count = 0; count < obj.length; count++) {
obj[count] = "obj" + count;
}
As you've noted, you can't use the variable in an array iteration to set the values of the array. In fact your code, while legal, is unusual in iterating through the elements of an array in order to initialise them. As other answers have noted, you are better off using the index of the array.
Even better is to create the array in the process of initialisation. For example, in Java 8 you could use:
String[] obj = IntStream.range(0, 4).mapToObj(n -> "obj" + n).toArray();
This seems to me to capture your intent of creating strings and then turning them into a new array rather than create an array and then iterate through it changing each element.

Kinda new to Java and stuck with collections. Here I'm trying to generate random numbers without duplicates

This is my snippet. record[i] is an object with 2 variables id and number. And I'm getting the error unexpected type : required variable; found : value.
int Shuffle = 0;
List<Integer> randomID = new ArrayList<Integer>();
List<Integer> randomNumber = new ArrayList<Integer>();
for (int i=0;i<100 ;i++) {
randomID.add(new Integer(i));
}
Collections.shuffle(randomID);
for (int i=0;i<100000;i++) {
randomNumber.add(new Integer(i));
}
Collections.shuffle(randomNumber);
for (int i=0;i<length;i++) {
if (randomID.contains(record[i].ID)) {
randomID.indexOf(record[i].ID)=null; //ERROR : REQUIRED VARIABLE FOUND VALUE
}
}
for (int i=0;i<length;i++) {
if (randomNumber.contains(record[i].getNumber())) {
randomNumber.indexOf(record[i].getNumber())=null;
}
}
Your call to randomID.indexOf(record[i].ID) returns some value. You have put it on the left side of an equals sign, so the compiler is looking for something to which it can ASSIGN a value. It can't assign a value to a value, it must have a variable.
I suppose you might mean to assign null to the ID of that element of the array: record[i].ID = null;
Or you might need the index into randomID:
int index = randomID.indexOf(record[i].ID);
randomID.set(index, null);
but you end up with a list that has a bunch of nulls in it. Is that really what you want?
Anyway, your question was about the error. If you have a different question, ask it in a different post.
With java collections, there are several types of storage.
The List collection allows for duplicate entries.
The Set collection does not allow duplicates.
Set set = new HashSet<Integer>(); //assuming you want Integer
int randomNumberCount = 10
while(set.size() < randomNumberCount) {
int temp = Math.random() * 100;
set.add(new Integer(temp));
}
Adding entries to a set that already exist will just replace it.

Java references not updated

I have the following code
List<String> strings = new ArrayList<String>();
strings.add("a");
strings.add("b");
strings.add("c");
for (String s : strings) {
s = new String("x");
}
System.err.println(strings);
which prints [a, b, c]
I thought it would print [x, x, x] because I iterate over the Strings, which returns a reference to a String Object. In the loop I assign a new Object to the reference, accordingly s should point to the new String Object?
Where is my fault?
What is the best way to update the strings in my array?
In the loop I assign a new Object to the reference
Well, you assign a new reference as the value for s. s is just a local variable though, which was initialized with the value of the element. It's not tied to the element in the list though - that was just how it was initialized. It's a bit like changing the value of a method parameter - that doesn't change whatever variable was used as an argument:
void method(String y) {
y = "bar"; // This doesn't change x.
}
...
String x = "foo";
method(x);
System.out.println(x); // foo
If you want to update the strings in your list (not an array - it's worth being clear about the difference) you should use a regular for loop:
for (int i = 0; i < strings.size(); i++) {
strings.set(i, "x");
}
It prints "a b c " because you are not changing(adding) anything in the list.
for (String s : strings) {
s = new String("x");
}
The above code can be read as :
For each String s in List strings set s to a new String value "x". You are not doing anything to the list. You get the value from the list, store it in s and overwrite s.
You only change the value of the local s variable, not the elements in the List.
You can change elements in the list by List.set(int index, E element).
s you specified here has scope only in the for loop
for (String s : strings) {
s = new String("x");
}
value of new String object is passed to s on each iteration, but strings is not getting affected at all.

Why can't I assign 1D arrays to 2D array using foreach cycle?

I have a method that returns 1D array. I want to call the method in a cycle and store the results in an 2D array. When using foreach cycle it doesn't work, the array results is full of null pointers.
//this doesn't work
...
double[][] results = new double[20][];
for(double[] result : results){
result = method();
}
...
public double[] method(){
double[] ret = new double[15];
//populate ret and do other stuff...
return ret;
}
But when using regular "for" cycle for iterating over the array it magically works!
...
double[][] results = new double[20][];
for(int i=0;i<20;i++){
results[i]=method();
}
...
public double[] method(){
double[] ret = new double[15];
//populate ret and do other stuff...
return ret;
}
Why?
Because in the enhanced for loop you access to a copy of each object reference of the arrays which is assigned to a variable, and you're modifying the value of this variable, not its contents.
for (double[] result : results) {
//here result is just a copy of results[0], results[1] and on...
//if you modify value of result i.e. assigning a new value
//you're just changing the value of the current variable
//note that if you modify an object inside the variable is reflected
//since you're updating the state of the reference, which is valid
}
This code can be somewhat translated to:
for (int i = 0; i < results.length; i++) {
double[] result = results[i];
//this explains why the enhanced for doesn't work
result = method();
}
Because, in your loop, result is a copy of the reference stored in the array. And you assign a new array to this copy. So the initial reference is left unmodified:
Before the assignment
results[i] ----> null
^
result -----------|
After the assignment:
results[i] ----> null
result --------> double array
It doesn't work in the first example because you are not using an index when you assign the 1D array to your 2D array :
result = method();
Here result is only a local variable, whose scope is the foreach loop, so you are only assigning the array to this local variable. The 2D array remains unchanged.
You could manage it using foreach with a manual index, setting to 0 before entering the loop and manually incrementing it. But in this case the classic for loop is probably better suited.

Categories

Resources