Benefits of creating a List using Arrays.asList() [duplicate] - java

This question already has answers here:
Why does Arrays.asList() return its own ArrayList implementation
(6 answers)
Closed 5 years ago.
Referring to Difference between Arrays.asList(array) vs new ArrayList<Integer>(Arrays.asList(ia)) in java
I was curious as in what's the exact purpose of Arrays.asList() method.
When we create a new List from it, say for example -
Integer[] I = new Integer[] { new Integer(1), new Integer(2), new Integer(3) };
List<Integer> list1 = Arrays.asList(I);
List<Integer> list2 = ((List<Integer>) Arrays.asList(I));
We cannot perform most of the the regular operations on it like .add(), .remove(). Thus, I was not able add an iterator to it to avoid concurrent modification.
Oracle docs state
public static List asList(T... a)
Returns a fixed-size list backed by the specified array. (Changes to
the returned list "write through" to the array.) This method acts as
bridge between array-based and collection-based APIs, in combination
with Collection.toArray(). The returned list is serializable and
implements RandomAccess.
It works well with creating a new List. List<Integer> list3 = new ArrayList<>(Arrays.asList(I));
So, why this and what are its advantages and disadvantages?

Not being able to call add, remove, etc is the exact difference. If you don't need those methods, Arrays.asList gives you a perfectly fine view of the array as a List (for APIs that take collections rather than arrays). If you need to change the "shape" of the list, then new ArrayList<>(Arrays.asList(myArray)) is the way to go.

Related

List addAll(aList) then aList.clear(): will I get null if the implementation is not ArrayList neither LinkedList? [duplicate]

This question already has answers here:
clearing or set null to objects in java
(7 answers)
Closed 1 year ago.
List interface does not enforce copy of added elements in the Javadoc, but ArrayList and LinkedList both copy them (if I understand the source code correctly).
So, am I safe to clear() the added list in this code? I assume not?
#Test
void test() {
List<MyObject> original = new ArrayList<>();
original.add(new MyObject("John", 1));
original.add(new MyObject("David", 2));
List<MyObject> newList = new LinkedList<>(); // or ArrayList, both can pass the test, but not sure about other impl.
newList.addAll(original);
original.clear();
System.gc();
for (MyObject o: newList) {
assertThat(o, CoreMatchers.notNullValue());
}
}
In a code review and see such issue, the added list is cleared after addAll(), not sure about if I can let this pass.
Both LinkedList.addAll() and ArrayList.addAll() copy the elements over to the new list. LinkedList.addAll() internally calls toArray(), and ArrayList.addAll() calls arraycopy().
so a call on original.clear() should only affect original, but not newList.
I can think of one list implementation that behaves slightly differently:
CopyOnWriteArrayList.addAll() has an exception so it just takes the source's array if the source is another CopyOnWriteArrayList. But then, all write operations, including clear, start from scratch. So in the end, the behaviour on clear() should still be the same.

I cannot add in a List [duplicate]

This question already has answers here:
UnsupportedOperationException when trying to remove from the list returned by Array.asList
(6 answers)
Closed 3 years ago.
I have next code:
List<String> str=Arrays.asList("cat","tiger","dog","mouse");
str.add("horse");
It compiles, but at runtime I have UnsupportedOperationException. Why does it happen?
Arrays.asList(String...) creates an unmodifiable array. Wrap it with another ArrayList like so:
List<String> str = new ArrayList<>(Arrays.asList("cat","tiger","dog","mouse"));
str.add("horse");
this called backed list .
backed list it's created when you convert an array to list but keep in your mind the element in the array is linked with the element in the list so you cant add or delete any thing and you are using varargs its similar to array ,
Arrays.asList() returns a list that is fixed-size and backed by the array you pass so you can't add or remove elements because that would mean changing the array as well. (note that if you have a look at the source you'll find that Arrays.asList() will return an instance of java.util.Arrays.ArrayList which you should not confuse with java.util.ArrayList which you probably already know).
Instead you'd need to create another list, e.g via calling new ArrayList<String>( Arrays.asList(...)) which effectively makes a copy of the passed list.
A Java 8+ way might be this:
List<String> str = Stream.of( "cat","tiger","dog","mouse" ).collect( Collectors.toList() );

How to sort a list without mutating it

I would like to sort a List of items in Java and have the sort return a new sorted List without mutating the original List. Is there a commonly used library that does this?
If you are using Java 8 or higher, you can use the Stream API. See Sorting a list with stream.sorted() in Java for details.
For example:
List<String> sortedList = myList.stream().sorted().collect(Collectors.toList());
This copies (by reference) the elements in the original list to the new list. Making changes like the ordering of one list won't affect the other.
List<String> originalList = new ArrayList<String>();
List<String> newList = new ArrayList(originalList);
Please note if you modify the objects that are in the list however, the changes will be reflected in both lists since objects are copied by reference.

How to quickly and conveniently create a one element arraylist [duplicate]

This question already has answers here:
Initialization of an ArrayList in one line
(34 answers)
Closed 6 years ago.
Is there a Utility method somewhere that can do this in 1 line? I can't find it anywhere in Collections, or List.
public List<String> stringToOneElementList(String s) {
List<String> list = new ArrayList<String>();
list.add(s);
return list;
}
I don't want to re-invent the wheel unless I plan on putting fancy rims on it.
Well... the type can be T, and not String. but you get the point. (with all the null checking, safety checks...etc)
Fixed size List
The easiest way, that I know of, is to create a fixed-size single element List with Arrays.asList(T...) like
// Returns a List backed by a varargs T.
return Arrays.asList(s);
Variable size List
If it needs vary in size you can construct an ArrayList and the fixed-sizeList like
return new ArrayList<String>(Arrays.asList(s));
and (in Java 7+) you can use the diamond operator <> to make it
return new ArrayList<>(Arrays.asList(s));
Single Element List
Collections can return a list with a single element with list being immutable:
Collections.singletonList(s)
The benefit here is IDEs code analysis doesn't warn about single element asList(..) calls.
Collections.singletonList(object)
the list created by this method is immutable.
You can use the utility method Arrays.asList and feed that result into a new ArrayList.
List<String> list = new ArrayList<String>(Arrays.asList(s));
Other options:
List<String> list = new ArrayList<String>(Collections.nCopies(1, s));
and
List<String> list = new ArrayList<String>(Collections.singletonList(s));
ArrayList(Collection) constructor.
Arrays.asList method.
Collections.nCopies method.
Collections.singletonList method.
With Java 7+, you may use the "diamond operator", replacing new ArrayList<String>(...) with new ArrayList<>(...).
Java 9
If you're using Java 9+, you can use the List.of method:
List<String> list = new ArrayList<>(List.of(s));
Regardless of the use of each option above, you may choose not to use the new ArrayList<>() wrapper if you don't need your list to be mutable.
With Java 8 Streams:
Stream.of(object).collect(Collectors.toList())
or if you need a set:
Stream.of(object).collect(Collectors.toSet())
The other answers all use Arrays.asList(), which returns an unmodifiable list (an UnsupportedOperationException is thrown if you try to add or remove an element). To get a mutable list you can wrap the returned list in a new ArrayList as a couple of answers point out, but a cleaner solution is to use Guava's Lists.newArrayList() (available since at least Guava 10, released in 2011).
For example:
Lists.newArrayList("Blargle!");
Very simply:
Arrays.asList("Hi!")
Seeing as Guava gets a mention, I thought I would also suggest Eclipse Collections (formerly known as GS Collections).
The following examples all return a List with a single item.
Lists.mutable.of("Just one item");
Lists.mutable.with("Or use with");
Lists.immutable.of("Maybe it must be immutable?");
Lists.immutable.with("And use with if you want");
There are similar methods for other collections.
Yet another alternative is double brace initialization, e.g.
new ArrayList<String>() {{ add(s); }};
but it is inefficient and obscure. Therefore only suitable:
in code that doesn't mind memory leaks, such as most unit tests and other short-lived programs;
and if none of the other solutions apply, which I think implies you've scrolled all the way down here looking to populate a different type of container than the ArrayList in the question.

How to add elements in List when used Arrays.asList()

We cannot perform <Collection>.add or <Collection>.addAll operation on collections we have obtained from Arrays.asList .. only remove operation is permitted.
So What if I come across a scenario where I require to add new Element in List without deleting previous elements in List?. How can I achieve this?
Create a new ArrayList using the constructor:
List<String> list = new ArrayList<String>(Arrays.asList("a", "b"));
One way is to construct a new ArrayList:
List<T> list = new ArrayList<T>(Arrays.asList(...));
Having done that, you can modify list as you please.
Arrays.asList(),generates a list which is actually backed by an array and it is an array which is morphed as a list. You can use it as a list but you can't do certain operations on it such as adding new elements. So the best option is to pass it to a constructor of another list obj like this:
List<T> list = new ArrayList<T>(Arrays.asList(...));
You can get around the intermediate ArrayList with Java8 streams:
Integer[] array = {1, 2, 3};
List<Integer> list = Streams.concat(Arrays.stream(array),
Stream.of(4)).collect(Collectors.toList());
This should be pretty efficient as it can just iterate over the array and also pre-allocate the target list. It may or may not be better for large arrays. As always, if it matters you have to measure.
The Constructor for a Collection, such as the ArrayList, in the following example, will take the array as a list and construct a new instance with the elements of that list.
List<T> list = new ArrayList<T>(Arrays.asList(...));
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection)
These days the streams API can easily get you an ArrayList in a concise and functional manner:
Stream.of("str1", "str2").collect(Collectors.toList()));
Of course this also has the flexibility to transform using mappings. For example, while writing unit tests for Spring security code it was convenient to write the following:
Stream.of("ROLE_1", "ROLE_2").map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
The list returned by Collectors.toList is an ArrayList and may be modified as required by your code.
Arrays.asList()
generates an unmodifiable list on object creation. You can use the below code.
List list = Collections.synchronizedList(new ArrayList(...));
This convert allows the list to add and remove objects. I have only tested in java 8.
ArrayList<Object> MyObjectList = new ArrayList<>();
Arrays.asList(params[1]).forEach((item)-> {
MyObjectList.add(item);
});

Categories