Final Array in Java

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



Leave a reply



Submit