将数组A []转换为ArrayList <b> </b>的有效且最短的方法

时间:2015-03-12 16:07:06

标签: java java-8

我有2个班级

A:

  public class A {
    private int intValue;
    private String stringValue;

    public A(int intValue, String stringValue) {
      this.intValue = intValue;
      this.stringValue = stringValue;
    }

    int getIntValue() {
      return intValue;
    }

    String getStringValue() {
      return stringValue;
    }
  }

和B:

  public class B {
    private int intValue;
    private String stringValue;

    B(int intValue, String stringValue) {
      this.intValue = intValue;
      this.stringValue = stringValue;
    }

    int getIntValue() {
      return intValue;
    }

    String getStringValue() {
      return stringValue;
    }
  }

和一些非常大的A对象数组。

我希望有效地将A[]转换为ArrayList<B>。我知道有几种方法可以做到这一点:

final A[] array = {new A(1, "1"), new A(2, "2")/*...*/};

// 1 - old-school
final List<B> list0 = new ArrayList<>(array.length);
for (A a : array) {
  list0.add(new B(a.getIntValue(), a.getStringValue()));
}

// 2 - pretty mush same as 1
final List<B> list1 = new ArrayList<>(array.length);
Arrays.stream(array).forEach(a -> list1.add(new B(a.getIntValue(), a.getStringValue())));

// 3 - lambda-style
final List<B> list2 = Arrays.stream(array).map(a -> new B(a.getIntValue(), a.getStringValue())).collect(Collectors.toList());

// 4 - lambda-style with custom Collector
final List<B> list3 = Arrays.stream(array)
    .map(a -> new B(a.getIntValue(), a.getStringValue()))
    .collect(Collector.of((Supplier<List<B>>)() -> new ArrayList(array.length), List::add, (left, right) -> {
      left.addAll(right);
      return left;
    }));

AFAIK 1效率最高。但是使用java 8功能可以缩短它。 2与1几乎相同,但foreach循环由流foreach替换。不确定它的有效性。 3是最短路径,但默认Collectors.toList()收集器使用默认的ArrayList::new构造函数,这意味着如果我们有相当大的初始数组,ArrayList中的数组将至少调整一次。所以效率不高。 4,正如我所理解的那样(从未使用过这种方式)与3几乎相同,但在ArrayList中为数组分配了单个内存。但它看起来很难看。

所以,我的问题是。我对这四种方式及其有效性是否正确?还有其他简短有效的方法吗?

2 个答案:

答案 0 :(得分:4)

你的#4可能会在短时间内写出来:

final List<B> list4 = Arrays.stream(array)
    .map(a -> new B(a.getIntValue(), a.getStringValue()))
    .collect(toCollection(() -> new ArrayList<>(array.length)));

您还可以使用单独的方法提取映射:

final List<B> list4 = Arrays.stream(array)
    .map(SomeClass::mapA2B)
    .collect(toCollection(() -> new ArrayList<>(array.length)));    

private static B mapA2B(A a) {
  return new B(a.getIntValue(), a.getStringValue());
}

答案 1 :(得分:1)

如果您对最有效的解决方案感兴趣,可以考虑

List<B> list=Arrays.asList(Arrays.stream(array)
    .map(a -> new B(a.getIntValue(), a.getStringValue()))
    .parallel().toArray(B[]::new));

与使用collect抽象的Collector不同,toArrayStream的内在操作。由于Arrays.asList返回的流具有已知大小,因此实现将创建一个目标数组,并在并行处理时写入该数组的不同区域。相反,collect将创建多个列表,并行处理它们并在之后合并它们,这不适合像这样简单的操作。

即使是单线程使用,它也可能表现更好,因为它只是填充一个数组(“处理原始金属”)并在之后创建一个轻量级List视图。

这个想法是this comment made by Brian Goetz

的直接后果