这里有一个使用Stream API的解决方案,它不需要进行额外的内存分配,如果您使用String和StringBuilder(因为即使在Java 8中也无法实例化没有复制数据的String,并且StringBuilder将为您提供访问其基础数组而不是副本的数组,而且自Java 9以来,String和StringBuilder都由byte[]数组支持而不是字符数组)。
首先,计算结果数组的大小是有意义的(正如@Maarten Bodewes和@Michael在他们的答案中已经提到的),这是一种非常快速的操作,因为我们不处理这些数组的数据,而只请求它们的长度。
然后为了构造结果数组,我们可以利用收集器,将流元素累积到底层char[]数组中,然后在所有流元素被处理完毕且没有中间转换和分配额外内存时将其提供出来。
所有
collector 的功能都需要是无状态的,更改应该只发生在其可变容器内部。因此,我们需要一个
可变容器 包装一个
char[]
数组,但它不应该像
StringBuilder
一样有一个
强封装,即允许访问其底层数组。我们可以通过使用
CharBuffer
来实现这一点。
所以基本上和
Maarten Bodewes 的答案 中介绍的相同思路完全使用流实现。
CharBuffer.allocate(length)
在幕后将实例化给定长度的
char[]
,而
CharBuffer.array()
将返回相同的数组,而不生成额外的副本。
public static void main(String[] args) {
List<char[]> listOfCharArrays =
List.of(new char[]{'a', 'b', 'c'},
new char[]{'d', 'e', 'f'},
new char[]{'g', 'h', 'i'});
char[] charArray = listOfCharArrays.stream()
.collect(Collectors.collectingAndThen(
Collectors.summingInt(arr -> arr.length),
length -> listOfCharArrays.stream().collect(
Collector.of(
() -> CharBuffer.allocate(length),
CharBuffer::put,
CharBuffer::put,
CharBuffer::array
))
));
System.out.println(Arrays.toString(charArray));
}
输出:
[a, b, c, d, e, f, g, h, i]
flatMap
存在的原因:将“二维”的源压扁成“一维”的流。 - Slawchar
原始类型的特化(如IntStream
),我看不到任何方法可以比迭代解决方案更易读。即使有,我强烈怀疑迭代解决方案会更快,因为arrayCopy
可以复制内存块,而流解决方案则需要逐个处理字符。 - Michaelchar[] concat(char[] array1, char[] array2)
,那么就可以实现这个功能。然后使用reduce
和身份元素new char[0]
,你可以将所有这些char[]
元素简单地连接成一个char[]
。这样做的缺点是会创建很多中间char[]
。更简单的选项需要两次迭代 - 一次获取总长度(可以使用流完成),一次复制。我个人会使用一个简单的 for 循环来完成后者,因为System.arraycopy
的起始索引会不断变化,需要一些恶心的技巧才能在流内部使其正常工作。 - Rob Spoor