I am trying to use remove method but I am getting messed up as I keep getting error for this:
List<String> list1 = new ArrayList<String>();
list1.add("Apple");
list1.add("Bus");
list1.add("Cat");
list1.add("Dog");
String ne = list1.listIterator().next();
System.out.println(ne);
list1.listIterator().remove();
the remove statement throws an error?? can anyone tell me why??
same thing when I just use iterator in place of listIterator?
Your code is correct in that you are allowed to call ListIterator#remove() once for each time next() is called (see Javadoc). However, in your code you are actually calling remove() on a new list iterator, not the one you used before it. Try the following code and hopefully it will be clear what you did wrong:
List<String> list1 = new ArrayList<String>();
list1.add("Apple");
list1.add("Bus");
list1.add("Cat");
list1.add("Dog");
// retain a reference to the same list iterator
ListIterator<String> list1itr = list1.listIterator();
String ne = list1itr.next();
System.out.println(ne);
list1itr.remove();
Demo
Related
I have a code that adds data to a list. What I do not understand is why
the UnsupportedOperationException is thrown in one case and
ConcurrentModificationException in the other.
I am adding data in list in both the case and then trying to remove list
data while iterating over the list.
What i have read so far is that whenever any modification is made to
fail- fast collection,ConcurrentModificationException is thrown. So why this
different behavior in both these cases?
List<String> animalList = new ArrayList<>();
animalList.add("cat");
animalList.add("dog");
animalList.add("bear");
animalList.add("lion");
Iterator<String> iter = animalList.iterator();
while(iter.hasNext()){
String animal = iter.next();
System.out.println(animal);
animalList.remove(3);
}
This code throws ConcurrentModificationException
String[] strings = { "Java", "Honk", "Test" };
List<String> list = Arrays.asList(strings);
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String name = iterator.next();
System.out.println(name);
list.remove(3);
}
while this one throws UnsupportedOperationException
For the code block, where you get ConcurrentModificationException , you get that exception because you created an iterator on List then removing directly from list from within loop so iterator has issues. You should use remove() method of iterator itself - Iterator.remove().
You should directly remove an element from list when removing from outside iterator loop. See this another SO Question
In second case, with Arrays.asList , you get a List but actual list object might not be an ArrayList and remove(int index) operation is optional at List interface. See this
All in all, as far as UnsupportedOperationException is concerned, in first case you are guaranteed to working with an ArrayList and for that class, remove operation is supported , See this
For second case, you can't be so sure. Refer documentation of Arrays.asList where it says that returned list of fixed size so certain operations are not supported.
Arrays.asList does not return an ArrayList. In fact, the list returned is not modifiable, thus when you try to modify it, it throws the UnsupportedOperationException.
This link says that I can remove a string by directly addressing it with the parameter, like:
myList.remove("myString");
but trying to do this I get the java.lang.UnsupportedOperationException exception.
UPDATE
The code I use to create and fill the list:
List<String> myList = new ArrayList<>(myArray.length);
for (String str : myArray) {
myList.add(str);
}
The code I get the exception while executing:
if (myList.contains("specificString"))
myList.remove("specificString");
}
How can I remove this element then without using the for loop or an index?
Assuming yours a ArrayList, ideally you could remove the object from a list using the list.remove(obj) as you did unless the list is unmodifiable as shown below:
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
System.out.println(list); // [a,b,c]
list.remove("a");
System.out.println(list); // [b,c]
List<String> unmodifiable = Collections.unmodifiableList(list);
unmodifiable.remove("b"); // UnsupportedOperationException
The List interface (java.util.List) includes a method remove(object). Not all implementations support that method though. For implementations that don't implement this method you get this exception. It is even documented here:
https://docs.oracle.com/javase/7/docs/api/java/util/List.html#remove(java.lang.Object)
If you use ArrayList then you should be fine. If you use some custom fixed size implementation or some other implementation that doesn't suppor that operation then you cannot use this method.
I'm currently having problems with the following, using Java 8:
I want to pass an ArrayList<String> as argument to another method. This method, among other things, removes an object from the ArrayList it was given:
public static void calledMethod(String item, ArrayList<String> list) {
list.remove(item);
}
Now I tried calling this method like this from main:
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next(); //<-
calledMethod(item, list);
}
In this case, the JVM returns a java.util.ConcurrentModificationException at the marked line in the code above (//<-). As far as my knowledge goes, this means that the list was modified while it was iterated. But how can this happen? As far as I know, Java hands method arguments by value, not by reference. If I call calledMethod using the following code in my main method, no error occurs:
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next(); //<-
calledMethod(item, (ArrayList<String>) list.clone());
}
So passing a cloned object to calledMethod works. What is wrong here?
java -version: Java SE Runtime Environment (build 1.8.0_20-b26)
I'm using Oracle Java on a Linux Mint 64bit.
Yes, Java is pass by value. But what is list? It's a reference to the actual ArrayList object. When it's passed to the method, it's copied, but the copy still refers to the same object, so the method's modification is visible to the calling method, and a ConcurrentModificationException occurs.
When you clone the object, only then is a copy of the object made, preventing the ConcurrentModificationException.
What happens here is that your iterator got "lost" due to "concurrent" modification on the list (it's not actually concurrent, but it's a modification made on the list without notifying the iterator. So from Iterator point of view, it's as if the list was modified at the same time)
While iterating through a list, you should never remove an element with List.remove. Use Iterator.remove instead, this way the iterator won't have an invalid state due to removing:
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next();
itr.remove(); // will remove "item" and keep iterator in a correct state
}
Yes you pass it by value, but you are passing an object which is actually passing the reference of the object in that case. Thus you are still modifying the actualy list in the calledMethod.
i have a small problem in java. I am trying to loop through an ArrayList and add more items to the same arraylist during the looping and am getting concurrentModificationexception. what are the work-around for this problem, my code is like this
ArrayList "Errors" is already populated.
ArrayList<MainErrorObject> errors;
ArrayList<MainErrorObject> newList;
for (MainErrorObject current : errors)
{
newList = processErrorObjects(current);
errors.addall(newList);
}
When i try to execute the code above, i get the concurrentmodification exception. please help me in resolving this.
Thanks in advance.
you can't iterate & modify the same collection. So have a temporary ArrayList and copy the content to main list when iteration is done.
ArrayList<MainErrorObject> tempErrors;
for (meObject : Errors) {
newList = processErrorObjects();
tempErrors.addAll(newList);
}
errors.addAll(tempErrors);
Ps: follow the java naming conventions
You can use the Iterator class and use the add() method from Iterator, like this:
ListIterator<MainErrorObject> it = Errors.listIterator();
MainErrorObject me = null;
while(it.hasNext()) {
me = it.next();
if (//condition)
it.add(item);
}
which will never throw such an exception because it's smart enough to handle said concurrent modifications.
Source: ListIterator javadocs
Use ListIterator.
To avoid java.util.ConcurrentModificationException exception, we can add an item through the iterator of list
for (ListIterator<MainErrorObject> itr = Errors.listIterator(); itr.hasNext();) {
newList = processErrorObjects(itr.next());
for (MainErrorObject obj : newList) {
itr.add(obj);
}
}
having a problem trying to get an arraylist containing arraylists to work in my program, Im getting a strange warning saying: add #SuppressWarnings "null" to processArray(), regardless of If I add this or not my program crashes, Is there anything obvious that Im doing wrong here? any help would go a long way thanks.
private ArrayList<ArrayList<String>> processArray(ResponseList<Status> responses){
ArrayList<ArrayList<String>> mainArray = null;
ArrayList<String> innerArrays = null;
for (Status response: responses ){
String name, status, imgUrl, time;
name = response.getUser().getName();
status = response.getText();
imgUrl = response.getUser().getProfileImageURL().toString();
time = response.getCreatedAt().toString();
ArrayList<String> rtLinks = checkLinks(response.getText());
if(rtLinks != null){
for (String tLink: rtLinks){
innerArrays.add(name);
innerArrays.add(status);
innerArrays.add(imgUrl);
innerArrays.add(time);
innerArrays.add(tLink);
mainArray.add(innerArrays);
}
}
}
return mainArray;
You never actually initialize either of those arraylists.
You want
ArrayList<ArrayList<String>> mainArray = new ArrayList<ArrayList<String>>(); // or new ArrayList<>() in java 7
and inside the inner for loop:
ArrayList<String> innerArrays = new ArrayList<String>(); // or new ArrayList<>() in java 7
Also, don't ever suppress warnings "just to make code work". Only suppress them when you know exactly why they appear and exactly why you're choosing to ignore them.
Your program is probably crashing due to a NullPointerException. This occurs when you try to access a variable whose value is null (known as dereferencing a null pointer). Before you access either of the two ArrayLists, you'll need to initialize it. Try changing the two lines to this:
ArrayList<ArrayList<String>> mainArray = new ArrayList<ArrayList<String>>();
ArrayList<String> innerArrays = new ArrayList<String>();
This should solve your immediate problem.
However, I'm not sure why you're using an innerArrays list at all. I would refactor the last bit to this:
for (String tLink: rtLinks){
ArrayList<String> tempList = new ArrayList<String>();
tempList.add(name);
tempList.add(status);
tempList.add(imgUrl);
tempList.add(time);
tempList.add(tLink);
mainArray.add(tempList);
}
and remove the innerArrays variable. This way, the scope is more limited, and the code operates more logically.
You are trying to add the innerArrays variable into your main ArrayList, but you have declared your main ArrayList null in the beginning of the method. Initialize the main ArrayList as a new ArrayList of ArrayLists of Strings, and your code should work.