|
The Java Specialists' Newsletter
Issue 178b 2009-11-17
Category:
Language
Java version: 5+ WalkingCollection Genericsby Dr. Heinz M. KabutzAbstract: 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.
Would you like to really understand Java concurrency? Join us for an
in-depth study of how threading works in Java. During the course,
you will learn how to write correct and fast multi-threaded Java code.
Please
click here if you would like to learn more. 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
Language Articles
Related Java Course
Discuss at The Java Specialist Club
|