面试题答案
一键面试使用普通for循环实现
fun main() {
val largeList = (1..1000000).toList()
var sum = 0
for (num in largeList) {
if (num % 2 == 0) {
sum += num * num
}
}
println(sum)
}
使用流式API实现
fun main() {
val largeList = (1..1000000).toList()
val sum = largeList.filter { it % 2 == 0 }
.map { it * it }
.sum()
println(sum)
}
性能差异及原理
- 普通for循环:
- 性能:通常在处理大数据集时性能较好。
- 原理:直接在内存中按顺序遍历列表,没有额外的中间操作对象创建。它在循环体内部直接进行条件判断和计算,没有过多的函数调用开销,对于简单的操作,直接使用索引访问数组或列表元素效率较高。
- 流式API:
- 性能:对于大数据集,性能可能不如普通for循环。
- 原理:流式API是基于函数式编程风格,会创建多个中间操作对象(如
filter
和map
操作后的流对象)。这些中间操作在流管道中被延迟执行,直到终端操作(如sum
)触发才会实际执行。虽然这种方式代码简洁,但在大数据集下,创建和管理这些中间对象会带来额外的内存开销和函数调用开销。
优化流式API性能的措施
- 使用并行流:将顺序流转换为并行流,利用多核CPU进行并行计算。
fun main() {
val largeList = (1..1000000).toList()
val sum = largeList.parallelStream()
.filter { it % 2 == 0 }
.map { it * it }
.sum()
println(sum)
}
原理是并行流会将数据分割成多个部分,分别在不同的线程中处理,最后合并结果。但要注意并行流会带来线程管理开销,对于过小的数据集可能反而降低性能。
2. 减少中间操作:尽量合并或减少不必要的中间操作。例如,如果有多个过滤条件,可以合并为一个过滤操作。这样可以减少中间流对象的创建。
3. 使用原始类型流:对于Int
类型,可以使用IntStream
代替Stream<Int>
。IntStream
是专门为int
基本类型设计的流,避免了装箱和拆箱操作,从而提高性能。
fun main() {
val largeList = (1..1000000).toList()
val sum = largeList.stream()
.mapToInt { it }
.filter { it % 2 == 0 }
.map { it * it }
.sum()
println(sum)
}