Difference Between Iterator remove vs ArrayList remove? - java

To remove element from ArrayList, we can use-
Iterator remove() is used while iteration.
For ArrrayList remove() no iteration required.
Syntax is different in those cases. So
Do both use same logic internally?
Is there any more difference than logic?
Which one is better?
Any detailed explanation/link is highly appreciated.

An iterator might throw ConcurrentModificationException if an element is removed from the underlying collection in another way than the iterator's own remove() method.
So if you need to remove elements while iterating over a collection, you're allowed to do that with Iterator.remove() but you can't do that with Collection.remove() without risking to get an exception.

remove is a method that should be implemented (if no, it should throw UnsupportedOperationException) by all objects that are Iterable (implement interface Itarable). The way it works depends always on the object that implements it.
That means an ArrayList can implement it in a totally different way then i.e. LinkedList.
Removing object in Iterator requires You to iterate (find) the object You want to remove.
Using a remove method in ArrayList (there is no delete I can see in Javadoc: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html) finds the object for You and deletes it. It actually shifts objects in an underlying arrays to fill the "gap" You created by removing the object, so if You want to remove items in a list often, You could use LinkedList Instead.
Additionally while You are iterating through a list, You will cause an exception if You want to modify the collection in some other way than via iterator methods.
The exact answers to Your questions are:
1.No they use diferent logic, and additionally Iterator might even not allow to delete object (UnsupportedOperationException)
2.You cannot remove object by ArrayList remove while You are itereating, and to remove object at position 4 in ArrayList by using Iterator You would have to iterate 4 times "manually".
3.It depends whether You allready know what object do You want to remove, or first You check all the objects and decide whether to delete, during the iteration process. Additionally - If You want to delete objects often, You better use LinkedList, instead of ArrayList.

Related

How to get forward iterator that starts from the last element

I have a LinkedList. Suppose that I'm inserting an element at the end and I want to save the position where was it inserted, so that I can call a function on an element next to it, whatever manages to get into this collection later. Is it possible with Java iterators? Many thanks.
Just to recollect, I'm not interested in reverse iteration. The application will be multithreaded, hence the weird requirement.
You can call List#listIterator(int index) with index = size() -1 to get an iterator to the current last element of the list. See documentation: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html
However, you are going to be stuck from there.
Whether the List implementation you are using isn't thread-safe, which is the case for LinkedList, ArrayList and most others, and any attempt to use the iterator after the list has been structurally modified is going to result in a ConcurrentModificationException being thrown.
A list is structurally modified when its size changes, i.e. on additions and removals.
Or the List implementation you are using is thread-safe, in which case you have no guaranty that the iterator will have access to the elements added to the list after the creation of the iterator.
For example, it wouldn't be the case with CopyOnWriteArrayList, for which the iterator iterates through data as it was at creation (like a snapshot).
You must find an implementation of List that clearly describe this behavior and explicitly say it in its documentation. As far as I know, there doesn't exist any that allow it, at least in the standard library.

Why can't we manually iterate through a LinkedList?

LinkedList is a data structure, in which each element is coupled with a link to its next element.
So, in theory, this data structure is made for freely iterating through a list, in whichever direction, while performing whatever operations (except, maybe, deleting the element you're currently at).
However, in application, this isn't true. Returning an Iterator from a LinkedList is subject to the general Iterator rules (i.e. no modifying while iterating), and even creating a ListIterator, an improved Iterator, which allows modifying the next/previous element of the iterator, and let's you go forward/backward dynamically, still has severe limitations:
You can't delete elements from the beginning of the list if you're not currently there, and neither can you add elements to the end of the list, unless you're currently there.
So, is there a way to iterate freely through a LinkedList while performing whatever modifications to the list? And if not, why isn't there one? Shouldn't it be one of the main goals of this data structure to realize it?
The choice to make all Iterators failfast was a design decision, just that and nothing more.
Nothing stops you to take the code and starting from that, build a NotSoFailFastIterator for yourself if you think you can use it. However I think you'll quickly revert from using it once yoy see its behaviour and its results in usage scenarios where there's really lots of concurrent activity going on on the underlying List of your iterator.
This behavior is not specific to LinkedLists. When you iterate over a List (any List) with a ListIterator, you can only make structural changes (adding or removing elements) in the current position of the iterator. Otherwise, continuing to use the iterator after a structural change of the List may yield unexpected results.
For adding elements to the start or end of the LinkedList, you have addFirst and addLast methods. You don't have to iterate over the List in order to do that.
A ListIterator instance maintains a state that allows it to locate the next and previous elements as well as support other operations (remove the current element, add an element at the current position). If you make a structural change to a List not via the ListIterator, the state of the iterator may become invalid, leading to unexpected results. Therefore all structural changes must be made via the ListIterator.
I guess that the LinkedList class could supply an implementation of a more complex iterator that supports operations such as addFirst and addLast. I'm not sure how useful that would have been, and whether it would justify the added complexity.
If you want to iterate freely use array or list. Linked lists are meant to be traversed and access the data useful in dynamic allocation of the memory to the data.
When you have a linked list datastructure, you can add or remove at a particular node, when your cursor is pointing to the right node where you want to add or remove.
Inserts the specified element into the list (optional operation). The
element is inserted immediately before the element that would be
returned by next(), if any, and after the element that would be
returned by previous(), if any. The new element is inserted before
the implicit cursor: a subsequent call to next would be unaffected,
and a subsequent call to previous would return the new element. (This
call increases by one the value that would be returned by a call to
nextIndex or previousIndex.)
ListIterator
Instead if its a array structure, then you access by index , and it is possible to add or remove at a particular index limited , by the length of the array. ArrayList does that.

Why don't we put the hasNext(), next() and other methods in Collection interface?

I am confused with a design problem in Java. It realized many abstract containers under the interface Collection and provides the method hasNext() and Next() along with class Iterator. What is the drawback if I put these methods directly under interface Collection and then overrides it in each subclass:
For example, I have already realized Next(); hasNext() method under class ArrayList. So what I wrote is
ArrayList ArrList=new ArrayList()
if(ArrList.hasNext())
new obj=ArrList.next();
}
returning the objects stored in ArrList.
So is it redundant to introduce Iterator class for the interface Collection? And what is the benefit to design ArrList.iterator(); if it's more covenient to set it up in interface?
Can I find any book to solve such oop-design problems(As the computer scientists described it)?
Thanks for your time.
The methods of the Iterator interface (next(), hasNext()) can't simply be added to the interface. An Iterator has a state which determines the next element that would be returned by the iterator.
If the Iterator methods were part of the Collection interface, you would need some additional method to reset this "built-in" iterator (in order to iterate again from the start of the Collection), and you would only have a single iterator for each Collection in any given time. A nested iteration as simple as the following snippet wouldn't be possible, since it requires two iterators :
List<Integer> list = ...
for (int i : list)
for (int j : list)
System.out.println(i+j);
Iterator stores a pointer to some element inside a collection. In case of ArrayList it is an index of the underlying array.
It allows you to say iterate over the collection in two separate threads simultaneously. If the pointer was a part of ArrayList, each of the threads would skip some of the elements.
An iterator is usually made to traversed once. In the Java collection library classes will fail if modifications are made to the underlying collection during a traversal of an iterator.
BTW, this question may be more appropriate for Programmers Stack Exchange which is dedicated to theoretical programming questions.
Let's assume for a moment that ArrayList did have hasNext and next methods, and so your code would compile. (You'd also need another method to tell the list you wanted to start over again.) That would mean that I could only have one iteration of the list active at a time, because the list itself contains the iteration state. That's just poor design; instead, we have the Iterator concept so that the state of the iteration is stored in the iterator, not the list, and we can have multiple iterators.
At the conceptual level: Collection represents a collection of objects. Adding methods for hasNext and next would turn it into a collection of objects along with another piece of state, a 'current object', as well as some concept of how to traverse the collection.
Since these are two separate ideas, it is best to divide them into separate structures that are implemented independently. In the case you speak of, that would be the Collection structure (which handles storage and structure for a collection of objects), and the Iterator structure (which handles position and traversal of some collection of objects).

ConcurrentModificationException and HashSet.iterator()

I have a for loop like
for (int neighbour : neighbours) {
Where I may modify neighbours within the loop. Found that thats the cause of ConcurrentModificationException. And read from https://stackoverflow.com/a/8189527/292291
Hence if you want to modify the list (or any collection in general),
use iterator, because then it is aware of the modifications and hence
those will be handled properly.
So I tried:
neighboursItr = neighbours.iterator();
while (neighboursItr.hasNext()) {
// try disconnecting vertices
neighbour = neighboursItr.next();
But that doesnt fix the problem. Why?
Are you calling neightbours.remove(neighbour)? In that case, that is the problem. You need to call neightboursItr.remove() instead.
Have you considered creating a new HashSet with desired state? I mean you can iterate through the neighbours and add to the newNeighbours whatever you want.
You may only modify the collection using methods of the iterator while iterating on the collection. So you may call neighboursItr.remove(), but you may not add an element to the collection using neighbours.add(), for example.
You cannot modify collection while iterating. The only exception is using iterator.remove() method (if it is supported by target collection).
The reason is that this is how iterator works. It has to know how to jump to the next element of the collection. If collection is being changed after iterator creation it cannot do this and throws exception.
There are several solutions for this problem. For example if you want to add elements to existing collection during iteration you can create yet another collection where you store new elements and then add all these elements after your iteration is finished.

While iterating over a collections of Java objects--how can I mutate current object?

I will be using an iterator to loop through a collection of objects in Java. I am a little confused about using an Iterator however (used to using for each loop). let say I have code like this:
Iterator<Organization> orgIter = orgs.iterator();
while (orgIter.hasNext()) {
Organization orgObj = orgIter.next();
orgObj.setChildOrgsTree(generateOrgChildTree(orgObj, new ArrayList<Organization>()));
}
I create a new object and then change the fields inside the object. My plan was to then set the original object I formed the iteroter out equal to a List of this Object that I create (List is not shown above, but I just figured out that I would need it).
But it would be so much easier if I didn't have to create a new Object to do all of this. Is there a way I can get the current object and mutate that?
Try this:
for(Organization org : orgs)
org.setChildOrgsTree(generateOrgChildTree(org, new ArrayList<Organization>());
If your iterator iterates over a List or Queue instance, then there are fewer restrictions. As long as you do not change the structure of the list, you can do whatever you wish with the object returned by Iterator.next(). Of course, the class of that specific object should allow it to be modified, but I presume that you can add the necessary code...
On the other hand, the only list structure modification that is allowed without invalidating the Iterator object, is to remove the current element using Iterator.remove(), which, incidentally, is an optional operation. If you try to modify the list directly then the iterator will be invalidated and you will get a ConcurrentModificationException the next time you try to use it.
Additionally, if you are iterating over a Set, you are generally far more constrained: depending on the details of the actual Set implemenation, you are not generally able to modify arbitrary fields in your objects. For example, the value returned by hashCode() should not change once an object has been inserted in a HashSet...
As a sidenote, for-each loops in Java are just syntactic sugar for using an Iterator. If you are not going to use Iterator.remove(), just use a for-each loop instead of the explicity iterator and be done with it.

Categories