Which advantages/disadvantages we can get by making ArrayList (or other Collection) final? I still can add to ArrayList new elements, remove elements and update it. But what
Final is a keyword or reserved word in java and can be applied to member variables, methods, class and local variables in Java. Once you make a reference final you are not allowed to change that reference and compiler will verify this and raise compilation error if you try to re-initialized final variables in java.
It doesn't effect what you can do with the ArrayList as you rightfully observe - the ArrayList itself is still mutable. You have just made the reference immutable.
But making a variable final does have other benefits:
final
can help the compiler make certain performance optimisations.In general, the more things that you make immutable, the better. So making references final (even if they are references to mutable objects) is generally a good idea.
To get a really immutable list, you will have to make deep copies of the contents of the list. UnmodifiableList would only render the list of references somewhat immutable. Now making a deep copy of the List or array will be tough on memory with the growing size. You can make use of serialization/deserialization and store the deep copy of array/list into a temp file. The setter would not be available as the member varaible needs to be immutable. The getter would serialize the member variable into a file and then desialize it to get a deep copy. Seraialization has an innate nature of going into the depths of an object tree. This would ensure complete immutability at some performance cost though.
package com.home.immutable.serial;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public final class ImmutableBySerial {
private final int num;
private final String str;
private final ArrayList<TestObjSerial> immutableList;
ImmutableBySerial(int num, String str, ArrayList<TestObjSerial> list){
this.num = num;
this.str = str;
this.immutableList = getDeepCloned(list);
}
public int getNum(){
return num;
}
public String getStr(){
return str;
}
public ArrayList<TestObjSerial> getImmutableList(){
return getDeepCloned(immutableList);
}
private ArrayList<TestObjSerial> getDeepCloned(ArrayList<TestObjSerial> list){
FileOutputStream fos = null;
ObjectOutputStream oos = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
ArrayList<TestObjSerial> clonedObj = null;
try {
fos = new FileOutputStream(new File("temp"));
oos = new ObjectOutputStream(fos);
oos.writeObject(list);
fis = new FileInputStream(new File("temp"));
ois = new ObjectInputStream(fis);
clonedObj = (ArrayList<TestObjSerial>)ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return clonedObj;
}
}
I personally mark the collections field of my classes as final
to save the users of my class from checking whether it is null or not. This works because, once the value is already assigned to a final variable, it can never be reassigned to another value, including null.
I came to think of this same question and coded and example to add to the explanation from yet another angle.
The final arrayList can still be modified, refer to the example below and run it to see for your self.
Here is the immutable class with immutable List declaration:
public final class ImmutableClassWithArrayList {
final List<String> theFinalListVar = new ArrayList<String>();
}
And here is the driver:
public class ImmutableClassWithArrayListTester {
public static void main(String[] args) {
ImmutableClassWithArrayList immClass = new ImmutableClassWithArrayList();
immClass.theFinalListVar.add("name");
immClass.theFinalListVar.forEach(str -> System.out.println(str));
}
}
As you can see, the main method is adding (modifying) the list. So the only thing to note is that the "reference" to the object of the collection type can't be re-assigned to another such object. As in the answer by adarshr above, you can't do immClass.theFinalListVar = new ArrayList(); in the main method here.
The modification part really helped me understand this and hope it helps in same way.
It just means that you can't re-assign its reference. Attempting to do something like the below will lead to compiler error.
final List<String> list = new ArrayList<String>();
list = new LinkedList<String>();
^
Compiler error here
If you really want an immutable list, you should use the Collections.unmodifiableList()
method.