Java: Converting lists of one element type to a li

2020-05-19 09:06发布

I'm writing an adapter framework where I need to convert a list of objects from one class to another. I can iterate through the source list to do this as in

Java: Best way of converting List<Integer> to List<String>

However, I'm wondering if there is a way to do this on the fly when the target list is being iterated, so I don't have to iterate through the list twice.

9条回答
太酷不给撩
2楼-- · 2020-05-19 09:45

As an alternative to the iterator pattern, you can use a abstract generic mapper class, and only override the transform method:

  1. create a generic collection mapper for any data type
  2. [optional] create a library of methods that transform between different data types (and override the method)
  3. use that library

the implementation:

// Generic class to transform collections
public abstract class CollectionTransformer<E, F> {

    abstract F transform(E e);

    public List<F> transform(List<E> list) {
        List<F> newList = new ArrayList<F>();
        for (E e : list) {
            newList.add(transform(e));
        }
        return newList;
    }
}

// Method that transform Integer to String
// this override the transform method to specify the transformation
public static List<String> mapIntegerToStringCollection(List<Integer> list) {

    CollectionTransformer transformer = new CollectionTransformer<Integer, String>() {
        @Override  
        String transform(Integer e) {
            return e.toString();
        }
    };
    return transformer.transform(list);
}

// Example Usage
List<Integer> integers = Arrays.asList(1,2);
List<String> strings = mapIntegerToStringCollection(integers);

This would be useful is you have to use transformations every time, encapsulating the process. So you can make a library of collection mappers very easy.

查看更多
仙女界的扛把子
3楼-- · 2020-05-19 09:46

Java 8 way:

List<String> original = ...;
List<Wrapper> converted = original.stream().map(Wrapper::new).collect(Collectors.toList());

assuming Wrapper class has a constructor accepting a String.

查看更多
【Aperson】
4楼-- · 2020-05-19 09:52

Well, you could create your own iterator wrapper class to do this. But I doubt that you would save much by doing this.

Here's a simple example that wraps any iterator to a String iterator, using Object.toString() to do the mapping.

public MyIterator implements Iterator<String> {

    private Iterator<? extends Object> it;

    public MyIterator(Iterator<? extends Object> it) {
        this.it = it;
    }

    public boolean hasNext() {
        return it.hasNext();
    }

    public String next() {
        return it.next().toString();
    }

    public void remove() {
        it.remove();
    }
}
查看更多
贼婆χ
5楼-- · 2020-05-19 10:01

My answer to that question applies to your case:

import com.google.common.collect.Lists;
import com.google.common.base.Functions

List<Integer> integers = Arrays.asList(1, 2, 3, 4);

List<String> strings = Lists.transform(integers, Functions.toStringFunction());

The transformed list is a view on the original collection, so the transformation happens when the destination List is accessed.

查看更多
We Are One
6楼-- · 2020-05-19 10:01

Lambdaj allows to do that in a very simple and readable way. For example, supposing you have a list of Integer and you want to convert them in the corresponding String representation you could write something like that;

List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
    public String convert(Integer i) { return Integer.toString(i); }
});

Lambdaj applies the conversion function only while you're iterating on the result. There is also a more concise way to use the same feature. The next example works supposing that you have a list of persons with a name property and you want to convert that list in an iterator of person's names.

Iterator<String> namesIterator = convertIterator(persons, on(Person.class).getName());

Pretty easy. Isn't it?

查看更多
够拽才男人
7楼-- · 2020-05-19 10:02

That question does not iterate through the list twice. It just iterates once and by far is the only known method.

Also you could use some transformer classes in commons-collections of google-collections but they all do the same thing under the hood :) the following being one way

CollectionUtils.collect(collectionOfIntegers, new org.apache.commons.collections.functors.StringValueTransformer());
查看更多
登录 后发表回答