简体   繁体   中英

Why can Java final array variable be modified?

I know that writing a lambda in Java 8 to use a variable requires final type, but why can a variable of final array type be modified?

public static void main(String[] args) {
        final String[] prefix = {"prefix_"};
        String suffix = "_suffix";

        List<Integer> list = Arrays.asList(1005, 1006, 1007, 1009);
        List<String> flagList = list.stream().map(param -> {
            prefix[0] = "NoPrefix_";
            String flag = prefix[0] + param + suffix;
            return flag;
        }).collect(Collectors.toList());

        System.out.println(flagList);

        System.out.println(prefix[0]);
    }
    

result:

[NoPrefix_1005_suffix, NoPrefix_1006_suffix, NoPrefix_1007_suffix, NoPrefix_1009_suffix]
NoPrefix_

why can a variable of final array type be modified?

It can't, even though it looks like it can.

The declaration is below, which defines "prefix" as an array:

final String[] prefix

First, edit the code to include two println() calls right after the declaration, like this:

final String[] prefix = {"prefix_"};
System.out.println("prefix: " + prefix);
System.out.println(prefix[0]);

And at the end, add a second println() next to the one you already had, like this:

System.out.println("prefix: " + prefix);
System.out.println(prefix[0]);

If you run that code, you'll see that the object hashCode when printing prefix will be the same object each time. The thing that changes then is not what "prefix" references – that remains the same, it's the same array as before. Instead, what you're doing is changing something inside the array, which is different from the array itself.

Here are the relevant lines from a local run showing that the object reference remains the same, but the value for "prefix[0]" changes:

prefix: [Ljava.lang.String;@5ca881b5
prefix_
prefix: [Ljava.lang.String;@5ca881b5
NoPrefix_

If we try to assign an entirely new array to "prefix", then the compiler will show an error – it knows "prefix" was defined as final.

prefix = new String[]{"new"};

cannot assign a value to final variable prefix

If you're looking for a way to prevent changes to the data, and if it's possible to use a List (instead of an array), you could use Collections.unmodifiableList() :

Returns an unmodifiable view of the specified list. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM