Java iterator.hasNext() is always true - java

I have a little problem with the code as seen below. The iterator().hasNext() will never turn into false because the next() function always returns the same element. It ends in an infinite loop.
I would like to set the attribute UserLock in every element in the collection (returned from GetElements()).
If the type of the element is "Package", I will lock all elements under the package with a recursive call of the lockAllElements function.
private void lockAllElements(String internalGUID) {
Element tempElem = null;
while((repo.GetPackageByGuid(internalGUID).GetElements().iterator().hasNext()) == true) {
tempElem = repo.GetPackageByGuid(internalGUID).GetElements().iterator().next();
if(tempElem.GetType().equals("Package")) {
this.lockAllElements(tempElem.GetElementGUID());
}
tempElem.ApplyUserLock();
}
}

It is always true because you get a new Iterator instance in each iteration of your loop. You should get a single Iterator instance and use that instance throughout the loop.
Change
while((repo.GetPackageByGuid(internalGUID).GetElements().iterator().hasNext()) == true) {
tempElem = repo.GetPackageByGuid(internalGUID).GetElements().iterator().next();
...
to
Iterator<Element> iter = repo.GetPackageByGuid(internalGUID).GetElements().iterator();
while(iter.hasNext()) {
tempElem = iter.next();
...

Following on from #Eran's answer... I sometimes prefer a for loop:
for (Iterator<Element> iter = repo.GetPackageByGuid(internalGUID).GetElements().iterator(); iter.hasNext(); ) {
tempElem = iter.next();
}

Related

Java iterate over map twice before deciding whether to remove an object

I have a map of Object string.
I need to iterate over it twice before deciding whether to remove it or not.
protected void removeDayOutOfRangeObjects(Map<Object, String> objects, Calendar[] clientTimeRange) {
String currentPartOfWeek = null;
for(Calendar range: clientTimeRange){
int dayOfWeek = range.get(Calendar.DAY_OF_WEEK);
if(1 == dayOfWeek || 7 == dayOfWeek) {
currentPartOfWeek = "weekends";
} else {
currentPartOfWeek = "weekdays";
}
Iterator<Map.Entry<Object,String>> iter = objects.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Object,String> entry = iter.next();
if(currentPartOfWeek.matches(entry.getValue())){
continue;
} else {
iter.remove(); // I need to remove the object only if true for both entries in the Calendar array
}
}
}
}
The obvious solution would be to reverse the order of the loops. Have the outer loop iterate over the Map entries, and the inner loop iterate over the array. In the inner loop, set some flag to true the first time your currentPartOfWeek.matches(entry.getValue()) is false (or true, it wasn't clear from your question when you want to remove the entry), and only remove that entry if that flag is true.
This way you only iterate once over the Map.
Basically, it will look like this:
Iterator<Map.Entry<Object,String>> iter = objects.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Object,String> entry = iter.next();
boolean remove = false;
for(Calendar range: clientTimeRange) {
if (someCondition) {
if (remove) {
iter.remove();
} else {
remove = true;
}
}
}
}
Note that this relies on having two elements in your clientTimeRange array. If there are more elements, you should adjust the logic accordingly (i.e. decide when you want to remove the entry - after two elements of the array match the current Map entry? after all the elements of the array match the current entry?).

How to remove element from ArrayList?

I have added data into ArrayList and now want to update that list be deleting some element from it.
I have element something like 1,2,3,4 in ArrayList of type CartEntry.
Code :
ArrayList<CartEntry> items = new ArrayList<CartEntry>();
public void remove(int pId)
{
System.out.println(items.size());
for(CartEntry ce : items)
{
if(ce.getpId() == pId)
{
items.remove(ce);
//System.out.println(items.get(1));
}
}
items.add(new CartEntry(pId));
}
CartEntry Code :
public long getpId() {
return pId;
}
Constructor :
public CartEntry(long pId) {
super();
this.pId = pId;
}
when I am trying this code it gives me an error:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
Here pId is the argument that specify that item should be deleted from items.
Suppose I want to delete item that have 2 data then what will I have to do ?
You are facing ConcurrentModificationException because you are doing two operations on the same list at a time. i.e looping and removing same time.
Inorder to avoid this situation use Iterator,which guarantees you to remove the element from list safely .
A simple example looks like
Iterator<CartEntry> it = list.iterator();
while (it.hasNext()) {
if (it.next().getpId() == pId) {
it.remove();
break;
}
}
There are at least two problems with your code:
you call remove on the collection you iterate over, that will cause a ConcurrentModificationException if you continue iterating after the remove.
There are two ways to fix this:
stop iterating after you found the object you want to remove (just add a break or a return) or
switch from the enhanced for-loop to using an Iterator and its remove method.
you add an element in your remove method, that's probably not what you want.
So I'd use this code (this assumes that there is only ever one CartEntry with a given id in the list):
public void remove(int pId)
{
for(CartEntry ce : items)
{
if(ce.getpId() == pId)
{
items.remove(ce);
return;
}
}
}
If the assumption with the unique id is not correct, then you'll need to use the Iterator approach:
public void remove(int pId)
{
Iterator<CartEntry> it = items.iterator();
while(it.hasNext())
{
CartEntry ce = it.next();
if(ce.getpId() == pId)
{
it.remove();
}
}
}
you have created an Arraylist of type carEntry. So you need to create an Iterator of type CarEntry
Iterator<CarEntry> it = items.iterator();
while(it.hasNext())
{
if(it.next().getPId == PId)
it.remove();
}
Implement .equals in CartEntry and then use ArrayList.remove(CartEntry) or loop through your array list, find the item with some condition, mark the index, and call ArrayList.remove(index) -- AFTER the loop
Try,
public void remove(int pId){
Iterator<CartEntry> it = items.iterator();
while(it.hasNext()) {
CartEntry entry = it.next();
if (entry.getpId() == pId) {
it.remove();
}
}
}
The enhanced-for(or for each) loop for iterating over an Expression which is a subtype of Iterable<E> or raw Iterable, basically equivalent to the following form:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
VariableIdentifiers_opt TargetType Identifier = (TargetType) #i.next();
Statement
}
This is clearly stated in jls 14.14.2. The enhanced for statement section.
For your context the Expression is an ArrayList. the iterators returned by ArrayList's iterator method is fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.
use an Iterator instead and use it's own remove() method:
Iterator<E>iterator = list.iterator();
while(iterator.hasNext())
if(iterator.next().equals(E))
iterator.remove();

Java: Get element before or after a given one in an Iterable

Is there a non verbose way (for example using a method call from an existing library, be it guava or similar) to retrieve the previous and the following element from an Iterable, given one of its elements?
I would like to have a general solution that fits for Iterable (or Collection if it is cool enough), so please do not post solutions that work just for Set or List and so on (maybe add a comment :) ).
I need either one or the other, I do not want to find both previous and following element in one method.
My solution is below. If you feel like commenting on returning null instead of throwing IllegalArgumentException or similar, please feel free to do so. The getElementBefore() method creates a new list, which I am not that happy with too.
public static <C> C getElementAfter(final C element, final Iterable<C> iterable) {
Iterator<C> iterator = iterable.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals(element)) {
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
}
throw new IllegalArgumentException("Iterable does not contain element.");
}
public static <C> C getElementBefore(final C element, final Iterable<C> iterable) {
return getElementAfter(element, Lists.reverse(Lists.newArrayList(iterable)));
}
Returning null would probably make more sense in this case, as it may not be an exception.
Your getElementBefore implementation could be improved:
public static <C> C getElementBefore(final C element, final Iterable<C> iterable) {
C previous = null;
while (iterator.hasNext()) {
C current = iterator.next();
if (current.equals(element)) {
return previous;
} else {
previous = current;
}
}
return null;
}
I would do something like this:
Iterator<C> iterator = iterable.iterator();
C before = null;
C after = null;
while (iterator.hasNext()) {
C current = iterator.next();
if (current.equals(element)) {
if (iterator.hasNext()) {
after = iterator.next();
}
break;
}
before = current;
}
This should save the element before in before and the element after in after.

Get specific class objects from HashSet in Java

I have a public Set<ProjectItem> projectItems = new HashSet<ProjectItem>(); which can contains two types of classes (ProjectItem is a abstract super class for both of them). The classes are Deliverable and Task. I want get all objects of the class Deliverable from the Set. Therefore I write this:
public Set<Deliverable> allDeliverables(){
Set<Deliverable> result = new HashSet<Deliverable>();
for(Iterator<ProjectItem> iter = projectItems.iterator(); iter.hasNext(); iter.next()){
if (iter.next().getClass() == Deliverable.class){
Deliverable del = (Deliverable) iter.next();
result.add(del);
}
}
return result;
}
But this makes an exception -
Exception in thread "main" java.lang.ClassCastException: edu.Chryb.ProjectManagement.Task cannot be cast to edu.Chryb.ProjectManagement.Deliverable
in the Line with: Deliverable del = (Deliverable) iter.next();
Is something in the if query wrong?
Thanks for every help.
Your code is a bit out. Try:
for(Iterator<ProjectItem> iter = projectItems.iterator(); iter.hasNext(); iter.next()){
ProjectItem item = iter.next();
if (item.getClass() == Deliverable.class){
result.add((Deliverable)item);
}
}
The problem is the multiple invocations of iter.next() (because it return current element and forwards the cursor to the next element) within the loop.
Within the loop do something as follows first -
for(Iterator<ProjectItem> iter = projectItems.iterator(); iter.hasNext();){
ProjectItem currItem = iter.next();
//...
And then use currItem instead of calling iter.next() multiple times.
Side Note:
for(Iterator<ProjectItem> iter = projectItems.iterator(); iter.hasNext(); iter.next()) {
The call iter.next() doesn't have to do with the mentioned problem but it shouldn't be there also. Because that you will skip actual current element.
You are calling iter.next() twice - once in the check, and once on the retrieval. It appears that you find a Deliverable followed by Task. The check of Deliverable succeeds, but the iterator moves on to Task right after that, so the following invocation of next returns a Task, not a Deliverable.
Change your code as follows:
for(Iterator<ProjectItem> iter = projectItems.iterator(); iter.hasNext(); iter.next()){
ProjectItem next = iter.next();
if (next.getClass() == Deliverable.class){
Deliverable del = (Deliverable) next;
result.add(del);
}
}

Is it possible to get the index of a for-each loop in Java

Given the code below, is it possible to remove the index of p from the properties list using this style of for loop in Java?
List<Properties> propertiesList = new ArrayList<Properties>();
String keyToDelete = "blah";
for(Properties p : propertiesList) {
if(p.getKey().equals(keyToDelete)) {
propertiesList.remove(index) //How to remove the element at index 'p'
}
}
This is how i would accomplish this with the other for loop
List<Properties> propertiesList = new ArrayList<Properties>();
String keyToDelete = "blah";
for(int i = 0; i < propertiesList.size(); i++) {
if(p.getKey().equals(keyToDelete)) {
propertiesList.remove(i);
}
}
The way to do this is with an explicit Iterator (no school like the old school!).
Iterator<Properties> it = propertiesList.iterator();
while (it.hasNext()) {
if (it.next().getKey().equals(keyToDelete)) {
it.remove();
}
}
Unlike the remove method on a list, the remove method on the iterator doesn't cause a concurrent modification. It's the only safe way to remove an element from a collection you're iterating over. As the javadoc for that method says:
The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.
No, you need to use the old-school for loop to get an index.
You could of course add it yourself to the for-each loop, but then you would most probably be better off using the old variant instead.
How about using proper Iterator and its remove method?
List<Properties> propertiesList = new ArrayList<Properties>();
String keyToDelete = "blah";
for (
Iterator<Properties> iter = propertiesList.iterator( );
iter.hasNext( );
)
{
Properties p = iter.next( );
if(p.getKey().equals(keyToDelete)) {
iter.remove( );
}
}
As Tim Anderson suggested you could also modify the list outside the loop
List<Properties> propertiesList = new ArrayList<Properties>();
String keyToDelete = "blah";
List<Properties> propertiesToRemove = new ArrayList<Properties>();
for(Properties p : propertiesList) {
if(p.getKey().equals(keyToDelete)) {
propertiesToRemove.add(p) ;
}
}
propertiesList.removeAll(propertiesToRemove);
As far as I know, foreach loop does not guarantee the order of elements it enumerates,
so if you will try Collection[i] you can get another element rather than currently iterated
It is can be clearly viewed in some multithreaded cases

Categories

Resources