This question already has answers here:
Immutable array in Java
(15 answers)
Closed 8 years ago.
I have following piece of code :
final int[] a = new int[5];
a[0] = 10;
a[0] = 5;
this code is perfectly fine as I am modifying the object and not the reference but now I want something like this :
int[] a = final new int[5];
so line 3 above will fire an error that I am trying to change immutable array. Is there any simple way to do it? There is a function in collections but I don't want to use any type of collection.
Is there any simple way to do it?
With a plain array, no. Arrays will always be mutable, so if you want this functionality you'll have to wrap an array and provide a mechanism for reading it (and not one for writing to it). There are already utilities in the standard JDK classes that can do this for you, like in Collections as you state.
You can, for example, use an unmodifiable list as returned by Collections.unmodifiableList instead. For example, to create an unmodifiable list containing 1, 2 and 3:
List<Integer> a = Collections.unmodifiableList(Arrays.asList(1, 2, 3));
Without some sort of wrapper (be it standard or not), what you're asking for can't be done.
If you declare:
final int[] myarray = new int[5];
it will not make your array immutable as you expect. The reference myarray will be final, but contents of this array can be changed.
As you do not want to use Collections Framework, make your own wrapper class over your array, to prevent modifying it's contents. And it will make your array immutable.
Related
This question already has an answer here:
Declaring an Array and altering its contents [duplicate]
(1 answer)
Closed 8 years ago.
List<Object[]> d = new ArrayList<Object[]>();
d.add({"A"});//compile error
Object [] arr = {"A"};//valid
I always thought that last 2 rows make equally operations and regulated by similar rules.
Who can it explain?
It's not about passing arguments to method. You can only use the {x} shorthand while initializing an array, such as your valid example. Anywhere else it's invalid. If you need to instantiate an array at a later time after initialization, you need to use new int[].
int[] a = {1,2}; // OK
int[] b;
b = {1,2}; // compiler error
I always thought that last 2 rows make equally operations and regulated by similar rules.
You were wrong.
Who can it explain?
I can't explain why you were wrong, but I can explain the syntax. The final line is valid because it is an initialisation, and initialisations have special syntax. If you had split it into a declaration and an assignment you would have got the same error in the assignment that you got in the second line. That syntax for a value simply does not exist in Java.
You can't use an array initializer as an argument.
In the first case
d.add({"A"});//compile error
You need to create a new instance of Object[] to serve as the method argument like this:
d.add(new Object[]{"A"});
In the second case, you create an array of Object. You can also do the similar thing:
Object [] arr = new Object[] {"A"};
Java lets you do the following because I think it maintains some compatibility with C/C++ array definition in the original design.
Object [] arr = {"A"};//valid
This question already has answers here:
Why won't declaring an array final make it immutable in Java?
(6 answers)
Why can I edit the contents of a final array in Java?
(9 answers)
Closed 9 years ago.
I tried using final keyword to array but still i can change the values, why arrays are not supporting final.
Thanks in advance
Because final applies to the array reference, not the contents.
You can modify the array content, but you can't say, reinstantiate the array.
Arrays in java are reference types. When you declare an array final, you are declaring the array object reference itself final, not the elements the array contains. So while you cannot alter the array reference, you can still alter individual elements in the array.
To get the effect you want, you'll have to use Collections.unmodifiableList or something similar.
Consider these
final int a[]={11,2};
int b[]={};
a=b;// this will compile wrong
a[1]=1;//this will compile fine
Because if you are declaring final array then it means that the array reference can not be changed but you can obviously change the content
Arrays are supported, but it's no different for any other reference variables: you can change the state of the variable, but you can't change the object that the variable refers to, here the array object. For arrays, the state are the item references.
final int[] test = new int[3];
test = new int[2]; //Error here
(final applies to the reference, not the object data)
If you need an immutable data structure, List (you can use ArrayList if desired) is where you'll want to go. If you really need it to be an array, you'll need to create your own data structure with only getter methods.
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
This question already has answers here:
Type List vs type ArrayList in Java [duplicate]
(15 answers)
List versus ArrayList as reference type?
(3 answers)
Closed 9 years ago.
Is there a difference between these two? If so, what is it?
List<Integer> x = new ArrayList<Integer>();
and
ArrayList<Integer> x = new ArrayList<Integer>();
The first declaration lets you program to interface. It ensures that later on you can safely replace ArrayList with, say, LinkedList, and the rest of code is going to compile.
The second declaration lets you program to the class, so you could potentially use methods of ArrayList which do not implement the List interface. For example, you can call ensureCapacity() on the list declared as ArrayList, but not on a list declared as List. Although generally programming to interface should be preferred, there is nothing wrong with doing it if you must call class-specific methods: for example, ability to call ensureCapacity() could save some unnecessary reallocations if you know the new target size of your list.
The former is preferred. It allows changing the implementation without changing code that depends on the field.
In Effective Java, Joshua Bloch says:
If appropriate interface types exist, then parameters, return values, variables and fields should all be declared using interface types.
...
If you get into the habit of using interfaces as types, your program will be much more flexible.
If you code to interfaces then you can change the implementation without much hassle
List<Integer> x = new ArrayList<Integer>();
you can make x now point to a LinkedList or any other implementation of List with only one line of code. If you need a specific method that is in ArrayList then having ArrayList on the left hand side is perfectly acceptable. 99 times out of 100 thought you wont so List is preferred
With ArrayList you can specify an intitalsize and so ArrayList has trimToSize() method to trim its size to the current size.With List<Integer> you won't be able to trim the size unless you cast it back to ArrayList
This question already has answers here:
Empty an array in Java / processing
(8 answers)
Closed 2 years ago.
I would like to remove all the elements in the String array for instance:
String example[]={"Apple","Orange","Mango","Grape","Cherry"};
Is there any simple to do it,any snippet on it will be helpful.Thanks
If example is not final then a simple reassignment would work:
example = new String[example.length];
This assumes you need the array to remain the same size. If that's not necessary then create an empty array:
example = new String[0];
If it is final then you could null out all the elements:
Arrays.fill( example, null );
See: void Arrays#fill(Object[], Object)
Consider using an ArrayList or similar collection
example = new String[example.length];
If you need dynamic collection, you should consider using one of java.util.Collection implementations that fits your problem. E.g. java.util.List.
Reassign again. Like example = new String[(size)]
list.clear() is documented for clearing the ArrayList.
list.removeAll() has no documentation at all in Eclipse.
Usually someone uses collections if something frequently changes.
E.g.
List<String> someList = new ArrayList<String>();
// initialize list
someList.add("Mango");
someList.add("....");
// remove all elements
someList.clear();
// empty list
An ArrayList for example uses a backing Array. The resizing and this stuff is handled automatically. In most cases this is the appropriate way.
Just Re-Initialize the array
example = new String[size]
or If it is inside a running loop,Just Re-declare it again,
**for(int i=1;i<=100;i++)
{
String example = new String[size]
//Your code goes here``
}**
This question already has answers here:
Create ArrayList from array
(42 answers)
Initialization of an ArrayList in one line
(34 answers)
Closed 6 years ago.
I am aware that you can initialize an array during instantiation as follows:
String[] names = new String[] {"Ryan", "Julie", "Bob"};
Is there a way to do the same thing with an ArrayList? Or must I add the contents individually with array.add()?
Arrays.asList can help here:
new ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21));
Yes.
new ArrayList<String>(){{
add("A");
add("B");
}}
What this is actually doing is creating a class derived from ArrayList<String> (the outer set of braces do this) and then declare a static initialiser (the inner set of braces). This is actually an inner class of the containing class, and so it'll have an implicit this pointer. Not a problem unless you want to serialise it, or you're expecting the outer class to be garbage collected.
I understand that Java 7 will provide additional language constructs to do precisely what you want.
EDIT: recent Java versions provide more usable functions for creating such collections, and are worth investigating over the above (provided at a time prior to these versions)
Here is the closest you can get:
ArrayList<String> list = new ArrayList(Arrays.asList("Ryan", "Julie", "Bob"));
You can go even simpler with:
List<String> list = Arrays.asList("Ryan", "Julie", "Bob")
Looking at the source for Arrays.asList, it constructs an ArrayList, but by default is cast to List. So you could do this (but not reliably for new JDKs):
ArrayList<String> list = (ArrayList<String>)Arrays.asList("Ryan", "Julie", "Bob")
Arrays.asList("Ryan", "Julie", "Bob");
Well, in Java there's no literal syntax for lists, so you have to do .add().
If you have a lot of elements, it's a bit verbose, but you could either:
use Groovy or something like that
use Arrays.asList(array)
2 would look something like:
String[] elements = new String[] {"Ryan", "Julie", "Bob"};
List list = new ArrayList(Arrays.asList(elements));
This results in some unnecessary object creation though.
The selected answer is: ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21));
However, its important to understand the selected answer internally copies the elements several times before creating the final array, and that there is a way to reduce some of that redundancy.
Lets start by understanding what is going on:
First, the elements are copied into the Arrays.ArrayList<T> created by the static factory Arrays.asList(T...).
This does not the produce the same class as java.lang.ArrayListdespite having the same simple class name. It does not implement methods like remove(int) despite having a List interface. If you call those methods it will throw an UnspportedMethodException. But if all you need is a fixed-sized list, you can stop here.
Next the Arrays.ArrayList<T> constructed in #1 gets passed to the constructor ArrayList<>(Collection<T>) where the collection.toArray() method is called to clone it.
public ArrayList(Collection<? extends E> collection) {
......
Object[] a = collection.toArray();
}
Next the constructor decides whether to adopt the cloned array, or copy it again to remove the subclass type. Since Arrays.asList(T...) internally uses an array of type T, the very same one we passed as the parameter, the constructor always rejects using the clone unless T is a pure Object. (E.g. String, Integer, etc all get copied again, because they extend Object).
if (a.getClass() != Object[].class) {
//Arrays.asList(T...) is always true here
//when T subclasses object
Object[] newArray = new Object[a.length];
System.arraycopy(a, 0, newArray, 0, a.length);
a = newArray;
}
array = a;
size = a.length;
Thus, our data was copied 3x just to explicitly initialize the ArrayList. We could get it down to 2x if we force Arrays.AsList(T...) to construct an Object[] array, so that ArrayList can later adopt it, which can be done as follows:
(List<Integer>)(List<?>) new ArrayList<>(Arrays.asList((Object) 1, 2 ,3, 4, 5));
Or maybe just adding the elements after creation might still be the most efficient.
How about this one.
ArrayList<String> names = new ArrayList<String>();
Collections.addAll(names, "Ryan", "Julie", "Bob");
This is how it is done using the fluent interface of the op4j Java library (1.1. was released Dec '10) :-
List<String> names = Op.onListFor("Ryan", "Julie", "Bob").get();
It's a very cool library that saves you a tonne of time.