ShoeShineBoy
ShoeShineBoy

Reputation: 82

ArrayLists better practice

I have written 2 methods in Java. Second method looks cleaner to me because I come from python background, but I think it will be slower than first because indexOf() also does the iteration? Is there a way to use for in loop correctly in situation like this? Also, if there is better way to do it (without Streams), how can it be done?

private ArrayList<MyObject> myObjects;

First method:

private int findObject(String objectName) {
    for(int i=0; i<this.myObjects.size(); i++) {
        MyObject myObject = this.myObjects.get(i);
        if(myObject.getName().equals(objectName)) return i;
    }
    return -1;
}

Second method:

private int findObject(String objectName) {
    for(MyObject myObject: this.myObjects) {
        if(myObject.getName().equals(objectName)) return this.myObjects.indexOf(myObject);
    }
    return -1;
}

Upvotes: 0

Views: 65

Answers (3)

Stephen C
Stephen C

Reputation: 718788

I think it will be slower than first because indexOf() also does the iteration?

You are correct.

Is there a way to use for each loop correctly in situation like this?

You can use a for each AND an index variable.

private int findObject(String objectName) {
    int i = 0;
    for (MyObject myObject: this.myObjects) {
        if (myObject.getName().equals(objectName)) return i;
        i++;
    }
    return -1;
}

This would be a good solution if myObjects.get(i) is an expensive operation (e.g. on a LinkedList where get(n) is O(N)) or if it is not implementable (e.g. if you were iterating a Stream).

You could also use a ListIterator provided that myObjects has a method that returns a ListIterator; see @Andy Turner's answer for an example. (It won't work for a typical Set or Map class.)

Upvotes: 2

Ralf Kleberhoff
Ralf Kleberhoff

Reputation: 7290

The first version is perfect if you know you're working with an ArrayList (or some other array-based List, e.g. Vector).

If myObject happens to be a LinkedList or similar, your performance will degrade with longer lists, as then get(i) no longer executes in constant time.

Your second approach will handle LinkedLists as well as ArrayLists, but it iterates twice over your list, once in your for loop, and once in the indexOf() call.

I'd recommend a third version: use the for loop from the second approach, and add an integer counting variable, incrementing inside the loop. This way, you get the best of both: iterating without performance degradation, and cheap position-counting.

Upvotes: 1

Andy Turner
Andy Turner

Reputation: 140318

The better way of doing this (that avoids you having to maintain a separate index variable; and works for non-RandomAccess lists too) would be to use a ListIterator:

for (ListIterator<MyObject> it = myObjects.listIterator(); it.hasNext();) {
  MyObject myObject = it.next();
  if(myObject.getName().equals(objectName)) return it.prevIndex();
}
return -1;

Upvotes: 0

Related Questions