java - 为什么通过 stream() 调用比使用 if 子句更耗时?
问题描述
为什么是这个方法:
public static int howManyDifferentFields() {
int difcolor = 0;
difcolor++;
if (fields[1] != fields[0]) {
difcolor++;
}
if (fields[2] != fields[1] && fields[2] != fields[0]) {
difcolor++;
}
if (fields[3] != fields[2] && fields[3] != fields[1] && fields[3] != fields[0]) {
difcolor++;
}
if (fields[4] != fields[3] && fields[4] != fields[2] && fields[4] != fields[1] && fields[4] != fields[0]) {
difcolor++;
}
if (fields[5] != fields[4] && fields[5] != fields[3] && fields[5] != fields[2] && fields[5] != fields[1] && fields[5] != fields[0]) {
difcolor++;
}
if (fields[6] != fields[5] && fields[6] != fields[4] && fields[6] != fields[3] && fields[6] != fields[2] && fields[6] != fields[1] && fields[6] != fields[0]) {
difcolor++;
}
if (fields[7] != fields[6] && fields[7] != fields[5] && fields[7] != fields[4] && fields[7] != fields[3] && fields[7] != fields[2] && fields[7] != fields[1] && fields[7] != fields[0]) {
difcolor++;
}
if (fields[8] != fields[7] && fields[8] != fields[6] && fields[8] != fields[5] && fields[8] != fields[4] && fields[8] != fields[3] && fields[8] != fields[2] && fields[8] != fields[1] && fields[8] != fields[0]) {
difcolor++;
}
return difcolor;
}
比这快得多?
public static int howManyDifferentFields2() {
return (int) Arrays.stream(fields).distinct().count();
}
我想使用第二种方式,因为它的代码少得多。但这需要更多的时间!当我使用第二种方法而不是第一种方法时,程序需要大约 8 倍的时间才能完成。我能做些什么?我可以以某种方式重写第一种方法以使其有效但代码更少吗?在我看来,第二种方法看起来好多了......
解决方案
大多数人认为流很快。但他们不是。有很多代码支持它们,而您遇到的正是隐藏的开销。
在一般情况下,一个普通的 for 循环比非并行流(甚至在元素数量不多时并行流)更快。
虽然流可以生成简洁而强大的代码并且有很多好处,但对于小流来说,性能并不是其中之一。
您的逻辑具有 O(n 2 ) 时间复杂度,但如果 n 固定为 8,您就可以了,您可以将其重写为接近等效的循环:
int difcolor = 8;
for (int i = 1; i < fields.length; i++) {
for (int j = 0; j < i; j++) {
if (fields[i] == fields[j]) {
difcolor--;
break;
}
}
}
return difcolor;
从一个完美的分数开始,然后在第一个匹配上递减提高了效率,因为它通过尽早退出内部循环来减少操作的数量,类似于您使用 short circuiting &&
。
你也可以使用 Set,它的时间复杂度为 O(n),而且更紧凑,但只有 8 个元素,它可能会比上面的循环慢:
Set<Integer> set = new HashSet<>(); // assuming fields is a int[]
int difcolor = 0;
for (int field : fields) {
if (set.add(field)) {
difcolor++;
}
}
这与您的流版本类似,但没有流开销。
如果对元素进行了排序,则可以一次通过仅比较邻居来完成。
推荐阅读
- mysql - 如何仅从指定字符的范围中进行选择
- javascript - 如何在一个 div 中居中多个 HTML 项目,包括多个画布?
- c - 如何克隆文件描述符?(不只是复制它)
- c - 我可以将 size_t 视为 void 指针吗?
- javascript - Frappe 框架自动计算年龄和全名
- r - 按 id 为多个日期之间的每个日期创建行
- c++ - C++ 类引用成员变量的打字稿等价物
- csv - 使用 D3 加载 CSV 数据时,如何将列的数据类型从字符串更改为浮点/整数?
- javascript - 节点:如何过滤嵌套在多个数组中的 JSON 值?
- java - Repaint() 请求合并为一个是神话吗?