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