Java 8流API,如何使用几个List字段将List收集到Object

时间:2019-02-13 13:06:48

标签: java lambda java-8 java-stream

我想从没有List <>字段的对象列表中获得一个带有List <>字段的对象。

这是我的代码:

public class ObjectDTO {
    private List<String> ids;
    private List<Date> times;
    private List<String> names;
    private List<String> details;

public class ObjectDTOHelper {
        private String id;
        private Date time;
        private String name;
        private String detail;
}

我提供List<ObjectDTOHelper>作为输入,并且只想获取ObjectDTO的对象。

我可以使用多个独立的流函数来解决:

List<ObjectDTOHelper> helpers; //about 1000 elements

List<String> ids= helpers.stream().map(h -> h.id).collect(toList());
List<Date> times= helpers.stream().map(h -> h.time).collect(toList());
List<String> names= helpers.stream().map(h -> h.name).collect(toList());
List<String> details= helpers.stream().map(h -> h.detail).collect(toList());

new ObjectDTO(ids, times, name, detail)

我认为这不是最好的解决方案,因为我需要执行100_000次以上)

您能帮助更好地解决这个问题吗?

3 个答案:

答案 0 :(得分:0)

假设ObjectDTO中的字段初始化为:

public class ObjectDTO {
    private List<String> ids = new LinkedList<>();
    ...
}

更新:请参见When to use LinkedList over ArrayList in Java?

您可以使用IntStream

填写
ObjectDTO objectDTO = new ObjectDTO();

IntStream.range(0, helpers.size())
    .forEach(i -> {
        objectDTO.getIds().add(helpers.get(i).getId());
        objectDTO.getTimes().add(helpers.get(i).getTime());
        objectDTO.getNames().add(helpers.get(i).getName());
        objectDTO.getDetails().add(helpers.get(i).getDetail());
     });

答案 1 :(得分:0)

要添加到已经完成的工作中的一种可能的优化方法是为所有列表预分配所需的确切内存量:

List<ObjectDTOHelper> helpers = ...; //about 1000 elements
int size = helpers.size();

List<String> ids= helpers.stream().map(h -> h.id).collect(toCollection(()->new ArrayList<>(size)));
List<Date> times= helpers.stream().map(h -> h.time).collect(toCollection(()->new ArrayList<>(size)));
List<String> names= helpers.stream().map(h -> h.name).collect(toCollection(()->new ArrayList<>(size)));
List<String> details= helpers.stream().map(h -> h.detail).collect(toCollection(()->new ArrayList<>(size)));

new ObjectDTO(ids, times, name, detail)

如果此类字段太多,则可以创建自己的收集器以传递给collect()。

答案 2 :(得分:0)

假设一个CPU /线程的解决方案在复杂度(O(n))方面同样高效,但是由于独立的lambda,它可能会有不必要的开销。

进行一次向ObjectDTO添加辅助程序的操作有意义吗:

class ObjectDTO {
  private List<String> ids;
  private List<Date> times;
  private List<String> names;
  private List<String> details;
  //...
  public void add(ObjectDTOHelper helper) {
      ids.add(helper.id)
      times.add(helper.time);
      names.add(helper.name);
      details.add(helper.detail);
  }
  //...
  public void addAll(Collection<? extends ObjectDTOHelper> helpers) {
     helpers.stream().forEach(this::add);
  }
  //...
}

如果ObjectDTO是常量类(创建后不允许进行修改),则可以将这些方法更改为private并在接受构造函数的公共构造函数中使用addAll助手集合。

您还可以借此机会根据要添加到每个辅助位的预期和已知数量来调整列表的大小。

class ObjectDTO {
  // ...
  public ObjectDTO(Collection<? extends ObjectDTOHelper> helpers) {
     int size = helpers.size();

     ids = new ArrayList<>(size);
     names = new ArrayList<>(size);
     // ...
     addAll(helpers);
  }

也总是使用ArrayList而不是LinkedList ...我认为,链接要比数组更好的唯一情况是,如果您要在大列表的中间进行重复插入,那不是你的情况。