I have a class like this
#Getter
public class MyClass {
private Collection<String> headers;
public myConfig(DownloadRequest downloadRequest) {
this.headers = downloadRequest.getHeaders() == null ? new ArrayList() : downloadRequest.getHeaders();
}
}
When I run this it gives me java.lang.UnsupportedOperationException.
As I use headers in another function and do getHeaders().clear(), I get this error.
Return type of downloadRequest.getHeaders() is Collection<String>
I am unable to figure out what I can cast the headers to.
I keep getting different Exceptions as I change my code, like UnsupportedOperationException and java.lang.ClassCastException: java.util.Arrays$ArrayList incompatible with java.util.ArrayList, when I change the code to something else, trying out other StackOverflow solutions like this - Why do I get an UnsupportedOperationException when trying to remove an element from a List?.
I have just started working on Java and have been working more on python and nodejs in the past.
Any help is appreciated.
The problem is that Collection#clear(), as mentioned in the docs is an optional operation and not all implementations need to support it. If they do not, they can throw UnsupportedOperationException. In your case, the list returned from downloadRequest.getHeaders() is apparently an unmodifiable collection which does not support this operation.
If it did, calling clear() on it would remove all headers from the downloadRequest. Is that what you're trying to achieve? Probably not. If yes, instead there should be a method like downloadRequest.clearHeaders().
To work around this problem, you can copy the elements out of an unmodifiable collection into e.g. an ArrayList:
new ArrayList<>(downloadRequest.getHeaders())
This copies the elements out of the original container into a new modifiable ArrayList that you can then modify however you like.
Also note you're mentioning java.util.Arrays$ArrayList which is named ArrayList, but it is not java.util.ArrayList. This is an unresizable collection returned from Arrays.asList(...) and it does not support clear() either.
The downloadRequest.getHeaders() method may return a Collection that is read-only and so doesn't support .clear()
You may use an ArrayList to wrap it and get a write-accessible structure
// private list<String> headers;
Collection<String> headers = downloadRequest.getHeaders();
this.headers = headers == null ? new ArrayList<>() : new ArrayList<>(headers) ;
I think you may be using the wrong ArrayList class when doing new ArrayList()
From your ClassCastException you are using :
java.util.Arrays$ArrayList, which is a nested class of the Arrays class and is immutable.
Check your import : you should be using java.util.ArrayList.
Edit : never mind this nested class is private; previous answer is probably right, the collection returned must be immutable.
Related
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.
I got a method
foo(list);
that get's a
List<SomeEntit>
as input.
My method foo looks somewhat like the following:
public void foo(List<SomeEntity someEntities) {
someEntities.add(anotherEntity);
}
I then get an "javax.ejb.EJBException: java.lang.UnsupportedOperationException" caused by "java.lang.UnsupportedOperationException: null" at "at java.util.AbstractList.add(AbstractList.java:148)"
Can you tell me why this is happening? I hope that my code example is not too minimal.
Some lists are unmodifiable. The operation of adding elements is then "unsupported".
Java collections framework does not have a distinct type for unmodifiable lists or other unmodifiable collections. You never really know if it is allowed to add something.
All you can do is to specify that the list that is passed must be modifiable.
It seems that the actual type of the List you get as the input does not override the add method.
Try converting that list to a list implementation that does, like ArrayList:
List<SomeEntity> newList = new ArrayList<>(list);
foo(newList);
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.
This one list object is biting me in the butt..
Any time I try to add an element to it, it produces this:
Caused by: java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
The line producing the error is insignificant, but here it is anyways:
AdventureLobbies.players.add(args[0].toLowerCase());
Should I not be accessing it statically?
Actual declaration of variable:
AdventureLobbies.players = Arrays.asList(rs.getString("players").toLowerCase().split(","));
Any ideas? Can't find anything on Google that's worthwhile.
Arrays.asList() will give you back an unmodifiable list, and that is why your add is failing. Try creating the list with:
AdventureLobbies.players = new ArrayList(Arrays.asList(rs.getString("players").toLowerCase().split(",")));
The java docs say
asList
#SafeVarargs
public static <T> List<T> asList(T... a)
"Returns a fixed-size list backed by the specified array"
Your list is fixed size, meaning it cannot grow or shrink and so when you call add, it throws an unsupported operation exception
This exception is very familiar with accessing objects that will not permit the access according to java language rules like accessing immutable objects, for that reason instantiate it in the following way instead:
AdventureLobbies.players = new ArrayList(Arrays.
asList(rs.getString("players").toLowerCase().split(","))); // Perfectly done
I have a List that is guaranteed to contain just one type object. This is created by some underlying code in a library that I cannot update. I want to create a List<ObjectType> based on the incoming List object so that my calling code is talking to List<ObjectType>.
What's the best way to convert the List (or any other object collection) to a List<ObjectType>.
When inter-operating with legacy code that doesn't specify type parameters for generic types, use a wildcard. For example, suppose you are calling a method in an older library that simply returns a raw Collection:
Collection getItems();
In your code, assign the result to a variable declared with a wildcard:
Collection<?> items = widget.getItems();
This way, you preserve type safety so you won't get any warnings.
The legacy code might specify (in a comment, most likely) what the generic parameters should be. For example:
/**
* #return the items, as a Collection of {#link Item} instances.
*/
Collection getItems();
In this case, you have a choice. You can cast the result to a Collection<Item>, but if you do so, you are relying 100% on the third-party library, and discarding the assurance of Java generic types: that any ClassCastException raised at runtime will occur right at an explicit cast.
What if you don't fully trust the third-party library, but still need to produce a Collection<Item>? Then create a new collection, and add the contents after casting them to the expected type. That way, if there is a bug in the library, you find out about it right away, rather than having some code far away and much later mysteriously blow up with a ClassCastException.
For example:
Collection<?> tmp = widget.getItems();
Collection<Item> items = new ArrayList<Item>(tmp.size());
for (Object o : tmp)
items.add((Item) o); /* Any type error will be discovered here! */
For a case where the type parameter isn't known at compile-time, you can use the type-checked collection factories of the Collections class.
You can simply cast the list:
List raw = new ArrayList();
List<String> generic = (List<String>) raw;
The best and safest way is to use java.util.Collections method 'checkedList(List list, Class type)'
With this method, all of the items in your old List will be checked as early as possible.
If you just cast to List<T> in any old place you will get an "unchecked" compiler warning. We resolved that by moving it to a utility method.
public class Lists {
#SuppressWarnings({"unchecked"})
public static <T> List<T> cast(List<?> list) {
return (List<T>) list;
}
}
Caller now gets no warning, e.g.:
for (Element child : Lists.<Element>cast(parent.getChildren())) {
// ...
}
That checkedList utility is in theory a great idea, but in practice it sucks to have to pass in the class you expect. I hope Java will get runtime generic typing information eventually.
Try this:
List<ObjectType> objectsWithType = Arrays.asList((ObjectType[])wildcardObjects).toArray());
But remember that this will produce a fixed length List. If you try to add or remove element from this list, it will throw an error. So be always careful while using Arrays.asList().