This is reg. a requirement where I need to remove an element from List in java. I am getting unsupported exception when I try to remove element from List. Below is the code:
String[] str_array = {"abc","def","ght"};
List<String> results = Arrays.asList(str_array);
String tobeRemovedItem="";
for(int i=0;i<results.size();i++){
if(results.get(i).equalsIgnoreCase(searchString)) {
tobeRemovedItem=results.get(i);
}
}
if(!TextUtils.isEmpty(tobeRemovedItem)) {
results.remove(tobeRemovedItem); // I am getting exception here.
}
Can anyone help me in solving this issue?
The type of list returned by Arrays.asList does not support the remove operation. Hence the exception.
You can use the java.util.ArrayList instead.
List<String> results = new ArrayList<String>(Arrays.asList(str_array));
Answered already, but now without indirect datastructure of .asList()
List<String> results = new ArrayList<>();
Collections.addAll(results, str_array);
The .asList is backed by the array, hence you can modify the original array be modifying the list. And vice versa you cannot grow or shrink the list, as then the backed array object would need to be exchanged, as arrays are fixed in java.
The size of List returned by Arrays.asList cannot be changed. Instead you can do:
List<String> results = new ArrayList<>(Arrays.asList(str_array));
In general, UnsupportedOperationException is thrown by the implementation of an interface (or a child class of a class with an abstract method), where the implementor did not want to support that particular method.
That said, to debug these issues in the future, check which implementation you're using - in this case, it's given via the Arrays.asList() method from the Android sdk. Here you can see it says that it does not support adding or removing of items to the list.
If you must add and remove items, you can wrap the call into the ArrayList implementation of List which does support such modification (as suggested by Banthar and khelwood). The constructor takes a list as input, and copies the elements inside.
Related
I have a List<SomeBean> that is populated from a Web Service. I want to copy/clone the contents of that list into an empty list of the same type. A Google search for copying a list suggested me to use Collections.copy() method. In all the examples I saw, the destination list was supposed to contain the exact number of items for the copying to take place.
As the list I am using is populated through a web service and it contains hundreds of objects, I cannot use the above technique. Or I am using it wrong??!! Anyways, to make it work, I tried to do something like this, but I still got an IndexOutOfBoundsException.
List<SomeBean> wsList = app.allInOne(template);
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());
I tried to use the wsListCopy=wsList.subList(0, wsList.size()) but I got a ConcurrentAccessException later in the code. Hit and trial. :)
Anyways, my question is simple, how can I copy the entire content of my list into another List? Not through iteration, of course.
Just use this:
List<SomeBean> newList = new ArrayList<SomeBean>(otherList);
Note: still not thread safe, if you modify otherList from another thread, then you may want to make that otherList (and even newList) a CopyOnWriteArrayList, for instance -- or use a lock primitive, such as ReentrantReadWriteLock to serialize read/write access to whatever lists are concurrently accessed.
This is a really nice Java 8 way to do it:
List<String> list2 = list1.stream().collect(Collectors.toList());
Of course the advantage here is that you can filter and skip to only copy of part of the list.
e.g.
//don't copy the first element
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
originalArrayList.addAll(copyArrayofList);
Please keep on mind whenever using the addAll() method for copy, the contents of both the array lists (originalArrayList and copyArrayofList) references to the same objects will be added to the list so if you modify any one of them then copyArrayofList also will also reflect the same change.
If you don't want side effect then you need to copy each of element from the originalArrayList to the copyArrayofList, like using a for or while loop. for deep copy you can use below code snippet.
but one more thing you need to do, implement the Cloneable interface and override the clone() method for SomeBean class.
public static List<SomeBean> cloneList(List<SomeBean> originalArrayList) {
List<SomeBean> copyArrayofList = new ArrayList<SomeBean>(list.size());
for (SomeBean item : list) copyArrayofList.add(item.clone());
return copyArrayofList;
}
I tried to do something like this, but I still got an IndexOutOfBoundsException.
I got a ConcurrentAccessException
This means you are modifying the list while you are trying to copy it, most likely in another thread. To fix this you have to either
use a collection which is designed for concurrent access.
lock the collection appropriately so you can iterate over it (or allow you to call a method which does this for you)
find a away to avoid needing to copy the original list.
Starting from Java 10:
List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);
List.copyOf() returns an unmodifiable List containing the elements of the given Collection.
The given Collection must not be null, and it must not contain any null elements.
Also, if you want to create a deep copy of a List, you can find many good answers here.
There is another method with Java 8 in a null-safe way.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(Collection::stream)
.orElseGet(Stream::empty)
.collect(Collectors.toList());
If you want to skip one element.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(Collection::stream)
.orElseGet(Stream::empty)
.skip(1)
.collect(Collectors.toList());
With Java 9+, the stream method of Optional can be used
Optional.ofNullable(wsList)
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList())
I tried something similar and was able to reproduce the problem (IndexOutOfBoundsException). Below are my findings:
1) The implementation of the Collections.copy(destList, sourceList) first checks the size of the destination list by calling the size() method. Since the call to the size() method will always return the number of elements in the list (0 in this case), the constructor ArrayList(capacity) ensures only the initial capacity of the backing array and this does not have any relation to the size of the list. Hence we always get IndexOutOfBoundsException.
2) A relatively simple way is to use the constructor that takes a collection as its argument:
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);
I was having the same problem ConcurrentAccessException and mysolution was to:
List<SomeBean> tempList = new ArrayList<>();
for (CartItem item : prodList) {
tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);
So it works only one operation at the time and avoids the Exeption...
You can use addAll().
eg : wsListCopy.addAll(wsList);
re: indexOutOfBoundsException, your sublist args are the problem; you need to end the sublist at size-1. Being zero-based, the last element of a list is always size-1, there is no element in the size position, hence the error.
I can't see any correct answer. If you want a deep copy you have to iterate and copy object manually (you could use a copy constructor).
You should use the addAll method. It appends all of the elements in the specified collection to the end of the copy list. It will be a copy of your list.
List<String> myList = new ArrayList<>();
myList.add("a");
myList.add("b");
List<String> copyList = new ArrayList<>();
copyList.addAll(myList);
just in case you use Lombok:
mark SomeBean with the following annotation:
#Builder(toBuilder = true, builderMethodName = "")
and Lombok will perform a shallow copy of objects for you using copy constructor:
inputList.stream()
.map(x -> x.toBuilder().build())
.collect(Collectors.toList());
subList function is a trick, the returned object is still in the original list.
so if you do any operation in subList, it will cause the concurrent exception in your code, no matter it is single thread or multi thread.
I start learning the Java generic collection using Deitel Harvey book - but I am facing a difficulty understanding the three line of codes below - Do all of them perform the same operation on by intializing and adding the relevant values of array ( colors ) to the LinkList variable (list1). How does the second method and third method works - I am having a bit difficulty understanding how Arrays can viewed as a list.. As I know arrays are not dynamic data structure, they have fixed sized length, adding/ removing elements on array can not be done on running time comparing to Lists in general.
String[] colors = { "black", "white", "blue", "cyan" };
List< String > list1 = new LinkedList< String >();
// method 1 of initalizing and adding elments to the list
for (String color : colors)
list1.add(color);
// method 2 of initializing and adding elements to the list
List< String > list1 = new LinkedList< String > (Arrays.asList(colors));
// method 3 of initializing and adding elements to the list
List< String > list1 = Arrays.asList(colors);
Please help me understand my queries above, don't judge me as I am still new to this.
Thank you, Sinan
Actually knowledge of generics is not necessary for answering this question.
As you correctly identifier arrays are static in the sense that you can't add elements to them or remove them.
Lists, however, usually allow those operations.
The List returned by Arrays.asList() does have the add/remove methods (otherwise it would not be a valid List). However actually calling those methods will throw an UnsupportedOperationException exactly because you can't actually add elements to an array (for which this List is simply a view/wrapper).
Operations that don't structurally modify the list (i.e. that don't change the number of elements in the list) are entirely possible: set(int, E) works just fine on the List returned by Arrays.asList().
Arrays.asList returns a fixed-size list backed by the specified array.
It is actually a bridge between Array and Collection framework. But returned list write through to the array.
Only your first method does anything to the LinkedList you have initially assigned into list1. The other two assign a new, unrelated list to it. The third option assigns something that isn't a LinkedList, but a special implementation of the List interface backed by your String array. In the third case you won't be able to add/remove elements from the list, but you can iterate over it and update existing slots. Basically, it does what a plain array does, just through the List interface.
Arrays.asList creates a List from an Array. Arrays in general can't be viewed as lists in Java. They can only be wrapped in a list.
So method 2 is used to have a specific list implementation LinkedList in this case.
to Method 2, just check the Api here:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/LinkedList.html#LinkedList(java.util.Collection)
For sure, Lists implement the Collections Interface so this Constructor will work here.
to Method 3, just check out the Api here: http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html#asList(T...)
Every time you are interested in implementation you can look into certain method. For example, by press Ctrl+left mouse button onto method or class.
// method 2 of initializing and adding elements to the list
List<String> list1 = new LinkedList<String> (Arrays.asList(colors));
This code leads to:
List<String> list1 = new LinkedList<String> (new ArrayList<String>(colors));
In constructor of ArrayList:
ArrayList(E[] array) {
if (array==null)
throw new NullPointerException();
a = array;
}
the actual array is copied to encapsulated private array field(link is copied).
Then in constructor of LinkedList:
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
Every element of passed collection is added to the LinkedList.
if you see the link below
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/LinkedList.html#LinkedList%28java.util.Collection%29
you will see the constructor of linked list class which is accepting a collection object as parameter.
Any in your post, the 2nd and 3 rd lines are passing an object of collection class(i.e Arrays.asList is finally giving a List which is a sub class of collection).
So both 2nd and 3rd lines fairly valid implementations.
More over you can observe one more good coding practice in all the 3 lines.
That is
writing code to interceptors than to classes
. (referring
LinkedList
instance with
List
interface)
Always try to refer your classes with interceptors which is a good practice
I was looking around for some elegant solution to removing null values from a List. I came across the following post, which says I can use list.removeAll(Collections.singletonList(null));
This, however, throws an UnsupportedOperationException, which I'm assuming is because removeAll() is attempting to do some mutative operation on the immutable singleton collection. Is this correct?
If this is the case, what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
Thanks in advance.
It works like a charm:
List<String> list = new ArrayList<String>();
list.add("abc");
list.add(null);
list.add("def");
list.removeAll(Collections.singletonList(null));
System.out.println(list); //[abc, def]
Indeed Collections.singletonList(null) is immutable (which is unfortunately hidden in Java[1]), but the exception is thrown from your list variable. Apparently it is immutable as well, like in example below:
List<String> list = Arrays.asList("abc", null, "def");
list.removeAll(Collections.singletonList(null));
This code will throw an UnsupportedOperationException. So as you can see singletonList() is useful in this case. Use it when client code expects a read-only list (it won't modify it) but you only want to pass one element in it. singletonList() is (thread-)safe (due to immutability), fast and compact.
[1] E.g. in scala there is a separete hierarchy for mutable and immutable collections and API can choose whether it accept this or the other (or both, as they have common base interfaces)
To answer your actual question :
what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
The typical use is if you have one element and want to pass it to a method that accepts a List, ie
public void registerUsers(List<User> users) {...}
User currentUser = Login Manager.getCurrentUser();
registerUsers(Collections.singletonList(currentUser));
The removeAll() is a special case for this.
Has your list been protected with
Collections.unmodifiableList(list)
Because if you have protected it and try to modify it later you get that error.
I want to remove specific elements from my List. I don't want to do this while iterating through the list. I want to specify the value which has to be deleted. In javadocs I found the function List.remove(Object 0) This is my code :
String str="1,2,3,4,5,6,7,8,9,10";
String[] stra=str.split(",");
List<String> a=Arrays.asList(stra);
a.remove("2");
a.remove("3");
But I get an Exception : java.lang.UnsupportedOperationException
The problem is that Arrays.asList() returns a list that doesn't support insertion/removal (it's simply a view onto stra).
To fix, change:
List<String> a = Arrays.asList(stra);
to:
List<String> a = new ArrayList<String>(Arrays.asList(stra));
This makes a copy of the list, allowing you to modify it.
http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html#asList%28T...%29
See this. Arrays.asList returns a fixed list. Which is an immutable one. By its definition you cant modify that object once it creates.Thats why it is throwing unsupported exception.
People say that asList method convert the array into list and its not copying, so every change in 'aList' will reflect into 'a'. So add new values in 'aList' is illegal, since array have fixed size.
But, asList() method returns ArrayList<T>. How the compiler differentiates line 3 from 5. Line 3 gives me exception (UnsupportedOperationException).
String[] a = {"a","b","c","d"};//1
List<String> aList = Arrays.asList(a);//2
aList.add("e");//3
List<String> b = new ArrayList<String>();//4
b.add("a");//5
This List implementation you receive from Arrays.asList is a special view on the array - you can't change it's size.
The return type of Arrays.asList() is java.util.Arrays.ArrayList which is often confused with java.util.ArrayList. Arrays.ArrayList simply shows the array as a list.
Read again, the type of Arrays.asList is:
public static <T> List<T> asList(T... a)
which clearly states that asList returns an object that implements interface java.util.List, nowhere does it says it will return an instance of class java.util.ArrayList.
Next, notice that the documentation on List.add says:
boolean add(E e)
Appends the specified element to the end of this list (optional operation).
Technically, everytime you use a variable typed as List (instead of ArrayList), you should always be careful to expect that this method may throw UnsupportedOperationException. If you are sure that you will only receive a List implementation that always have the correct semantic of .add(), then you can omit the check at the risk of a bug when your assumption is invalidated.
Manoj,
The Return type of Arrays.List is some unknown internal implementation of the List interface and not java.util.ArrayList, so you can assign it only to a List type.
If you assign it to an ArrayList for instance it will give you compile time error
"Type mismatch: cannot convert from List to ArrayList"
ArrayList<String> aList = Arrays.asList(a);// gives Compile time error
From the Javadoc "Arrays.asList Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.) " that means that you are only provided a list view of the Array which IMO is created at runtime and ofcourse you cannot change the size of an array so you can't change size of "Arrays.asList" also.
IMO the internal implementation of Arrays.asList has all the implemented methods which can change the size of the Array as -
void add(E e)
{
//some unknown code
throw(java.lang.UnsupportedOperationException);
}
so whenever you attempt to alter the size of the Array it throws the UnsupportedOperationException.
Still if you want to add some new items to an ArrayList by using such a syntax, you can do so by creating a subclass of Arraylist(preferably by using anonymous subclass of ArrayList). You can pass the return type of Arrays.List to the constructor of ArrayList, (ie. public ArrayList(Collection c)) something like this -
List<String> girlFriends = new java.util.ArrayList<String>(Arrays.asList("Rose", "Leena", "Kim", "Tina"));
girlFriends.add("Sarah");
Now you can easily add Sarah to your GF list using the same syntax.
PS - Please select this one or another one as your answer because evrything has been explained. Your low Acceptance rate is very discouraging.
asList() doesn't return a java.util.ArrayList, it returns a java.util.Arrays$ArrayList. This class doesn't even extend java.util.ArrayList, so its behaviour can be (and is) completely different.
The add() method is inherited from java.util.AbstractList, which by default just throws UnsupportedOperationException.
You're assuming that Arrays.asList() returns an ArrayList, but that's not the case. Arrays.asList() returns an unspecified List implementation. That implementaton simply throws an UnsupportedOperationException on each unsupported method.
It's an exception and not a compiler error. It is thrown when the program is run and not at the compile time. Basically the actual class that Arrays.asList will return has a throw UnsupporteOperationException inside the add() method.
To be more specific Arrays.asList will return an inner class defined inside the Arrays class that is derived from AbstractList and does not implement the add method. The add method from the AbstractList is actually throwing the exception.
The key to this is the List implementation returned by
List<String> aList = Arrays.asList(a);
If you look at the source code in Arrays you will see that it contains an internal private static class ArrayList. This is not the same as java.util.ArrayList.
asList returns a fixed-size list, so that you cannot add new elements to it. Because the list it returns is really a "view" of the array it was created from ('a' in your case), it makes sense that you won't be able to add elements - just like you can't add elements to an array. See the docs for asList