bloginvoke

Transforming an Iterator over X into an Iterator over Y in Java 5

Hannes de Jager java

I recently got exited about some new uses for an old design pattern, the Iterator. The implementation of Generics that we have since Java 5 stimulated this idea: To take an iterator over some data set and convert it into an iterator over that same data set, but that yields an interpreted value on each iteration. This is accomplished by using another design pattern that I power use these days dubbed the Transform. A transform is a method that takes an input and produces a transformed output value. See the Txf interface below.

The code below shows the basic concept. It takes an iterator over file names and converts it to an iterator over file sizes (the sizes of those files)

class Iterx {
 
 public interface Txf<I,O> {
   /** Takes some input and produces a transformed/interpreted output value. */
   public O transform(I input);
 } 
 
 /** Changes/transforms the iteration variable of the supplied iterator according to the supplied transformation */
 public static <I,O> Iterator<O> transform(final Iterator<I> iter, final Txf<I, O> txf) {
  return new Iterator<O>() {
   @Override
   public boolean hasNext() {
    return iter.hasNext();
   }
   @Override
   public O next() {
    return txf.transform(iter.next());
   }
   @Override
   public void remove() {
    iter.remove();
   }
  };
 }
 
 /** Converts an iterator to an iterable so that it can be used in for each loops. */
 public static <T> Iterable<T> from(final Iterator<T> itr) {
  return new Iterable<T>() {
   @Override
   public Iterator<T> iterator() {
    return itr;
   }
  };
 }
 
 public static void main(String[] args) {
  List<String> s = new ArrayList<String>();
  s.add("a.txt");
  s.add("b.txt");
  s.add("c.txt");
  Iterator<Long> sizeIter = Iterx.transform(s.iterator(), new Txf<String, Long>() {
   @Override
   public Long transform(String input) {
    return new File(input).length();
   }
  });
 
  long totalSize = 0;
  for (long fSize : Iterx.from(sizeIter)) {
   totalSize += fSize;
  }
  System.out.println("Total File Size: " + totalSize);
 }
}

From this concept I was able to build a library that allows me to write code like the following:

Iterx
    .from(myIter)
    .select(someTransformation)
    .where(someCondition);
Hannes de Jager
Software Builder