Java Guava one-liner 用于转换不可变列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19383323/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Guava one-liner for transforming immutable lists
提问by WannaKnow
I think there must be a one-liner Guava solution for transforming an immutable list into another immutable list, but I can't find it. Suppose we have the following objects:
我认为必须有一个单行的 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;
}
};
The transformation can be achieved like this:
转换可以这样实现:
Iterable<String> transformedIt = Iterables.transform(input, function);
ImmutableList<String> output = ImmutableList.<String>builder().addAll(transformedIt).build();
or like this:
或者像这样:
List<String> transformedList = Lists.transform(input, function);
ImmutableList<String> output2 = ImmutableList.copyOf(transformedList);
but I think that there must be somewhere a performance-optimized one-liner for this kind of transformation, without intermediate objects, I just can't find it. Where is it?
但是我认为对于这种转换,必须有性能优化的单线,没有中间对象,我就是找不到。它在哪里?
采纳答案by maaartinus
You can simply remove your builder and inline it to get a (bit longer) one-liner
您可以简单地移除您的构建器并将其内联以获得(更长的)单线
ImmutableList<String> output =
ImmutableList.copyOf(Iterables.transform(input, function));
This is sort of optimal as the result of Iterables.transform
is lazy, so no temporary list gets allocated. There are AFAIK some minor inefficiencies:
这是一种最佳结果,因为它Iterables.transform
是懒惰的,因此没有分配临时列表。AFAIK 存在一些小问题:
- Allocation of a
FluentIterable
- Resizing of the array used for the result
- 分配一个
FluentIterable
- 调整用于结果的数组的大小
If you really care a lot about the speed, you could benchmark it and compare to something like
如果你真的很关心速度,你可以对它进行基准测试并与类似的东西进行比较
ArrayList<String> tmp = Lists.newArrayListWithCapacity(input.size());
Iterables.addAll(tmp, Iterables.transform(input, function));
ImmutableList<String> output = ImmutableList.copyOf(tmp);
and to a handrolled loop.
和手动循环。
UPDATE
更新
While the first approach is surely the most readable one, it incurs some allocations for array resizing and also the final shrinking to desired size. With a list of length 1234567, there are the following resizing steps:
虽然第一种方法肯定是最易读的方法,但它会为数组调整大小以及最终缩小到所需大小而进行一些分配。对于长度为 1234567 的列表,有以下调整大小步骤:
4 -> 7 -> 11 -> 17 -> 26 -> 40 -> 61 -> 92 -> 139 -> 209 -> 314 -> 472 -> 709 -> 1064 -> 1597 -> 2396 -> 3595 -> 5393 -> 8090 -> 12136 -> 18205 -> 27308 -> 40963 -> 61445 -> 92168 -> 138253 -> 207380 -> 311071 -> 466607 -> 699911 -> 1049867 -> 1574801
4 -> 7 -> 11 -> 17 -> 26 -> 40 -> 61 -> 92 -> 139 -> 209 -> 314 -> 472 -> 709 -> 1064 -> 1597 -> 2396 -> 3595 - > 5393 -> 8090 -> 12136 -> 18205 -> 27308 -> 40963 -> 61445 -> 92168 -> 138253 -> 207380 -> 311071 -> 466697 -> 466697>7->1
and the final shrinking
和最后的缩小
1574801 -> 1234567
1574801 -> 1234567
UPDATE 2
更新 2
As Louis and Chris said, the optimal solution is
正如路易斯和克里斯所说,最佳解决方案是
ImmutableList<String> output =
ImmutableList.copyOf(Lists.transform(input, function));
as it includes no array copying. This works as the result of Lists.transform
is a lazy collection and ImmutableList.copyOf
queries its size in order to allocate a properly sized array. Note that neither Iterables.transform
nor FluentIterable
are that efficient.
因为它不包括数组复制。这是因为Lists.transform
是惰性集合并ImmutableList.copyOf
查询其大小以分配适当大小的数组。请注意,既不高效Iterables.transform
也不FluentIterable
高效。
回答by AlexR
I think that you have already written several examples of such one-liners. The transformation is done with minimal creation of new objects. Indeed Guava works in lazy manner: it does not iterate over your list, creates other elements and put it to another list. It creates lazy list that is filled as far as its elements are needed, e.g. while you are iterating over the new list. I think that java 8 with closures will not be too much faster for this use case because it will execute similar byte code but the syntax will be shorter.
我想你已经写了几个这种单行的例子。转换是通过最少的新对象创建完成的。事实上,番石榴以懒惰的方式工作:它不会遍历您的列表,创建其他元素并将其放入另一个列表。它会创建惰性列表,该列表会根据需要填充元素,例如,当您迭代新列表时。我认为对于这个用例来说,带有闭包的 java 8 不会快太多,因为它会执行类似的字节码,但语法会更短。