How for-each loop knows where to start? - java

Iterator is guaranteed to have the following methods:
hasNext()
next()
remove (optional)
When for-each loop iterates through iterable class objects, how does it know what object to start with? The above methods provide clear path forward, but what points to the starting element?
For-each guarantees to iterate through all relevant objects. Depending on a class and its next() implementation it could be vitally important where to start (consider forward linked list or any other implementation that has a root element).
How does it work?
If my question does not make sense please explain why.

From the spec:
What's officially called the enhanced for statement (for(E e: Iterable<E> iterable)) is translated by the compiler into the equivalent of the following code:
E e;
for(Iterator<E> it = iterable.iterator(); it.hasNext(); ) {
e = it.next();
// contents of your for loop
}
The behavior of the loop is exactly as if you'd written it with an explicit Iterator, so the "starting point" of the enhanced for loop is wherever iterable.iterator() would have started anyway.

You might want to look at ArrayList's implementation of an Iterator, the Itr inner class.
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
#SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
...
}
cursor gets initialized to 0 by default. You use cursor to access the elements in the ArrayList object's backing array (it's an inner class, it has access to that field).
Similar logic applies for other implementations of Iterator. It always depends on the underlying data structure. As another example, a Set is not supposed to have an ordering, but it does implement Iterator. A decision has to be made as to where the iterator starts.

foreach is a shorthand for for loop starting from first till last.

This all depends on your collection.
If your collection is a List (ArrayList or LinkedList usually), then the iterator will go in list order according to how they were inserted.
If it is a Map or Set, it is very hard to predict the ordering of its members. If you are using a Map or Set, you should not count on any sort of predictable ordering, in fact, because it doesn't match those collections' purposes. However, LinkedHashMap or LinkedHashSet can be used if you need a specific order but also need the functionality of a Map or Set.

Related

Removing element from list in counted loop vs iterator [duplicate]

This question already has answers here:
Why iterator.remove does not throw ConcurrentModificationException
(6 answers)
Closed 7 years ago.
Why is this legal:
for(int i=0; i < arr.size(); i++) {
arr.remove(i);
}
But using an iterator or the syntactic sugar of a for each results in a ConcurrentModificationException:
for(String myString : arr) {
arr.remove(myString);
}
Before everyone starts jumping on the bandwagon telling me to use iterator.remove(); I'm asking why the different behavior, not how to avoid the conc mod exception. Thanks.
Let's take a look at how, e.g., ArrayLists's iterator is implemented:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
public E next() {
checkForComodification();
int i = cursor;
if (i >= size) throw new NoSuchElementException();
// ...
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
// ...
ArrayList.this.remove(lastRet);
// ...
cursor = lastRet;
lastRet = -1;
}
Let's look at an example:
List list = new ArrayList(Arrays.asList(1, 2, 3, 4));
Iterator it = list.iterator();
Integer item = it.next();
We remove the first element
list.remove(0);
If we want to call it.remove() now, the iterator would remove number 2 because that's what field lastRet points to now.
if (item == 1) {
it.remove(); // list contains 3, 4
}
This would be incorrect behavior! The contract of the iterator states that remove() deletes the last element returned by next() but it couldn't hold its contract in the presence of concurrent modifications. Therefore it chooses to be on the safe side and throw an exception.
The situation may be even more complex for other collections. If you modify a HashMap, it may grow or shrink as needed. At that time, elements would fall to different buckets and an iterator keeping pointer to a bucket before rehashing would be completely lost.
Notice that iterator.remove() doesn't throw an exception by itself because it is able to update both the internal state of itself and the collection. Calling remove() on two iterators of the same instance collection would throw, however, because it would leave one of the iterators in an inconsistent state.
Looking at your code, I am assuming arr is a List. In the top loop you operate on the list directly, and "re-calibrate" your condition at the top when you check
i < arr.size()
So if you remove an element, i has to compare to a lesser value.
On the other hand, in the second case you operate on the collection after an iterator has been instantiated, and don't really re-calibrate yourself.
Hope this helps.
In the first one you are modifying an array that it's not being used as an iterator on your for loop.
In the second one you are trying to access to an array that it's being modified at the same time you are iterating with it on the loop. It's why it throws ConcurrentModificationException.

Modifying each item of a List in java

I'm just starting to work with lists in java. I'm wondering what the recommended method to modify each element of a list would be?
I've been able to get it done with both the following methods, but they both seem fairly unelegant. Is there any better way to get this done in java? And is any of the below methods recommended over the other, or are both on the same level?
//Modifying with foreach
for (String each : list)
{
list.set(list.indexOf(each), each+ " blah");
}
//Modifying with for
for (ListIterator<String> i = list.listIterator(); i.hasNext(); i.next())
{
i.next();
list.set(i.nextIndex()-1, i.previous() + " blah yadda");
}
The second version would be better. Internally they are the same in the end, but the second actually allows you to modify the list, while the first one will throw a ConcurrentModificationException.
But then you are using the Iterator in a wrong way. Here is how you do it correctly:
for (final ListIterator<String> i = list.listIterator(); i.hasNext();) {
final String element = i.next();
i.set(element + "yaddayadda");
}
The iterator is the one that needs to modify the list as it is the only one that knows how to do that properly without getting confused about the list elements and order.
Edit: Because I see this in all comments and the other answers:
Why you should not use list.get, list.set and list.size in a loop
There are many collections in the Java collections framework, each on optimized for specific needs. Many people use the ArrayList, which internally uses an array. This is fine as long as the amount of elements does not change much over time and has the special benefit that get, set and size are constant time operations on this specific type of list.
There are however other list types, where this is not true. For example if you have a list that constantly grows and/or shrinks, it is much better to use a LinkedList, because in contrast to the ArrayList add(element) is a constant time operation, but add(index, element), get(index) and remove(index) are not!
To get the position of the specific index, the list needs to be traversed from the first/last till the specific element is found. So if you do that in a loop, this is equal to the following pseudo-code:
for (int index = 0; index < list.size(); ++index) {
Element e = get( (for(int i = 0; i < size; ++i) { if (i == index) return element; else element = nextElement(); }) );
}
The Iterator is an abstract way to traverse a list and therefore it can ensure that the traversal is done in an optimal way for each list. Test show that there is little time difference between using an iterator and get(i) for an ArrayList, but a huge time difference (in favor for the iterator) on a LinkedList.
EDIT: If you know that size(), get(index) and set(index, value) are all constant time operations for the operations you're using (e.g. for ArrayList), I would personally just skip the iterators in this case:
for (int i = 0; i < list.size(); i++) {
list.set(i, list.get(i) + " blah");
}
Your first approach is inefficient and potentially incorrect (as indexOf may return the wrong value - it will return the first match). Your second approach is very confusing - the fact that you call next() twice and previous once makes it hard to understand in my view.
Any approach using List.set(index, value) will be inefficient for a list which doesn't have constant time indexed write access, of course. As TwoThe noted, using ListIterator.set(value) is much better. TwoThe's approach of using a ListIterator is a better general purpose approach.
That said, another alternative in many cases would be to change your design to project one list to another instead - either as a view or materially. When you're not changing the list, you don't need to worry about it.
Internally there in Iterator for for-each implementation. So there is no deference between these two cases. But if you trying to modify element it will throws ConcurrentModificationException.
I got mine working this way
String desiredInvoice="abc-123";
long desiredAmount=1500;
for (ListIterator<MyPurchase> it = input.getMyPurchaseList().listIterator(); it.hasNext();) {
MyPurchase item = it.next();
if (item.getInvoiceNo().equalsIgnoreCase(desiredInvoice)) {
item.setPaymentAmount(desiredAmount);
it.set(item);
break;
}
}

Reverse Ordered list using Previous Iterator

I want to start at the end of the list and iterate it using ListIterators previous method
public void add(E obj) {
ListIterator <E> iter = theList.listIterator();
while (iter.hasNext()) {
if (obj.compareTo(iter.next()) < 0) {
iter.previous();
iter.add(obj);
return;
}
}
iter.add(obj);
}
Every time I run my test class it iterators from the beginning.
to get iterator in reverse order use method list.listIterator(int index)
this method will return iterator from specified position,
you should put size of list means last element index.
after that you can use hasPrevious() and previous() method.
this will work,
// declare arraylist
ArrayList<...> a = new ArrayList<...>();
// Add elements to list.
// Generate an iterator. Start just after the last element.
ListIterator li = a.listIterator(a.size());
// Iterate in reverse.
while(li.hasPrevious()) {
System.out.println(li.previous());
}
ListIterator, like all Iterators, always start at the beginning. The previous method allows for less constrained movement, but it still starts at the beginning. You overall intent is unclear, so it's possible you're coming at this the wrong way, but the most straightforward way for you would be to reorder the list first and then do your iteration.
UPDATE Nevermind, Rajj has it.

Iterator has .next() - is there a way to get the previous element instead of the next one?

I have an Iterator that I use on a HashMap, and I save and load the iterator.
is there a way to get the previous key in the HashMap with Iterator? (java.util.Iterator)
Update
I save it as an attribute in a Red5 connection and then load it back to continue working where i stopped.
Another update
I'm iterating through the keyset of the HashMap
You can use ListIterator instead of Iterator.
ListIterator has previous() and hasPrevious() methods.
Not directly, as others pointed out, but if you e.g. need to access one previous element you could easily save that in a separate variable.
T previous = null;
for (Iterator<T> i = map.keySet().iterator(); i.hasNext();) {
T element = i.next();
// Do something with "element" and "previous" (if not null)
previous = element;
}
It sounds like you want the array semantics more akin to a ListIterator rather than those provided by the Iterator interface. The easiest way to acquire such a thing is likely to construct a list ( from the key-set (LinkedList<K> keyList = new LinkedList<K>(map.keySet())), then use a ListIterator manually instead of a regular Iterator or foreach.
For very simple cases of needing to remember consecutive items, the simplest way to handle this is to store the previous Key in a local variable and update it at the end of the loop.
No, an Iterator<E> defines only 3 methods:
boolean hasNext()
E next()
void remove()
You can of course implement your own iterator.
As others have said, you only access an element using next(). However it's sort of a matter of terminology. Once you call next() this is the current element.
Unless the problem is you need to see two consecutive items in the collection each iteration, in which case a simple variable would seem easiest.
Although Set doesn't provide a method for a reverse iterator, Deque does. You can use descendingIterator() for an iterator in reverse order and iterator(), for an iterator in forwards order.
(You can create a Deque from a Set via Deque<T> deque = new LinkedList<T>(set), where set is your Set and T the generic type you're using.)
Ultimately Iterators are not fully suited for your task.
Why not create a List from your Set (via, eg, List list = new LinkedList(set)) and iterate by using a standard indexed for-loop? That way you know the previous element is at i - 1.
using iterator, No you dont have an option to get a previous key value. it has only hasNext() and next() methods.
No, you can't. The Iterator interface has no method to get the previous element.
But what you can do is - a little bit rubbish- creating a List<Entry<Integer, YourObjectType>> where the Integer-value represents the hash-code of the key-object. Then you can do something like this:
for (int i = 0; i < list.size(); i++)
{
YourObjectType current = list.get(i).getValue();
YourObjectType previous = (i == 0 ? null : list.get(i - 1).getValue());
// Do whatever you want
}
I know this is very rubbish, but it is possible
Make your own Iterator:
public class EnhancedIterator<E> implements Iterator<E>{
private List<E> list;
private int indexSelected=-1;
public EnhancedIterator(List<E> list){
this.list=list;
}
#Override
public boolean hasNext() {
return indexSelected<list.size()-1;
}
#Override
public E next() {
indexSelected++;
return current();
}
#Override
public void remove() {
list.remove(indexSelected);
}
public void remove(int i){
list.remove(i);
if(i<indexSelected){
indexSelected--;
}
}
public E previous(){
indexSelected--;
return current();
}
public E current(){
return list.get(indexSelected);
}
public E get(int i){
return list.get(i);
}
}

Java: Why does calling `remove()` on a List throw UnsupportedOperation exception?

For some reason, I'm getting an UnsupportedOpeationException with the following code. Examining it in the debugger, it looks like the object I'm calling remove() on is a list.
// to optimize, remove totalSize. After taking an item from lowest, if lowest is empty, remove it from `lists`
// lists are sorted to begin with
public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) {
List<T> result = new ArrayList<T>();
HashMap<List<T>, Integer> location = new HashMap<List<T>, Integer>();
int totalSize = 0; // every element in the set
for (List<T> l : lists) {
location.put(l, 0);
totalSize += l.size();
}
boolean first;
List<T> lowest = lists.iterator().next(); // the list with the lowest item to add
int index;
while (result.size() < totalSize) { // while we still have something to add
first = true;
for (List<T> l : lists) {
if (! l.isEmpty()) {
if (first) {
lowest = l;
}
else if (l.get(location.get(l)).compareTo(lowest.get(location.get(lowest))) <= 0) {
lowest = l;
}
}
}
index = location.get(lowest);
result.add(lowest.get(index));
lowest.remove(index); //problem here
}
return result;
}
The exception:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(Unknown Source)
at interview.questions.MergeLists.merge(MergeLists.java:72)
at interview.questions.MergeLists.main(MergeLists.java:32)
Why is this happening?
It's quite possible the underlying implementation of List you received is fixed-length, such as one created by Arrays#asList.
If you look at the API docs for the List interface you will see that a number of them are "optional operations". That means that a concrete class is permitted to throw the UnsupportedOperationException.
If, for example, the List was converted to an unmodifiable list it could not allow the remove operation to actually remove something (or the list would be modified).
So for the Set< List<>> part of the code one or mnre of the lists does not allow you to remove from it.
If you are going to be removing items from a List, then rather than use a for-each loop to iterate through the list, you should be using a ListIterator, which supports remove() in a safe manner (i.e. without leaving holes in the list or an index pointing to nowhere).
It is optional for a class implementing the Collection interface to allow objects to be removed (see Collection#remove() which is an optional operation). As stated in the javadoc, it throws
UnsupportedOperationException - if the remove operation is not supported by this collection
You are likely in that case (e.g. if your set contains a list returned by Arrays.asList as pointed out by Jeffrey).
Could it be that the Lists you pass in the set are derived from AbstractList and do not implement (support) the remove() method?
Also, it seems that location always maps to 0 for all list object that are mapped in the location HashMap?
The remove() method in the Collection interface is explicitly specified as an optional operation:
remove(Object o)
Removes a single instance of the specified element from this collection, if it is present (optional operation).
Lists do not have to support in. In fact, there is no clear semantics for it. Lists are not meant for that sort of random-access. Rather than provide some default implementation that may be inefficient or inaccurate, you get the exception.
You can write your own utility method with a for-each loop to do this if it is critical.

Categories