Why retainAll in ArrayList throws an Exception - java

I have created a new ArrayList using subList Method.Now when I try to perform intersection operation using retainAll it Throws following exception
retainAll() Method works for Below Code
List<Integer> arrNums1 = new ArrayList<Integer>();
arrNums1.add(1);
arrNums1.add(2);
arrNums1.add(3);
List<Integer> arrNums2 = arrNums1.subList(0, 1);
arrNums2.retainAll(arrNums1);
But when i try to apply retainAll for Below code it generates Exception as Below
Java Code
public class Generics1
{
public static void main(String[] args)
{
List<Fruits> arrFruits = new ArrayList<Fruits>();
Fruits objApple = new Apple();
Fruits objOrange = new Orange();
Fruits objMango = new Mango();
arrFruits.add(objApple);
arrFruits.add(objOrange);
arrFruits.add(objMango);
List<Fruits> arrNewFruits = arrFruits.subList(0, 1);
System.out.println(arrFruits.retainAll(arrNewFruits));
}
}
class Fruits {}
class Apple extends Fruits {}
class Orange extends Fruits {}
class Mango extends Fruits {}
ERROR

When you use List#subList():
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.
You are allowed to mutate elements within it but not change the structure of the list.
The doc further says :
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
The retainAll() function uses an iterator to delete the non intersecting values , this causes ConcurrentModificationException. Note what the documenation says :
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception.
Make a copy of the List and then perform retainAll():
List<Fruits> arrNewFruits = new ArrayList<>(arrFruits.subList(0, 1));

In your two code examples you have the big list and the sub-list in reverse order.
When you invoke retainAll() on the sub-list, no modifications will occur.
This is because each element in the sub-list is in the big list.
If no modification occurs, no ConcurrentModificationException will be thrown.
You do this above with your list of Integers.
If you reverse the order and invoke retainAll() on the big list, it will get mutated.
This is because not every item in the big list is in the sub-list.
When you remove an element from the big list, a ConcurrentModificationException is thrown.
This is because you cannot mutate a list while iterating over it.
You do this above with your list of Fruits.
The iteration takes place in the retainAll() method.
In your code, the list argument happens to reference the same list that's being modified.
This is because of the way List.subList() works:
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
Long story short:
You won't get an Exception If you change your code to this:
System.out.println(arrNewFruits.retainAll(arrFruits));
More importantly:
You need to create a new list from the sub-list if there's a chance that either list will get modified while one of the lists is being iterated over.
You can create a new list from the sub-list like this:
List<Foo> freshList = new ArrayList<Foo>(bigList.subList(0,2));
Now you can iterate and mutate to your heart's content!
Here's an implementation of ArrayList.retainAll(), where you can look for the iteration.

The problem is that arrNewFruits is actually just a logical view of a part of arrFruits.1 To avoid the error, you need to make an independent list:
List<Fruits> arrNewFruits = new ArrayList<>(arrFruits.subList(0, 1));
1 That is why you can remove part of a list by calling clear() on a subList()—changes to one are seen in the other.

Related

trouble when deleting sublist from list in java

I have a function in java like
void remove(List<Var> vars, List<List<Value>> vals) {
int index = calculateIndex();
vars.removeAll(vars.subList(index, vars.size()));
vals.removeAll(vals.subList(index, vals.size()));
}
always both lists have the same number of elements before enter the method, but, after removeAll vars have one element more than vals, index is between zero and the size of the lists, why could this be happening?
If I understand correctly what you're trying to do, the code to remove the sublists should look like
int index = calculateIndex();
vars.subList(index, vars.size()).clear();
vals.subList(index, vals.size()).clear();
removeAll isn't the right tool for the job. The purpose of removeAll is to look at all the elements in collection A, and remove elements in collection B that are equal to any element in collection A. I believe it uses .equals to determine which elements are equal, not reference equality, which means that you could be removing some elements you don't intend to remove. Furthermore, since the collection A in this case would be a sublist of collection B, so that they overlap, I wouldn't count on removeAll to function correctly anyway, although it might; using overlapping lists in this situation could lead to havoc.
As an alternative design and not necessarily on track, I think it would be a nicer method if you actually constructed a new List containing the difference and returned it preserving both the original lists, otherwise its a slight code smell.
i.e.
List<Var> difference(List<Var> vars, List<List<Value>> vals) {
List<Var> results = new ArrayList<Var>();
// Loop through Vars and Vals appropriately adding Var to results based on some criteria
// ....
return results;
}
This way you preserve List vars from appearing to magically change when passed in as a input parameter to a method.

Java - does reallocating a List using subList hold a reference to previously allocated memory?

I inherited some java code which keeps a list of items to be displayed in a GUI table. The list has a size constraint so that only the most recent 100 items are displayed. When the list size reaches the limit, the code reallocates a new list, keeping the most recent 50 items via subList().
I have a concern that when this occurs, a reference may still be kept to the previously allocated list, keeping it from getting garbage collected. Can someone tell me if this is really an issue or not?
private List<myclass> theList= new LinkedList<myclass>();
public int addToList( myclass newitem) {
theList.add(0, newitem);
if (theList.size() > 100) {
theList = new LinkedList<myclass>(theList.subList(0, 50));
}
}
Returns a view of the portion of this list between the specified
fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and
toIndex are equal, the returned list is empty.) The returned list is
backed by this list, so non-structural changes in the returned list
are reflected in this list, and vice-versa. The returned list supports
all of the optional list operations supported by this list.
http://docs.oracle.com/javase/7/docs/api/java/util/List.html#subList(int,%20int)
subList() returns a view of the original list so it does remain used. However, once you get to new LinkedList<myclass>(theList.subList(0, 50));, it will make a shallow copy and you will lose the reference to the old list.
public ArrayList(Collection c)
Constructs a list containing the elements of the specified collection,
in the order they are returned by the collection's
iterator.
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection)
When you instantiate the new LinkedList instance, it will create new "nodes" to hold the contents of the subList call. It does not maintain a reference to the Collection.
This is true of all Collection implementations which have a constructor taking a Collection as an argument. The result is a shallow copy of the argument - not a maintained reference to that Collection.

ConcurrentModificationException when clearing a sub list [duplicate]

This question already has answers here:
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 3 years ago.
Why does the following code throw ConcurrentModificationExcrption, when I clear the sub List after the master List, but not if I clear the sub list and then the master List?
ArrayList<Integer> masterList = new ArrayList<Integer>();
List<Integer> subList;
// Add some values to the masterList
for (int i = 0; i < 10; i++) {
masterList.add(i * i);
}
// Extract a subList from the masterList
subList = masterList.subList(5, masterList.size() - 1);
// The below throws ConcurrentModificationException
masterList.clear();
subList.clear(); // Exception thrown in this line
// The below doesn't throw any exception
subList.clear();
masterList.clear(); // No exception thrown. Confused??
SubList is not an independent entity, but it is just giving a view of the original list, and internally refers to same list. Hence, its design seem to be such that if underlying list is modified structurally (addition/removal of elements), it is not able to fulfill its contract.
As can be seen here in the source code of SubList, the method checkForComodification checks whether the underlying list has been modified, and thus if the modCount (number of times the list has been structurally modified) value of SubList is not same as parent ArrayList, then, it throws ConcurrentModificationException
So, clearing parent ArrayList from which SubList was created can result in the certain operations of SubList to result in ConcurrentModificationException
subList is a view over the masterList. There is just 1 underlying collection. Now masterList is kind of a superset of sublist. So,
sublist cannot exist if masterlist's elements are removed //exception case
masterlist can exist if sublist's elements are removed //OK
acording to ArrayList doc subList() returns a sublist that is backed by the original ArrayList, so if the original changes so does the subList, when you execute subList.clear() the sublist itself doesn't exist anymore.
From the API docs:
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
Undefined semantics means of course that it is allowed to throw an exception (and indeed this is probably the wisest course of action).
So you can change the size of the sublist and have those changes reflected in the main list, but the reverse isn't true.

Java generic collections

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

Java List and recursion leads to Concurrent Modification Exception

The following function walks recursively through a list and divide it always by half and do something with the sublists. The recursion breaks when the listsize is 2. I know a concurrent modification exception occurs if I change the list when I iterate over it. But I don't use iterations and it still happens:
private static List<ParticipantSlot> divide(List<ParticipantSlot> list) {
int n = list.size();
//do something
if (n>2){
List<ParticipantSlot> l = divide(list.subList(0, n/2-1));
List<ParticipantSlot> r= divide(list.subList(n/2, n));
l.addAll(r);
return l;
}else{
return list;
}
}
You're using addAll() which will iterate over the collection you provide in the argument. Now subList only returns a view onto the original list, so you're trying to add values onto a view of the original list, and iterate over a different part of the original list at the same time. Bang.
If you created a copy of the sublist each time, it should work - although it'll be pretty inefficient.
You get a concurrent modification exception because sublist is backed by the original list:
The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.
If you would like to avoid an exception, make a copy of the first sublist before modifying it.
If you are using ArrayList, you may want to change it to a CopyOnWriteArrayList, or ConcurrentLinkedQueue.
If you are on a Multi-thread environment, you will want to put a synchronized around your Array.
Hope it helps.

Categories

Resources