用于转换不可变列表的番石榴单行程序

时间:2013-10-15 14:06:00

标签: java guava

我认为必须有一个单行的Guava解决方案,用于将不可变列表转换为另一个不可变列表,但我找不到它。假设我们有以下对象:

ImmutableList<String> input = ImmutableList.of("a", "b", "c");
Function<String, String> function = new Function<String, String>() {
    @Override
    public String apply(String input) {
        return input + input;
    }
};

转变可以这样实现:

Iterable<String> transformedIt = Iterables.transform(input, function);
ImmutableList<String> output = ImmutableList.<String>builder().addAll(transformedIt).build();

或者像这样:

List<String> transformedList = Lists.transform(input, function);
ImmutableList<String> output2 = ImmutableList.copyOf(transformedList);

但我认为必须有某种性能优化的单线程用于这种转换,没有中间对象,我就是找不到它。它在哪里?

3 个答案:

答案 0 :(得分:23)

您可以简单地移除构建器并将其内联以获得(更长的)单行

ImmutableList<String> output =
    ImmutableList.copyOf(Iterables.transform(input, function));

这是最优的,因为Iterables.transform的结果是惰性的,因此不会分配临时列表。 AFAIK有一些轻微的低效率:

  • 分配FluentIterable
  • 调整用于结果的数组的大小

如果你真的非常关心速度,你可以对它进行基准测试并与

之类的东西进行比较
ArrayList<String> tmp = Lists.newArrayListWithCapacity(input.size());
Iterables.addAll(tmp, Iterables.transform(input, function));
ImmutableList<String> output = ImmutableList.copyOf(tmp);

和手动循环。

更新

虽然第一种方法肯定是最具可读性的方法,但它会产生一些数组大小调整的分配以及最终缩小到所需大小的方法。使用长度为1234567的列表,有以下调整步骤:

4 - &gt; 7 - &gt; 11 - &gt; 17 - &gt; 26 - &gt; 40 - &gt; 61 - &gt; 92 - &gt; 139 - &gt; 209 - &gt; 314 - &gt; 472 - &gt; 709 - &gt; 1064 - &gt; 1597 - &gt; 2396 - &gt; 3595 - &gt; 5393 - &gt; 8090 - &gt; 12136 - &gt; 18205 - &gt; 27308 - &gt; 40963 - &gt; 61445 - &gt; 92168 - &gt; 138253 - &gt; 207380 - &gt; 311071 - &gt; 466607 - &gt; 699911 - &gt; 1049867 - &gt; 1574801

和最后收缩

1574801 - &gt; 1234567

更新2

正如路易斯和克里斯所说,最佳解决方案是

ImmutableList<String> output =
    ImmutableList.copyOf(Lists.transform(input, function));

因为它不包含数组复制。这是因为Lists.transform是一个惰性集合,ImmutableList.copyOf查询其大小以便分配一个正确大小的数组。请注意,Iterables.transformFluentIterable都不是那么有效。

答案 1 :(得分:1)

我认为你已经写过几个这样的单行的例子。转换是在最少的新对象创建的情况下完成的。事实上,Guava以懒惰的方式工作:它不会遍历您的列表,创建其他元素并将其放到另一个列表中。它创建了一个惰性列表,只要需要它就可以填充它,例如当你在迭代新列表时。我认为带有闭包的java 8对于这个用例来说不会太快,因为它会执行类似的字节代码,但语法会更短。

答案 2 :(得分:1)

我想input.stream().collect(toImmutableList())是您所需要的。参见doc