0

I have a LinkedHashSet of objects (each object has 3 instance variables) and i need to operate on each object and process the fields. How can I iterate through it? My guess is I need to use the Iterator, but I'm not sure how to do it.

Bogdan
  • 31
  • 1
  • 1
  • Have a look at "Traversing collections" from the [tutorial](https://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html). – Mick Mnemonic Jul 26 '18 at 08:37

3 Answers3

2

There are currently 3 major ways to iterate through a collection however the class has to implement the java.lan.Iterable interface. If so we can do as follows:

The common for-each loop:

Assuming a set Set<Object> set = new LinkedHashSet<>(); filled with random objects and we want to print then we can use the for-each loop:

for ( Object o : set )
{
  // o is the reference to the currently selected object
  System.out.println(o);
  processObject( o );
}

This loop will select every object in the set sequentially and process it as defined in the body. This specific loop prints it to the standard output stream and then passes the object to the processObject(Object o) method. Since this is just an example the method does nothing else than printing the value again. Since this loop acts sequtially each object is processed completely before the next one is 'selected'.
One major drawback of the for-each loop is that we cannot safely remove any items from the set during iteration.

Wrong example:

// Doing so will lead to a ConcurrentModificationException being thrown
for ( Object o : set )
{
  set.remove( o );
}

However the for-each loop can be expressed in another way.

The Iterator loop:

Quiet similar to Suryakant Bhartis answer we're this time using the java.util.Iterator in this example:

// Utilizing the iterator provided by Set#iterator()
for ( Iterator<Object> iter = set.iterator(); iter.hasNext(); /* empty*/ )
{
  // Iterator#next() returns the next object in line.
  Object o = iter.next();
  System.out.println( o );
  processObject( o );
}

The Iterator is declared and initialized directly within the for-loop and overall the structure is quite similar to a 'normal' loop ( for(int i = 0; i < n;i++){} ) but we have nothing to increment after the loop so the third section remains empty. This is because the Iterator has an internal counter and pointer to the next object which autmatically increment with a call to iterator#next(). However when the same object is needed by multiple operations we have to store it in a local variable first since subsequent calls to Iterator#next() will lead to different results or a NoSuchElementException if there are no more elements in the set.
Assuming we just wanted to pass our object of the set to the processObject method the boilerplate code would boil down to:

for ( Iterator<Object> iter = set.iterator(); iter.hasNext(); )
{
  processObject( iter.next() );
}

One major benefit of the Iterator is that we can remove items from the set if we do not longer need/want them in our set if the used Iterator supports it otherwise an UnsupportedOperationException is thrown.

So let's take a look at removing the item. For that we assume that our set contains only Integer values and therefore the Iterator returning Integer values:

for ( Iterator<Integer> iter = set.iterator(); iter.hasNext(); )
{
  // if the returned vlaue equals 3...
  if ( iter.next().intValue() == 3 )
  {
    // ... we remove it from the set 
    iter.remove();
  }
}

Note that this action will remove the returned object of the Iterator instead of the next one.

Java8 Streams, Lambdas and Method References.

Since Java 8 (JDK 1.8 or later) we are able to invoke streams on any class of the collections API which iterate through the entire content and are able to evaluate whatever is needed. Let's have a quick look at some possible operations:

// Invoke the stream and then print every object to the standard output stream
set.stream().forEach( System.out::println );
// A 'shortcut' for the above
set.forEach( Test::processObject );
// Safely removing objects from the set. (Also a 'shortcut').
set.removeIf( i -> i.intValue() == 3 );

However these are a little bit more complex since most of the iterations are obfuscated. It is therefore recommended to follow a tutorial like this to completely understand what the above does. It's also not recommended for beginners.

Community
  • 1
  • 1
L.Spillner
  • 1,772
  • 10
  • 19
1

A simple example solution to understand the concept. I hope it helps...

    LinkedHashSet<String> lhs = new LinkedHashSet<String>();

    //Adding elements to HashSet
    lhs.add("first");
    lhs.add("second");
    lhs.add("third");

    Iterator<String> itr = lhs.iterator();

    //Traversing or Iterating
    while(itr.hasNext()){
        System.out.println(itr.next());
    }
0

I would start quoting for sure this comment https://stackoverflow.com/a/51534527/4149078.

But I could suggest also to use the Java8 stream implementations.

    public static void main(String[] argv) {

    LinkedHashSet<String> set = new LinkedHashSet<>();

    set.add("First");
    set.add("Second");
    set.add("Third");

    set.stream().forEach(s -> {
        // Do your staff here
        System.out.println(s);
    });

    set.stream().map(s -> s.concat(" additional string")).forEach(s -> System.out.println(s));

    // Etc.
}

Read more info about stream click this link

carmelolg
  • 493
  • 5
  • 17