Why can I edit the contents of a final array in Java?
final
in Java affects the variable, it has nothing to do with the object you are assigning to it.
final String[] myArray = { "hi", "there" };
myArray = anotherArray; // Error, you can't do that. myArray is final
myArray[0] = "over"; // perfectly fine, final has nothing to do with it
Edit to add from comments: Note that I said object you are assigning to it. In Java an array is an object. This same thing applies to any other object:
final List<String> myList = new ArrayList<String>():
myList = anotherList; // error, you can't do that
myList.add("Hi there!"); // perfectly fine.
modifying a public static final array
The array is not immutable.
You can still write:
KEYS[0] = "d";
without any issues.final
just means you cannot write:
KEYS = new String[]{"d"};
I.e. you cannot assign a new value to the variable KEYS
.
Is a final array of final strings still mutable?
The final
applies to the array reference, not its entries. Different strings can still be written to its entries.
If so, would making the array private, and having a getter that makes a copy of the array using Arrays.copyOf solve this issue?
Yes, defensive copies are a fairly standard way to handle this.
Alternately, given what you've outlined, you don't need to have the array at all, just a getter that looks like this:
public String[] getFooArray() {
return new String[] { Foo.a, Foo.b, Foo.c };
}
Or as jtahlborn commented, use an unmodifiable List<String>
:
public static final List<String> fooArray;
static {
List<String> a = new ArrayList<>();
Collections.addAll(a, Foo.a, Foo.b, Foo.c);
fooArray = Collections.unmodifiableList(a);
}
// (There's probably some really nifty Java8 way to do that as a one-liner...
Assigning final array to an array in java
You have to strictly differentiate instances/objects from variables. final
in Java is a concept that only applies to variables.
In your code you have two different variables that both refer to the same array instance. One of the variables is final
, that neither affects the array nor the other variable at all.
final
disallows re-assignment of the variable, it does not disallow altering the array. finalArr[1] = 4;
is perfectly valid.
To illustrate this, consider
arr ---------|
|----> instance created by new int[8]
finalArr ----|
You see two different arrays, both point to the same instance. final
makes sure that you can not change the arrow going out of finalArr
anymore. So it will always point to that array instance. But it does not give any restrictions regarding what you do to the array instance itself or to arr
.
If you are coming from a C/C++ context, final
is very different to const
in that regard.
Java changing value of final array element
Arrays
are mutable Objects unless created with a size of 0.Therefore,you can change the contents of an array.final
only allows you to prevent the reference from being changed to another array Object.
final String[] ABC ={"Hello"};
ABC[0]="Hi" //legal as the ABC variable still points to the same array in the heap
ABC = new String[]{"King","Queen","Prince"}; // illegal,as it would refer to another heap Object
I suggest you use Collections.unmodifiableList(list)
to create a immutable List.See the javadoc here (unmodifibale list).
You can do the following
String[] ABC = {"Hello"};
List<String> listUnModifiable = Collections.unmodifiableList(java.util.Arrays.asList(ABC));
At any point of time,you can get the array by calling listUnModifiable.toArray();
Why can Java final array variable be modified?
So a final array means that the array variable which is actually a reference to an object, cannot be changed to refer to anything else, but the members of the array can be modified
refer below link for more information.
https://www.geeksforgeeks.org/final-arrays-in-java/
As per description
for example
final String[] arr = new String[10];
list.stream().map(ele -> {
arr[0] = ele.getName(); // this will work as you are updating member of array
arr = new String[5]; // this will not work as you are changing whole array object instead of changing member of array object.
}).collect(Collectors.toList());
the same thing happen when you use any final collection there.
java final array lowercase or uppercase
No Java code conventions that I'm aware of advocates that all final variables should be all caps. Constants should be all caps, and by constants you usually refer to final fields that are immutable (or deliberately never mutated).
In this case you're using an array, and since it public it may very well be mutated. For this reason, I wouldn't count this as a constant, and therefor go with myArray
.
For reference, here's a quote from the Official Oracle Java Code Conventions:
The names of variables declared class constants and of ANSI constants should be all uppercase with words separated by underscores (“_”). (ANSI constants should be avoided, for ease of debugging.)
Why are public static final array a security hole?
Declaring static final public
fields is usually the hallmark of a class constant. It's perfectly fine for primitive types (ints, doubles etc..), and immutable classes, like strings and java.awt.Color
. With arrays, the problem is that even though the array reference is constant, the elements of the array can still be changed, and as it's a field, changes are unguarded, uncontrolled, and usually unwelcome.
To combat this, the visibility of the array field can be restricted to private or package private, so you have a smaller body of code to consider when looking for suspicious modification. Alternatively, and often better, is to do away with the array together and use a 'List', or other appropriate collection type. By using a collection, you control if updates are allowed, since all updates go through methods. You can prevent updates by wrapping your collection using Collections.unmodifiableList()
. But beware that even though the collection is immutable, you must also be sure that the types stored in it are also immutable, or the risk of unsolicited changes on a supposed constant will reappear.
How to delete an (effectively) final array in Java
The array becomes eligible for garbage collection at the latest when the method returns - you don't need to set it to null.
If you have a long method and are concerned that the array is kept around for the rest of it, the solution is to write smaller methods. Dividing the functionality among smaller methods may also improve readability and reusability.
If you can't or don't want to write smaller methods, introducing separate blocks in the method may help. Local variable declarations are local to the block, so this "trick" also lets you re-use a variable name in different blocks in the method.
void largeMethod() {
first: {
final int number = 1;
}
second: {
final int number = 2;
}
}
Technically, the array becomes eligible for garbage collection after its last use, which can be in the middle of the method - before the variable goes out of scope. This is explicitly allowed by section 12.6.1 in the language specification:
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.
While the specification allows this optimization, it does not require it. If you find that the optimization is not being made in a particular situation and you need a better guarantee, splitting the big method into smaller methods will help.
what is the sense of final ArrayList?
But what is effect making it's final?
This means that you cannot rebind the variable to point to a different collection instance:
final List<Integer> list = new ArrayList<Integer>();
list = new ArrayList<Integer>(); // Since `list' is final, this won't compile
As a matter of style, I declare most references that I don't intend to change as final
.
I still can add to ArrayList new elements, remove elements and update it.
If you wish, you can prevent insertion, removal etc by using Collections.unmodifiableList()
:
final List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>(...));
Related Topics
Sorting an Array of Int Using Bubblesort
Why Can't We Use '==' to Compare Two Float or Double Numbers
Replacing If Else Statement with Pattern
How to Parse a JSON String to an Array Using Jackson
How to Get Client Information Such as Os and Browser
How to See the Source Code of the Sun Jdk
Simple Hibernate Query Returning Very Slowly
Jtable with Horizontal Scrollbar
Spring MVC Type Conversion:Propertyeditor or Converter
What Does Maven Do, in Theory and in Practice? When Is It Worth to Use It
When Is It Ok to Catch Nullpointerexception
Transform Java Future into a Completablefuture
Efficiently Compute Intersection of Two Sets in Java
How to Compile and Deploy a Java Class at Runtime