List type mapping in Java

Update for Java 8: List mapping in Java 8

Recently someone asked me how to convert a List of type X to a List of type Y, given a well-defined function from X to Y. I’ve seen some horrible “solutions” for that in real world programs, and I hope that some people will benefit from my way of doing this:

/**
 * Defines a Function from E to F.
 * @param <E> the domain
 * @param <F> the codomain
 */
public interface Converter<E,F> {
    F convert(E f);
}
/**
 * Maps a List of one type to a List of another type.
 * @param c the function used to convert from type E to type F
 * @param list the List to be mapped
 * @param <E> the domain
 * @param <F> the codomain
 * @return a new List with the elements mapped
 * @throws NullPointerException iff any argument is <code>null</code>
 */
public static <E,F> List<F> map(final Converter<E,F> c, final List<E> list) {
    if (c == null || list == null) {
        // fail early; particularly important when using lazy evaluation
        throw new NullPointerException();
    }
    return new AbstractList<F>() {
        @Override
        public F get(final int index) {
            return c.convert(list.get(index));
        }
 
        @Override
        public int size() {
            return list.size();
        }
    };
}

This is some pretty generic code that can be used in many situations. For example in web applications it’s often necessary to map a certain entity to a String representation to display on the page.

Here is a usage example:

final List<JFrame> frames = Arrays.asList(new JFrame("hello"), new JFrame("world"));
 
final List<String> titles = map(
        new Converter<JFrame, String>() {
            @Override
            public String convert(final JFrame f) {
                return f.getTitle();
            }
        },
        frames
);
 
System.out.println(titles); // prints: [hello, world]
 
final List<Integer> nums = Arrays.asList(1,2,3);
final List<Integer> inc = map(
        new Converter<Integer, Integer>() {
            @Override
            public Integer convert(final Integer f) {
                return f + 1;
            }
        },
        nums
);
 
System.out.println(inc); // prints: [2, 3, 4]

Not as sweet as it would look like in a functional programming language like Haskell or Scala, but as good as it gets in Java.

See also:

  • Functional Java provides a more pure approach, using its own List implementation rather than java.util.List
  • Jushua Bloch. Effective Java, 2nd Edition. Chapter 4, Item 18 provides a similar application of AbstractList

Leave a Reply

You must be logged in to post a comment.