I try to add objects to a List<String> instance but it throws an UnsupportedOperationException.
Does anyone know why?
My Java code:
String[] membersArray = request.getParameterValues('members');
List<String> membersList = Arrays.asList(membersArray);
for (String member : membersList) {
Person person = Dao.findByName(member);
List<String> seeAlso;
seeAlso = person.getSeeAlso();
if (!seeAlso.contains(groupDn)){
seeAlso.add(groupDn);
person.setSeeAlso(seeAlso);
}
}
The error message:
java.lang.UnsupportedOperationException
java.util.AbstractList.add(Unknown Source)
java.util.AbstractList.add(Unknown Source)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
Not every List implementation supports the add() method.
One common example is the List returned by Arrays.asList(): it is documented not to support any structural modification (i.e. removing or adding elements) (emphasis mine):
Returns a fixed-size list backed by the specified array.
Even if that's not the specific List you're trying to modify, the answer still applies to other List implementations that are either immutable or only allow some selected changes.
You can find out about this by reading the documentation of UnsupportedOperationException and List.add(), which documents this to be an "(optional operation)". The precise meaning of this phrase is explained at the top of the List documentation.
As a workaround you can create a copy of the list to a known-modifiable implementation like ArrayList:
seeAlso = new ArrayList<>(seeAlso);
Many of the List implementation support limited support to add/remove, and Arrays.asList(membersArray) is one of that. You need to insert the record in java.util.ArrayList or use the below approach to convert into ArrayList.
With the minimal change in your code, you can do below to convert a list to ArrayList. The first solution is having a minimum change in your solution, but the second one is more optimized, I guess.
String[] membersArray = request.getParameterValues('members');
ArrayList<String> membersList = new ArrayList<>(Arrays.asList(membersArray));
OR
String[] membersArray = request.getParameterValues('members');
ArrayList<String> membersList = Stream.of(membersArray).collect(Collectors.toCollection(ArrayList::new));
Form the Inheritance concept, If some perticular method is not available in the current class it will search for that method in super classes. If available it executes.
It executes AbstractList<E> class add() method which throws UnsupportedOperationException.
When you are converting from an Array to a Collection Obejct. i.e., array-based to collection-based API then it is going to provide you fixed-size collection object, because Array's behaviour is of Fixed size.
java.util.Arrays.asList( T... a )
Souce samples for conformation.
public class Arrays {
public static <T> List<T> asList(T... a) {
return new java.util.Arrays.ArrayList.ArrayList<>(a); // Arrays Inner Class ArrayList
}
//...
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
//...
}
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
//...
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
private class ListItr extends Itr implements ListIterator<E> {
//...
}
}
Form the above Source you may observe that java.util.Arrays.ArrayList class doesn't #Override add(index, element), set(index, element), remove(index). So, From inheritance it executes super AbstractList<E> class add() function which throws UnsupportedOperationException.
As AbstractList<E> is an abstract class it provides the implementation to iterator() and listIterator(). So, that we can iterate over the list object.
List<String> list_of_Arrays = Arrays.asList(new String[] { "a", "b" ,"c"});
try {
list_of_Arrays.add("Yashwanth.M");
} catch(java.lang.UnsupportedOperationException e) {
System.out.println("List Interface executes AbstractList add() fucntion which throws UnsupportedOperationException.");
}
System.out.println("Arrays → List : " + list_of_Arrays);
Iterator<String> iterator = list_of_Arrays.iterator();
while (iterator.hasNext()) System.out.println("Iteration : " + iterator.next() );
ListIterator<String> listIterator = list_of_Arrays.listIterator();
while (listIterator.hasNext()) System.out.println("Forward iteration : " + listIterator.next() );
while(listIterator.hasPrevious()) System.out.println("Backward iteration : " + listIterator.previous());
You can even create Fixed-Size array form Collections class Collections.unmodifiableList(list);
Sample Source:
public class Collections {
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
}
A Collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data.
#see also
HashMap vs HashTable
Object Serialization uses the Serializable and Externalizable interfaces
You will also get this exception if you attempt to add to a List<T> returned by Collections.singletonList(T o):
Returns an immutable list containing only the specified object. The returned list is serializable.
The JVM does not implement add() for Collections.singletonList
List membersList = Arrays.asList(membersArray);
returns immutable list, what you need to do is
new ArrayList<>(Arrays.asList(membersArray)); to make it mutable
You must initialize your List seeAlso :
List<String> seeAlso = new Vector<String>();
or
List<String> seeAlso = new ArrayList<String>();
You cannot modify a result from a LDAP query. Your problem is in this line:
seeAlso.add(groupDn);
The seeAlso list is unmodifiable.
instead of using add() we can use addall()
{ seeAlso.addall(groupDn); }
add adds a single item, while addAll adds each item from the collection one by one. In the end, both methods return true if the collection has been modified. In case of ArrayList this is trivial, because the collection is always modified, but other collections, such as Set, may return false if items being added are already there.
Related
Let's say I have a function similar to the following:
public static List<Integer> empty(List<Integer> list) {
List<Integer> empty = new ArrayList<>();
return empty;
}
which I want to return a List of the same implementation as the passed in list. For my example function, this is only true if the passed in list is an ArrayList. How do I initialize a List based on the implemenation of list (e.g. so the returned List would be a LinkedList if list was a LinkedList)?
Not sure why you need this. For me, it is a bad design. However, you can do it using reflection:
public static List<Integer> empty(List<Integer> list) throws InstantiationException, IllegalAccessException {
Class<? extends List> c = list.getClass();
return c.newInstance();
}
Note: above example only works if List implementation class have a public accessible empty constructor else you will get an exception.
so I was given an interface where one method I need to implement gives me a Collection and wants me to "addAll" the data in the collection to my object. I'm still not sure what exactly a collection is. Is it an array list? I don't belive it is, but can I use a for each loop for each piece of data in the collection? Or is there another way to iterate through the collect accessing all of the value.
Iterating a Collection<? extends E> can be done with an Iterator (and you can get one with Collection.iterator() which can iterate the Collection) like
public static <E> void iterateWithIterator(Collection<? extends E> coll) {
Iterator<? extends E> iter = coll.iterator();
while (iter.hasNext()) {
E item = iter.next();
// do something with the item.
}
}
or, with Java 5+, with a for-each loop like
public static <E> void forEachIterate(Collection<? extends E> coll) {
for (E item : coll) {
// do something with the item.
}
}
From the documentation of Collection :
The root interface in the collection hierarchy. A collection
represents a group of objects, known as its elements. Some collections
allow duplicate elements and others do not. Some are ordered and
others unordered.
You can iterate over it with for or for-each loop or using an Iterator.
The most common type of collections are :
Set
List
Deque
SortedSet
Queue
I want to initialize a Set Implementation (HashSet) in Java with an Iterable. However, the constructor of HashSet doesn't accept Iterables, but only Collections type objects.
Is there a way to convert from Iterable to some subtype of Collections.
You can use Guava.
Set<T> set = Sets.newHashSet(iterable);
or to make it read like a sentence static import,
import static com.google.common.collect.Sets.*;
Set<T> set = newHashSet(iterable);
HashSet constructor relies on more than what Iterable offers: it wants to know the size of the collection up front in order to optimally construct the underlying HashMap. If you have a true, austere Iterable, which doesn't know its size, then you'll have to realize the Iterable up front by turning it into a regular Collection in any of a number of obvious ways.
If, on the other hand, you have a richer object that already knows its size, then it would pay to create a minimalist adapter class that wraps your Iterable into a collection, implementing just size in addition to forwarding the call to iterator.
public class IterableCollection<T> implements Collection<T>
{
private final Iterable<T> iterable;
public IterableCollection(Iterable<T> it) { this.iterable = it; }
#Override public Iterator<T> iterator() { return iterable.iterator(); }
#Override public int size() { return ... custom code to determine size ... }
#Override .... all others ... { throw new UnsupportedOperationException(); }
}
Sure, it's shown in this answer. Basically, iterate over the iterable and copy its contents in a collection:
public static <T> List<T> copyIterable(Iterable<T> iterable) {
Iterator<T> iter = iterable.iterator();
List<T> copy = new ArrayList<T>();
while (iter.hasNext())
copy.add(iter.next());
return copy;
}
Use it as follows, the resulting List object can be passed as a parameter to the HashSet constructor.
Iterable<Integer> list = Arrays.asList(1, 2, 3);
List<Integer> copy = copyIterable(list);
Set<Integer> aSet = new HashSet<Integer>(copy);
EDIT
I've been mistaken all along. Iterable is a superinterface of Collection, so a simple (but unsafe) cast will do the trick, as long as the Iterable was a Collection to begin with.
Iterable<Integer> list = Arrays.asList(1, 2, 3);
Set<Integer> aSet = new HashSet<Integer>((Collection)list); // it works!
The Iterable interface allows the "foreach" syntax to work, so the cleanest way is likely:
public <T> Set<T> toSet(Iterable<T> collection) {
HashSet<T> set = new HashSet<T>();
for (T item: collection)
set.add(item);
return set;
}
Just add each one.
public static <T> Set<T> setFromIterable(Iterable<T> i) {
HashSet<T> set = new HashSet<T>();
Iterator<T> it = i.iterator();
while (it.hasNext()) {
set.add(it.next());
}
return set;
}
Iterable<Integer> someIterable = ...;
Set<Integer> someSet = setFromIterable(someIterable);
Note that you don't use the constructor new HashSet<Integer>(someIterator), because that doesn't exist. Just call the static method.
I use this one-liner (with Java 8+), which only relies on java.util.stream:
StreamSupport.stream(myIterable.spliterator(), false).collect(Collectors.toSet());
// or with static imports:
stream(myIterable.spliterator(), false).collect(toSet());
Putting somewhat a repeated answer for conciseness. Below worked for me for converting the Iterable of String type to a Set(Java8).
Iterable<String> stringIterable = Arrays.asList("str1", "str2", "str3");
Set<String> stringHashSet = new HashSet<>((Collection<? extends String>) stringIterable);
I have a function f that gets a sublist of a LinkedList and passes it to g, which also takes a LinkedList:
public static <T> void g(LinkedList<T> l) {
}
public static <T> void f() {
LinkedList<T> l = new LinkedList<T>();
...
LinkedList<T> l2 = l.subList(i,j);
...
g(l2);
}
But this doesn't compile, because apparently LinkedList.subList returns List instead of LinkedList. So I have to change it to this:
LinkedList<T> l2 = (LinkedList<T>)l.subList(i,j);
Why?
subList is defined in the List interface and returns a List. And if you check the implementation in LinkedList, which is actually in one of the parent classes (AbstractList), you will see that it does not return a LinkedList but a SubList and your cast will throw an exception.
Unless you use methods specific to LinkedList, the easiest way to fix this would be to change g to:
public static <T> void g(List<T> l) {
if g() doesn't use the method of LinkedList but only the List interface is preferable to define g() as follow:
public static <T> void g( List<T> l ) {
}
and the main becomes:
public static <T> void f() {
List<T> l = new LinkedList<T>();
...
List<T> l2 = l.subList(i,j);
...
g(l2);
}
For a justification, please consult this post.
The method sublist is declared in the List interface which is implemented by LinkedList. The signature of the sublist method in the List interface is:
List<E> subList(int fromIndex, int toIndex)
Thus whenever you call this method from a LinkedList class, the object will be of LinkedList, but return type of the method is List, thus it will be given in the form of List. However, you can cast the variable to LinkedList and use it.
You can't instantiate 'Objects' such List. List is an interface, not a concrete class.
An interface is just a set of functions that a class can implement; it doesn't make any sense to instantiate an interface.
Hope it helps.
Clemencio Morales Lucas.
Java wants as much polymorphism as you can get, so subList returns List, and you have to cast it to what you want.
If I have a method like this (for simplicity assume integers):
public static List<Integer> doSomething(List<Integer> list) {
// logic here
}
and I need for my processing to create internally a new list which I will create and somehow populate and return to the caller, how can I do it since I don't know what type of list the caller passed in?
I don't want to return a List of different type that what the caller passed in.
E.g. If the caller passed a LinkedList and I don't want to return an ArrayList.
How can this issue best be approached?
You shouldn't tie your implementation to a particular implementation of List, the idea of using an interface is that, from the outside, it shouldn't matter what concrete class you're instantiating as long as it conforms to the List interface.
EDIT :
Anyway, here's a possible way:
List<Integer> lst1 = new ArrayList<Integer>();
Class<?> klass1 = lst1.getClass();
List<Integer> copy1 = (List<Integer>) klass1.newInstance();
System.out.println(copy1.getClass().getName());
> java.util.ArrayList
List<Integer> lst2 = new LinkedList<Integer>();
Class<?> klass2 = lst2.getClass();
List<Integer> copy2 = (List<Integer>) klass2.newInstance();
System.out.println(copy2.getClass().getName());
> java.util.LinkedList
As you can see in the console, the copies are instances of the same class as the original list.
If you can get away with just using one of those two output types, then you can do
if (inputList instanceof RandomAccess) {
// use an ArrayList
} else {
// use a LinkedList.
}
The RandomAccess interface is meant to indicate that the implementation allows O(1) get operations.
Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.
By doing this, your APIs allow clients to defend their inputs. They can pass in the result of Collections.unmodifiableList(...) and be sure that it isn't modified by other code.
If you really know the input is a mutable list, you can clone() the list, then clear() it. Both ArrayList and LinkedList have public clone() methods which can be accessed reflectively.
The best thing to do is to remove the list creation from the method. Have the caller decide how to create the list:
public static void doSomething(List<Integer> dest, List<Integer> src) {
You could use Class.newInstance to create a list of the passed in type:
public static List<Integer> doSomething(List<Integer> list)
{
List<Integer> newList = null;
try
{
newList = list.getClass().newInstance();
}
catch(InstantiationException e)
{
throw new RuntimeException(e);
}
catch(IllegalAccessException e)
{
throw new RuntimeException(e);
}
//Logic here
return newList;
}
#Test
public void test()
{
List<Integer> testList = new ArrayList<Integer>();
List<Integer> resultList = doSomething(testList);
Assert.assertEquals(testList.getClass(), resultList.getClass());
Assert.assertNotSame(LinkedList.class, resultList.getClass());
testList = new LinkedList<Integer>();
resultList = doSomething(testList);
Assert.assertEquals(testList.getClass(), resultList.getClass());
Assert.assertNotSame(ArrayList.class, resultList.getClass());
}
If you really, really care what kind of object comes out, I would include that as a parameter to the method, like:
<T extends List<Integer>> T doSomething(Class<T> returnType,List<Integer> v)
throws Exception
{
// constructors for your return will be tricky :)
// returnType.newInstance() will probably work.
T result = returnType.newInstance();
result.add(86); result.add(99);
return result;
}