How to determine last element when using an iterator? - java

I love to use a for loop with the iterator principle, like
for(String s : collectionWithStrings)
System.out.println(s + ", ");
Question: How can I determine if the current element is the last one?
With an own index like int = 0; i < collection.size(); i++ this is possible with i == collection.size() - 1, but not nice. Is it also possible to determine the last element with an iterator for the example above?

Indeed, the Iterator#hasNext method returns a boolean determining if the iterator will return another element with the next method.
Your iteration can be put as this:
Iterator<String> iterator = collectionWithString.iterator();
while(iterator.hasNext()) {
String current = iterator.next();
// if you invoke iterator.hasNext() again you can know if there is a next element
}

Just use the hasNext method.
if(!iterator.hasNext()) {
// this is the last element
}
Normally, we iterate using an Iterator as so:
while(iterator.hasNext()) {
Object obj = iterator.next();
}

It's not possible with an enhanced for loop without maintaining your own counter. To be honest, this is my one deciding factor when I choose which type of for loop to use.
When using an Iterator, one has access to the hasNext() method which will return false when you are processing the last element.

Related

hasnext() in iterator is not working as expected

I have difficulty in using hasNext() iterator method. I have a JSONArray:
JSONArray = [{"a":1},{"b":2,"c":3}]
I am accessing one JSONObject at a time. First JSONObject in the JSONarray has one element second have two elements. The issue is that when the iterator check hasNext() on first JSONObject with one element it gives true, my understanding is that it should give true only if it has more elements then the present one. Please help and clarify this.
for (int i=0; i<JArrayLength; i++) {
JSONObject obj = newJArray.getJSONObject(i);
Iterator k = obj.keys();
System.out.println("Value k.hasnext is = " + k.hasNext());
if(k.hasNext())
{ //print somehting} // here its printing but as the value should be false it should not for i=0.
}
Please suggest where am I going wrong.
You open the iterator
Iterator k = obj.keys();
and then immediately check to see whether it has keys. Since you haven't consumed the first key (a), of course it does.
Note also that you're getting warnings about using the raw type Iterator. Pay attention to them and parameterize appropriately (probably with <String>).
hasNext checks the iterator if it has any values to iterate to actually get the value you should do:
if(k.hasNext()){
k.next(); // gets the actual value
}
hasNext() Returns true if the iteration has more elements.
next() Returns the next element in the iteration.

Concurrent Modification in Java

If I write
String myFirstString = "a";
String mySecondString = "b";
List<String> lstOfStrings = new ArrayList<String>();
lstOfStrings.add(myFirstString);
lstOfStrings.add(mySecondString);
for (String value : lstOfStrings) {
if(value.equals("a")) {
lstOfStrings.remove("a");
System.out.println("removed successfully");
}
}
It works fine but,
If I change the order of insertion in list , it will gives java.util.ConcurrentModificationException see below code
String myFirstString = "a";
String mySecondString = "b";
List<String> lstOfStrings = new ArrayList<String>();
lstOfStrings.add(mySecondString);
lstOfStrings.add(myFirstString);
for (String value : lstOfStrings) {
if(value.equals("a")) {
lstOfStrings.remove("a");
System.out.println("removed successfully");
}
}
gives java.util.ConcurrentModificationException
Why such behavior occur in for each? I know there are many way like Iterator, CoppyOnWriteArraylist as resolution of ConcurrentModificationException Exception. but I want to know reason of this specific case. please explain.
I am going to guess that the implementation of the byte-code generated for the iterator syntactic sugar of for (val:collection) includes an optimization of checking that you are on the last element of the collection and not bothering to enter the iterator again. So if you remove an item next to last in the collection it will not throw the exception and just skip the last item. This is somewhat proven by 2 experiments:
add 3rd item to your first example and it will fail.
Modify it to delete 2nd item instead of the 1st and will complete "successfully" again.
UPDATE: ah, this question is a duplicate of
Why isn't this code causing a ConcurrentModificationException?
A Java for-each loop internally uses iterator of the collection.
The behavior of Java iterator is fail-fast which fails when any contents of the collection has been changed while looping through it.
For more information, I recommend to read the articles below.
http://www.jguru.com/faq/view.jsp?EID=221988
http://www.developersfusion.com/Articles/AD/F/53/ConcurrentModificationException---Fail-Fast-and-Fail-Safe-iterators.aspx
http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html
It is because of the way that the ArrayList's iterator is implemented.
When you remove the element before the last one the iterator will not iterate the last one anymore.
Try printing out each iteration
String myFirstString = "a";
String mySecondString ="b";
List<String> lstOfStrings = new ArrayList<String>();
lstOfStrings.add(myFirstString);
lstOfStrings.add(mySecondString);
for (String value : lstOfStrings) {
System.out.println("Iterating: " + value);
if(value.equals("a")){
lstOfStrings.remove("a");
System.out.println("removed successfully");
}
}
System.out.println(lstOfStrings);
The output is
Iterating: a
removed successfully
[b]
As you can see in the last System.out.printlnthe lstOfStringstill contains element "b", but it is not iterated.
And when you look at the Implementation of ArrayList you can see why.
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;
}
....
}
The Iterator.hasNext() only checks if the actual cursor is not the size. So if you iterate through the list and remove string "a" the cursor points to the second element "b" but the size has been reduced to 1. So the second will not be iterated anymore.
This happens even in JDK 1.7 and I have not tested if this behavior still exists in 1.8.
When you use the Iterator.remove() method it will work, because the iterator is aware of the removal.
Iterator<String> iterator = lstOfStrings.iterator();
while (iterator.hasNext()) {
String value = iterator.next();
System.out.println("Iterating: " + value);
if (value.equals("a")) {
iterator.remove();
System.out.println("removed successfully");
}
}
Prints out:
Iterating: a
removed successfully
Iterating: b
There is no Exception in your first block of code snippet, because the loop will break out after the lstOfStrings.remove("a"), and before the interator.next() call. The iterator of the ArrayList is checking hasNext()by checking the return cursor != size, where the cursor is the current position in the iterator, that means after you remove the element: a from the list, the cursor increased: cursor++(cursor==1), but the size is decreased(you removed an element, size == 1). It does not throw Exception but it doesn't mean it is correct.
Think the following code:
for (String value : lstOfStrings) {
System.out.println("Iterating: " + value);
if(value.equals("a")){
lstOfStrings.remove("a");
System.out.println("removed successfully");
} else if (value.equals("b")) {
doSomethingOnB(value) // this won't be executed anyway!!!
}
}
And if you add one more elements into the lstOfStrings in the first code snippet, like: lstOfStrings.add("c"), it will throw the Exception you desire. :-)
The ConcurrentModificationException is thrown in your second block of code snippet, because it passed the hasNext() checking(cursor == 2, size == 1), then goes into the interator.next() call, which will check the modCount in the ArrayList and the expectedModCount in the Iterator, which represents count of modifications on the List elements size. Obviously, modeCount == 3 (2 adds and 1 remove), but the ArrayList.remove(Object) methods does not affect the expectedModCount in the ArrayList.Iterator, thus expectedModCount == 2, that is why it throws the Exception.
I am not sure whether it should be considered a bug in ArrayList, the root reason in your cases are the ArrayList's elements modification count is not synchronized with the Iterator's.
Some excerpts from ArrayList API -
With every addition and removal on list modCount is incremented.
For each loop's iterator call next() method for list size + 1 times in this case 3 times.
When lstOfStrings.remove("a"); is called modCount is set to 3.
At every next() iteration of iterator checkForComodification(); is called to check if there is any modification, since modification is found we get ConcurrentModificationException.
Why doesn't Iterator throw Exception then ?
Had there been call for checkForComodification(); after this ArrayList.this.remove(lastRet); It would have thrown same exception.

iterator returning random letters can't get it to iterate

I have this iterator,
Set<BigFraction> key = knowledgeD.keySet();
TreeSet<BigFraction> sortKey = new TreeSet<BigFraction>();
sortKey.addAll(key);
Iterator<BigFraction> iter = sortKey.iterator();
return iter;
BigFraction is just the data type if it makes it any easier just sub this with int or something.
Anyway when i called the iterator later on to
while (iterator().hasNext());
It basically just gives me an infinite loop of somesort... and when i printout iterator() before this while loop i get
java.util.TreeMap$KeyIterator#53b4b24d
Any idea's kind of stuck,
Regards,
Sim
You need to use your Iterator like this:-
while (iter.hasNext()) {
System.out.println(iter.next()); //Do whatever you want
}
where hasNext() tells if the iterator has more values or not, and next() returns the next value in the iterator.
Also, the explanation of why your current iterator loop is not working(going into an infinite loop), has been explained by #jacobm.
iterator().hasNext() never advances the iterator, it just checks to see if it has an element. So while (iterator().hasNext()); will always infinite-loop if there are any values to iterate over. You can fix it with:
Iterator<BigFraction> it = iterator();
while (it.hasNext()) {
it.next();
}
The call to iterator() constructs a new iterator, so your code will construct a new iterator each time through the loop. Instead try something like:
Iterator it = iter;
while (it.hasNext()) {
it.next()
}
Be sure to call next() each time through the loop, otherwise you won't increment the iterator, and it will just stay on the first item.
Iterator#hasNext returns true if the iteration has more elements, it does not return the next element in the iteration. which Iterator#next does.
If you use itarator if you must call iterator#next to get the next element of collection, but hasNext is operation is optional.
you could either write -
while (iter.hasNext()) {
Object oj = iter.next();
}
or
Object obj = null;
while ( (obj = iter.next())!=null) {
....
}
with this approach hashNext is not at all required.

Remove all occurrencies of the first element in ArrayList

I want to remove all elements in ArrayList that are duplicates of the first element, but I want the firs element to remain in the ArrayList. I tried to do that with for loop, but it didn't remove all duplicates.
for(int i = 1; i < arraylist.size(); i++) {
if(arraylist.get(i) == v1)
arraylist.remove(i);
}
v1 is equal to the first element of the arraylist.
I also tried with ListIterator, but it removed the first element
ListIterator<Integer> iterator = arraylist.listIterator();
while(iterator.hasNext()) {
if(iterator.next().intValue() == v1)
iterator.remove();
}
Can you please help me?
You need to read the first element separately, outside the while loop, and store it in some variable, with which you would compare the rest of the elements, to remove:
ListIterator<Integer> iterator = arraylist.listIterator();
int first = 0;
// Check if there is a first element
if (iterator.hasNext()) {
first = iterator.next();
// Iterate over the rest of the elements
while(iterator.hasNext()) {
// If this value is equal to `first`, remove it
if(iterator.next().intValue() == first) {
iterator.remove();
}
}
}
System.out.println(arrayList);
iterator.next() will return a value of type Integer. Using intValue() will give your primitive value out.
But since I'm doing the comparison with an int primitive itself, you won't need to call intValue() at all. Your Integer will automatically be unboxed to primitive int before comparison. So, replacing the if statement in while with the below one will also work:
if(iterator.next() == first) {
iterator.remove();
}
As far as your first way is concerned, I would say, always use Iterator if you want to modify the List you are looping upon. This will prevent you from facing awkward ConcurrentModificationException.
See also:
Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop
You are doing the correct way by using Iterator and its method remove. But you should add a call to next() before the loop itself, in order to go over the first element and not remove it.
ListIterator<Integer> iterator = arraylist.listIterator();
iterator.next(); // pass the first element.
while(iterator.hasNext()) {
if(iterator.next().intValue() == v1)
iterator.remove();
}
Contrary to what others have said, you don't have to use "equals" if v1 is an int, which seems to be the case.
Count down (not up):
Object v1 = arraylist.get(0);
for (int i = arraylist.size() - 1; i > 1; i--) {
if (arraylist.get(i).equals(v1))
arraylist.remove(i);
}
You have to count down because as you remove elements, they the remaining ones shuffled down.
Also, you should change == to .equals() (as shown).
int v1 = arraylist.get(0);
for(int i = 0; i < arraylist.size(); i++) {
if(arraylist.get(i) == v1){
arraylist.remove(i);
i--;
}
}
If you don't want to use the Iterator approach: The other answers are correct in that you need to index from zero (if you want to remove the first one as well), but you also need to decrement your iteration variable (the i-- line) each time you remove an element from the list, because you're changing the list's length with remove().
It's best to be careful about removing elements from an array (or an iterable list) whilst iterating over it.
Easiest approach, in my experience, is to create a new list. Can you consider doing that?
Looking at your code, firstly remember to use "equals" over "==" for comparison (since .equals means "meaningfully equivalent", which I think is what you need here). (edit: may not matter here due to autoboxing, but it's still a nice habit to have)
But even this won't work:
for (int i = 1; i < arraylist.size(); i++) {
if (arraylist.get(i).equals(v1))
arraylist.remove(i);
}
Since imagine you have an ArrayList of three integers, all the same. When i == 1, The element at index 1 is compared to the value at index 0, and removed. But then the element at index 2 becomes the element at index 1, the for-loop counter is incremented, thereby "missing" to remove the last entry in the list.
Can I recommend something like this?
List<Integer> newlist = new ArrayList<Integer>();
newlist.add(v1);
for (Integer integer : arraylist) {
if (!integer.equals(v1))
newlist.add(integer);
}
Best of luck!
P.S. if you're feeling brave, you might be able to do a neat one-liner out of this:
CollectionUtils.filter(Collection,Predicate)
CollectionUtils.filter(arraylist.subList(1, arraylist.size()), new Predicate() {
#Override
public boolean evaluate(Object o) {
return !v1.equals(o);
}
});

The correct way to return the only element from a set

I have the following kind of situation:
Set<Element> set = getSetFromSomewhere();
if (set.size() == 1) {
// return the only element
} else {
throw new Exception("Something is not right..");
}
Assuming I cannot change the return type of getSetFromSomewhere(), is there a better or more correct way to return the only element in the set than
Iterating over the set and returning immediately
Creating a list from the set and calling .get(0)
You can use an Iterator to both obtain the only element as well as verify that the collection only contains one element (thereby avoiding the size() call and the unnecessary list creation):
Iterator<Element> iterator = set.iterator();
if (!iterator.hasNext()) {
throw new RuntimeException("Collection is empty");
}
Element element = iterator.next();
if (iterator.hasNext()) {
throw new RuntimeException("Collection contains more than one item");
}
return element;
You would typically wrap this up in its own method:
public static <E> E getOnlyElement(Iterable<E> iterable) {
Iterator<E> iterator = iterable.iterator();
// The code I mentioned above...
}
Note that this implementation is already part of Google's Guava libraries (which I highly recommend, even if you don't use it for this particular code). More specifically, the method belongs to the Iterables class:
Element element = Iterables.getOnlyElement(set);
If you're curious about how it is implemented, you can look at the Iterators class source code (the methods in Iterables often call methods in Iterators):
/**
* Returns the single element contained in {#code iterator}.
*
* #throws NoSuchElementException if the iterator is empty
* #throws IllegalArgumentException if the iterator contains multiple
* elements. The state of the iterator is unspecified.
*/
public static <T> T getOnlyElement(Iterator<T> iterator) {
T first = iterator.next();
if (!iterator.hasNext()) {
return first;
}
StringBuilder sb = new StringBuilder();
sb.append("expected one element but was: <" + first);
for (int i = 0; i < 4 && iterator.hasNext(); i++) {
sb.append(", " + iterator.next());
}
if (iterator.hasNext()) {
sb.append(", ...");
}
sb.append('>');
throw new IllegalArgumentException(sb.toString());
}
The best general solution (where you don't know the actual set class) is:
Element first = set.iterator().next();
If the set class is known to be a SortedSet (e.g. a TreeSet or ConcurrentSkipListSet), then a better solution is:
Element first = ((SortedSet) set).first();
In both cases, an exception will be thrown if the set is empty; check the javadocs. The exception can be avoided using Collection.isEmpty().
The first solution is O(1) in time and space for a HashSet or LinkedHashSet, but typically worse for other kinds of set.
The second one is O(logN) in time , and uses no space for TreeSet or ConcurrentSkipListSet.
The approach of creating a list from the set contents and then calling List.get(0) gives a poor solution since the first step is an O(N) operation, both in time and space.
I failed to notice that N is actually 1. But even so, creating an iterator is likely to be less expensive than creating a temporary list.
You could grab the iterator:
Element firstEl = set.iterator().next();
In Java 8, we can do like below:
set.stream().findFirst().get()
But, remember to check the size of set before as Optional.get() throws NoSuchElementException

Categories