tags:

views:

311

answers:

5

I am new in Java so please be patient.

It is common to map (convert) lists to lists. Some languages have a map method, some (C#) Select. How is this done with Java? Is a for loop the only option?

I expect to be able to do something like this:

List<Customer> customers = new ArrayList<Customer>();
...
List<CustomerDto> dtos = customers.convert(new Converter(){
  public convert(c) {
    return new CustomerDto();
  }
})

I have missed something? Please give me a starting point.

+4  A: 

There is no built-in way of doing this in Java - you have to write or use a helper class. Google Collections includes

public static <F,T> List<T> transform(List<F> fromList,
                                  Function<? super F,? extends T> function)

This works well, but it's a bit clumsy to use, as you have to use a one-method anonymous class and a static method. This is no fault of Google Collections, it is just the nature of doing this type of task in Java.

Note that this lazily transforms items in the source list as needed.

Steve McLeod
Pity.. But thanks, this definitely needs a look.
Mike Chaliy
+2  A: 

As long as customerDto extends Customer, this will work

   List<Customer> customers = new ArrayList<Customer>();

   List<CustomerDto> dtos = new ArrayList<CustomerDto>(customers);

Otherwise :

List<Customer> customers = new ArrayList<Customer>();

List<CustomerDto> dtos = new ArrayList<CustomerDto>();

for (Customer cust:customers) {
  dtos.add(new CustomerDto(cust));
}
Mike Pone
Why do you think that CustomerDto extends Customer? This is not the case. Thanks for your replay.
Mike Chaliy
A: 

There isn't yet a way to apply a mapping function like this to a Java List (or other collections). Closures, which will provide this functionality, were seriously considered for the upcoming JDK 7 release, but they have been deferred to a later release due to a lack of consensus.

With current constructs, you can implement something like this:

public abstract class Convertor<P, Q>
{

  protected abstract Q convert(P p);

  public static <P, Q> List<Q> convert(List<P> input, Convertor<P, Q> convertor)
  {
    ArrayList<Q> output = new ArrayList<Q>(input.size());
    for (P p : input)
      output.add(convertor.convert(p));
    return output;
  }

}
erickson
Thank you for clarifying things.
Mike Chaliy
Minimalist closures are in JDK 1.1.
Tom Hawtin - tackline
I'm not a fan of any closure proposal; inner classes combined with iteration are good enough for me. My point here is that there is no method to apply one to a collection as the poster requested.
erickson
+4  A: 

I implemented something on the fly. See if this helps you. If not, use Google Collections as suggested.

public interface Func<E, T> {
    T apply(E e);
}

public class CollectionUtils {

    public static <T, E> List<T> transform(List<E> list, Func<E, T> f) {
     if (null == list)
      throw new IllegalArgumentException("null list");
     if (null == f)
      throw new IllegalArgumentException("null f");

     List<T> transformed = new ArrayList<T>();
     for (E e : list) {
      transformed.add(f.apply(e));
     }
     return transformed;
    }
}

List<CustomerDto> transformed = CollectionUtils.transform(l, new Func<Customer, CustomerDto>() {
 @Override
 public CustomerDto apply(Customer e) {
  // return whatever !!!
 }
});
bruno conde
As Steve McLeod's answer, you can be more flexible with your type parameters.
Tom Hawtin - tackline
A: 

Personally, I find the following shorter and simpler, but if you find the functional approach simpler you could do it that way. If other Java developers might need to read/maintain the code I suggest using the approach they might feel more comfortable with.

List<CustomerDto> dtos = new ArrayList<CustoemrDto>();
for(Customer customer: customers)
   dtos.add(new CustomerDto());

You might find this library interesting Functional Java

Peter Lawrey