Running on Java 17-ea+15-1230 (Preview)
Home of The JavaSpecialists' Newsletter

178bWalkingCollection Generics (Follow-Up)

Author: Dr. Heinz M. KabutzDate: 2009-11-17Java Version: 5Category: Language
 

Abstract: Generics can be used to further improve the WalkingCollection, shown in our previous newsletter.

 

When I wrote the WalkingCollection, I was not very happy that PrintProcessor was defined with a generic type, since it could always be called on Object. I was also not happy with the WalkingCollection.iterate() method signature as it was too restrictive. At the very least, it should have been defined with <? super E> type parameter. One of my subscribers, Per Claesson, a Java specialist from Gothenburg, Sweden, picked up on this issue, so together we improved the code a bit.

We are planning an informal get-together next week Thursday evening (26th Nov 09) at 18:30 in Montreal (Quebec), where I will be presenting my "Secrets of Concurrency" talk. Seating is limited. There is no cover charge to attend. Please let me know if you are interested.

We have three upcoming LIVE virtual classes in April and May 2021:

  1. Refactoring to Streams and Lambdas for US$ 497 on April 6-7 2021 @ 9am-1pm Frankfurt Time.
  2. Extreme Java - Advanced Topics Java 17 Edition for EUR 1299 on April 19-20 2021 @ 9am-5pm Frankfurt Time. (almost sold out)
  3. Design Patterns Deep Dive for US$ 497 on May 11-12 2021 @ 7-11am Los Angeles Time.

My favourite course at the moment is the Refactoring to Streams and Lambdas course. We spend 8 hours ripping apart a 330k LOC application and replacing bits with more modern code. Too much fun! We still have a few places available for next week. The Advanced Topics Course is also very interesting. It is almost sold out though, so please grab the seats if you would like to join.

WalkingCollection Generics

In the WalkingCollection newsletter, we looked at how we could control the iteration from within the Collection, thus making concurrency easier. However, the interface was more restrictive than necessary. Instead, we could have written the following iterate() method:

public void iterate(Processor<? super E> processor) {
  rwlock.readLock().lock();
  try {
    iterating.set(true);
    for (E e : wrappedCollection) {
      if (!processor.process(e)) break;
    }
  } finally {
    iterating.set(false);
    rwlock.readLock().unlock();
  }
}
  

This would allow us to write the PrintProcessor to be defined on Object, rather than on the same generic type parameter as our WalkingCollection. Infact, any Processor can be defined on a super type of the WalkinCollection's type parameter.

public class PrintProcessor implements Processor<Object> {
  public boolean process(Object o) {
    System.out.println(">>> " + o);
    return true;
  }
}
  

The CompositeProcessor is now changed to contain a collection of super classes of E, as follows:

import java.util.*;

public class CompositeProcessor<E>
    implements Processor<E> {
  private final List<Processor<? super E>> processors =
      new ArrayList<Processor<? super E>>();

  public void add(Processor<? super E> processor) {
    processors.add(processor);
  }

  public boolean process(E e) {
    for (Processor<? super E> processor : processors) {
      if (!processor.process(e)) return false;
    }
    return true;
  }
}
  

Instead of constructing the PrintProcessor with a type parameter, we simply construct it with Object. The rest of the WalkingCollectionTest class remains the same:

public class WalkingCollectionTest {
  public static void main(String[] args) {
    WalkingCollection<Long> ages = new WalkingCollection<Long>(
        new java.util.ArrayList<Long>()
    );

    ages.add(10L);
    ages.add(35L);
    ages.add(12L);
    ages.add(33L);

    PrintProcessor pp = new PrintProcessor();
    ages.iterate(pp);

    AddProcessor<Long> ap = new AddProcessor<Long>();
    ages.iterate(ap);
    System.out.println("ap.getTotal() = " + ap.getTotal());

    // composite
    System.out.println("Testing Composite");
    ap.reset();

    CompositeProcessor<Long> composite =
        new CompositeProcessor<Long>();
    composite.add(new Processor<Long>() {
      private long previous = Long.MIN_VALUE;
      public boolean process(Long current) {
        boolean result = current >= previous;
        previous = current;
        return result;
      }
    });
    composite.add(ap);
    composite.add(pp);
    ages.iterate(composite);
    System.out.println("ap.getTotal() = " + ap.getTotal());
  }
}  

Paul Cowan sent me another interesting piece of code that is related to what we have done here. It compiles in Java 6, but not in Java 5:

import java.util.*;
import java.util.concurrent.*;

public class CompilesOnJava6Not5 {
  public static void main(String args[]) throws Exception {
    List<WorkerTask> tasks = new ArrayList<WorkerTask>();
    ExecutorService executor = Executors.newCachedThreadPool();
    executor.invokeAll(tasks); // fails in Java 5, but not in 6
  }

  public static class WorkerTask implements Callable<String> {
    public String call() {
      return "some work";
    }
  }
}
  

The reason is a change in the signature of the invokeAll() method. Previously, it would only accept Collection<Callable<T>>. However, in Java 6 they changed that to also accept Collection<Callable<? extends T>>:

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
  throws InterruptedException;
  

As a result, we can now upcast the List<WorkerTask> to Collection<? extends Callable<T>>.

Kind regards

Heinz

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack 21

Superpack 21 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...

Java Emergency?

If your system is down, we will review it for 15 minutes and give you our findings for just 1 € without any obligation.