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_
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.
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.
Related
Suppose I have an array
public static final String[] fooArray ={ Foo.a, Foo.b, Foo.c };
where Foo.a b and c are static final Strings.
Could I still do something like fooArray[0] = "taco"; and end up with { taco, Foo.b, Foo.c } as the contents of fooArray?
If so, would making the array private, and having a getter that makes a copy of the array using Arrays.copyOf solve this issue?
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...
Yes.
A final array means you can't reassign the array.
So you couldn't do: fooArray = new String[]{...};.
But you can however change what is inside the array. This is the effect of saying: "You can't change the box, but you can change the apples inside the box to be oranges." The box stays the same, and is final, but you've effectively changed the contents.
That being said, if you encapsulate the class, then you can just clone the array when it is needed.
This is currently employed by many classes, such as String#toCharArray and Enum#values, where changing the array's contents comprises the integrity of the finalized object(s).
The final-modifier will only prevent changing the fooArray-reference, not the contents of the array itself. Making it private and having a getter returning a copy would hide the original array, and any changes made to the returned array would only affect the copy. However, it would still be possible to modify the original via reflection, but if your intent is to only prevent accidental modification of the original array, that would work.
Rest have answered about the final well. Just a suggestion on the other part - rather than implementing a getter which does a copy of entire array, if your scenario allows, its better to have a getArrayElement(int position) where you just return an array element rather than the whole array - copying an array is expensive.
You could make a getter that returns a mutable copy of an immutable value.
If you used array copy the values inside the copy will still be final.
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World");
final int b = 5;
int c = b; // Because of c being mutable we can now change this copy
c = 7;
System.out.println(c);
}
}
... Some psudo code -> for copying an iterable into a mutable form.
public collection<int>(final collection<final int> finalCollection )
collection nonFinalCollection = new collention();
for(k : finalCollention){collection.add((int) k)}
return(collection)
This question already has answers here:
Why can I edit the contents of a final array in Java?
(9 answers)
Closed 8 years ago.
I am confused. I tried using
final String usr;
and trying to change its value never worked, but when I used an array final String[] usr = {"", ""};, it worked. I even accessed it from this
sgnup.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
user[0] = sUsr.getText();
}
});
I find it very confusing because my understanding of final is that a variable declared with final and add a value to it, the value never changes. But why did an array with final work? I can even set a text to one of those arrays.
Yes, because you don't change the reference of usr but what it contains. final block you from doing something like usr = new String[5]; (change the usr to another array) but the content of the array can be changed without problems.
final String[] a = new String[5];
a = new String[3]; // illegal
final String[] a = new String[5];
a[0] = "Hello"; // legal, i don't change a but what is inside a[0]
In Java, a variable of any object type (including any array) actually is a reference to an object, not the object itself. When you declare a variable to be final, it means that the reference will not change, meaning that the object it references will always be the same object. However, if the internal state of the object can still change without the final modifier, then adding final won't prevent the internal state of the referenced object from changing. In particular for a final array, the array reference itself cannot be reassigned, but the array elements can still change.
In your situation, you can avoid using an array by simply eliminate the final modifier from the String variable.
The following code in Java uses a final array of String.
final public class Main {
public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};
public static void main(String[] args) {
for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
System.out.print(CONSTANT_ARRAY[x] + " ");
}
}
}
It displays the following output on the console.
I can never change
If we try to reassign the declared final array of type String, we cause an error:
final public class Main {
public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};
public static void main(String[] args) {
CONSTANT_ARRAY={"I", "can", "never", "change"}; //Error - can not assign to final variable CONSTANT_ARRAY.
for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
System.out.print(CONSTANT_ARRAY[x] + " ");
}
}
}
Error: cannot assign to final variable CONSTANT_ARRAY.
However, the following code works:
final public class Main {
public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};
public static void main(String[] args) {
CONSTANT_ARRAY[2] = "always"; //Compiles fine.
for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
System.out.print(CONSTANT_ARRAY[x] + " ");
}
}
}
It displays
I can always change
This mean that we could manage to modify the value of the final array of type String. Can we modify the entire array in this way without violating the immutable rule of final?
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.
You are misinterpreting the final implementation. final applies to the array object reference, which means once it is initiated, the reference can never change but the array its self can be populated. "Its not violating the rules" you have specified only one rule about the reference change which is working accordingly. If you want the values should also never change you should go for Immutable lists i.e
List<String> items = Collections.unmodifiableList(Arrays.asList("I", "can", "never", "change"));
You can only make it so the array reference can't be changed. If you want the elements to be unable to be changed, you need to use an unmodifiable collection of some kind.
When you declare an array as final, you can change the elements in the array, however you cannot change the reference of this array.
final only guarantees immutability of primitives. And also guarantees that a variable is assigned only once. If an object is mutable you can change the content of it event it defined as final. You may check immutable collections for your needs. Such as Collections.unmodifiableList()
http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#unmodifiableList(java.util.List)
The reference to the array object is final (can not change e.g. in case you would attempt to associate a different Java array object (instance of String[]) to the same final variable...you'd get a compile time error).
BUT the fields of the final array object in your example are not final, and so you can modify their value. ...while the Java object you created, CONSTANT_ARRAY, after receiving an initial value, will have that value "forever" == until the JVM stops. :) It will be the same String Array instance "forever".
Final variables in Java are not a big deal, just spend some time to digest the topic/idea carefully. :-)
I suggest to all of those who are uncertain to meditate over this page, for example:
https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4
Let me cite the respective part:
"Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.
This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array."
The value of the variable CONSTANT_ARRAY cannot change. That variable contains a (reference to an) array. However, the contents of the array can change. Same thing happens when you declare any kind of final variable that is not a simple scalar type (e.g. an object).
Be careful how you name your variables. :-) Calling it a CONSTANT_ARRAY doesn't make the contents of the array unchangeable.
Here's a good reference: The final word on final
When a variable is declared with the final keyword, its value can’t be modified, essentially, a constant. This also means that you must initialize a final variable. If the final variable is a reference, this means that the variable cannot be re-bound to reference another object, but the internal state of the object pointed by that reference variable can be changed i.e. you can add or remove elements from the final array or final collection.
final int[] res;
int[] res1;
int[] res2 = new int[1];
res2[0]=20;
res1=res2;
res1=res2;//no error
System.out.println("res1:"+res1[0]);
res = res2;//only once
//res = res2;//error already initialised
res2[0]=30;
System.out.println("res:"+res[0]);
output::
res1:20
res:30
I have an array of type string which I want to re-use inside a method.
I need to pass it to a function which returns a subset of the elements of array passed. To capture the returned array from function, should I declare a new string array or can I safely re-use same array that was holding the unfiltered array to hold filtered array ??
Also clarify that, when I pass a variable like array to a function does it creates a new space for the array in the heap each time I pass it as parameter to further functions or just it uses the same space in the heap & just passes the reference? I guess in case of array it passes just the reference but in case of simple variables it allocates new space on stack, right?
EDIT: Thanks you all for the great answers and explanations!!
Please also clarify whether that if I am reusing the array, would I be required to set the null at the position when I end the subset of array ? (Actually the subset of my array is not directly calculated from the array but some other calulations, so I would be required to manually set the null otherwise the older elements of the list would be visible, right??)
when I pass a variable like array to a function does it creates a new space for the array in the heap each time I pass it as parameter to further functions or just it uses the same space in the heap & just passes the reference
Java is entirely pass by value, but with arrays and object types, the value being passed is a reference (pointer) to the actual object, which is not duplicated. So when you pass an array into a function, only the reference to the array is copied; the array itself isn't. That's why if a function modifies the contents of an array, the code calling the function sees the modifications.
Example:
// A method that changes the first entry in an array
void changeArray(String[] theArray) {
theArray[0] = "Updated";
}
// A method that uses the above
void someMethod() {
String[] foo = new String[3];
foo[0] = "Original 0";
foo[1] = "Original 1";
foo[2] = "Original 2";
this.changeArray(foo); // `changeArray` receives a *copy* of the reference
// held in `foo`; both references point to the same
// array
System.out.println(foo[0]); // Prints "Updated"
}
Passing a reference into a method is exactly like assigning it to another reference variable:
String[] foo = new String[3]; // Create a new aaray, assign reference to `foo` variable
String[] bar = foo; // Copy the reference into `bar` as well
foo[0] = "Hi there"; // Use the reference in `foo` to assign to the first element
System.out.println(bar[0]); // Use the reference in `bar`, prints "Hi there"
Essentially, references are values (numbers) that tell the JVM where the data for an object is. So even when we copy a reference (because Java is entirely pass-by-value, the value of the reference is passed to the function), it still points to the same memory as the original.
Since the reference is passed into the function by value, the function can't change the calling code's reference:
// A method that assigns a new reference; the calling code sees no change
void changeReference(String[] theArray) {
theArray = new String[1]; // Now we're not using the caller's object anymore
theArray[0] = "I was changed";
}
// A method that uses the above
void someMethod() {
String[] foo = new String[3];
foo[0] = "Original 0";
foo[1] = "Original 1";
foo[2] = "Original 2";
this.changeReference(foo);
System.out.println(foo[0]); // Prints "Original 0", our reference wasn't changed
}
You'll note that this is exactly how primitives are treated:
void whatever(int a) {
a = 5;
}
void someMethod() {
int foo;
foo = 3;
whatever(foo);
System.out.println(foo); // Prints 3, of course, not 5
}
...and in fact, object references (as opposed to objects) are primitives.
...should I declare a new string array or can I safely re-use same array that was holding the unfiltered array to hold filtered array
You can safely re-use it if that's appropriate within the scope of your function. It may be more appropriate to declare a new variable (e.g., filteredThingy), but that's a matter of style and will depend on the situation.
You probably can by it is very bad style and is very error prone and is very unsafe for future modifications.
Here is the example.
public void foo(String[] args) {
// do something with array.
args = new String[] {"a", "b"}; // reuse of the array.
// more code.
for (Sring s : args) {
// what will this loop get"?
// The answer is: a, b
// but will you remember this fact in a month if "more code" above is 50 lines long?
}
}
Passing objects is essentially passing references. E.g., your array will only exist in one place in memory when passing it between functions. Here's a runnable example illustrating that.
If you like you can reuse the same array in your routine. Note that changes made to that array will be visible to all objects sharing the same reference to that array. If that's not desirable then you must declare a new array.
String parentArray = {"S","B","R"};
// no need to use new operator to hold subSetArray.
String subSetArray = returnSubSet(parent);
public String[] returnSubSet(String[] _parent)
{
return Arrays.copyOfRange(_parent,1,2);
}
, when I pass a variable like array to
a function does it creates a new space
for the array in the heap each time I
pass it as parameter to further
functions or just it uses the same
space in the heap & just passes the
reference?
Answer
1. Object in Java are Pass by reference by value
2. when you pass an array to a function , a _parent variable will be created in stack and it points to the same Array Object in heap.
UPDATES: Primitive example
int global_scope_variable=10;
setValue(global_scope_variable);
public void setValue(int val)
{
// val is visible only within this method.
System.out.println(val); // output is 10
val=20;
System.out.println(val); // output is 20
System.out.println(global_scope_variable); // output is 10
}
I am having a problem with the following lines where car is a String array which has not been initialized/has no elements.
String car [];
System.out.println(car.length);
What is a possible solution?
Since car has not been initialized, it has no length, its value is null. However, the compiler won't even allow you to compile that code as is, throwing the following error: variable car might not have been initialized.
You need to initialize it first, and then you can use .length:
String car[] = new String[] { "BMW", "Bentley" };
System.out.println(car.length);
If you need to initialize an empty array, you can use the following:
String car[] = new String[] { }; // or simply String car[] = { };
System.out.println(car.length);
If you need to initialize it with a specific size, in order to fill certain positions, you can use the following:
String car[] = new String[3]; // initialize a String[] with length 3
System.out.println(car.length); // 3
car[0] = "BMW";
System.out.println(car.length); // 3
However, I'd recommend that you use a List instead, if you intend to add elements to it:
List<String> cars = new ArrayList<String>();
System.out.println(cars.size()); // 0
cars.add("BMW");
System.out.println(cars.size()); // 1
Well, in this case the car variable will be null, so dereferencing it (as you do when you access car.length) will throw a NullPointerException.
In fact, you can't access that variable at all until some value has definitely been assigned to it - otherwise the compiler will complain that "variable car might not have been initialized".
What is it you're trying to do here (it's not clear to me exactly what "solution" you're looking for)?
String car [];
is a reference to an array of String-s. You can't see a length because there is no array there!
This won't work. You first have to initialize the array. So far, you only have a String[] reference, pointing to null.
When you try to read the length member, what you actually do is null.length, which results in a NullPointerException.
Since you haven't initialized car yet so it has no existence in JVM(Java Virtual Machine) so you have to initialize it first.
For instance :
car = new String{"Porsche","Lamborghini"};
Now your code will run fine.
INPUT:
String car [];
car = new String{"Porsche","Lamborghini"};
System.out.println(car.length);
OUTPUT:
2
As all the above answers have suggested it will throw a NullPointerException.
Please initialise it with some value(s) and then you can use the length property correctly. For example:
String[] str = { "plastic", "paper", "use", "throw" };
System.out.println("Length is:::" + str.length);
The array 'str' is now defined, and so it's length also has a defined value.
I think you are looking for this
String[] car = new String[10];
int size = car.length;
In Java, we declare a String of arrays (eg. car) as
String []car;
String car[];
We create the array using new operator and by specifying its type:-
String []car=new String[];
String car[]=new String[];
This assigns a reference, to an array of Strings, to car.
You can also create the array by initializing it:-
String []car={"Sedan","SUV","Hatchback","Convertible"};
Since you haven't initialized an array and you're trying to access it, a NullPointerException is thrown.