题目:设有一个字符串集合,其中有 N 条数据,请过滤出 1000-2000 之间的数据。
Stream VS For - Round One
假如 N = 10000,使用for循环和stream循序流/并行流分别进行对比:
public static void main(String[] args) {
// 初始化1万条数据
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(String.valueOf(i));
}
// 开启计时器
StopWatch sw = new StopWatch();
sw.start("stream-1");
// 利用skip和limit进行过滤
list.stream()
.skip(1000)
.limit(1001)
.collect(Collectors.toList());
sw.stop();
sw.start("stream-2");
// 将所有条件写到一个filter中进行过滤
List<String> collect = list.stream()
.filter(str -> Integer.parseInt(str) >= 1000 && Integer.parseInt(str) <= 2000)
.collect(Collectors.toList());
sw.stop();
sw.start("stream-3");
// 将所有条件分开写到多个filter中进行过滤
List<String> collect1 = list.stream()
.filter(str -> Integer.parseInt(str) >= 1000)
.filter(str -> Integer.parseInt(str) <= 2000)
.collect(Collectors.toList());
sw.stop();
sw.start("for-1");
// 使用 for循环+if 进行过滤
ArrayList<String> strings = new ArrayList<>();
for (String s : list) {
if (Integer.parseInt(s) >= 1000 && Integer.parseInt(s) <= 2000) {
strings.add(s);
}
}
sw.stop();
System.out.println(sw.prettyPrint());
}
PK 结果(Stream 顺序流):
PK 结果(Stream 并行流,将stream()方法改为 parallelStream()):
第一局,For 循环完胜!并且并行流相比顺序流的总耗时要慢。
Stream VS For - Round Two
假如 N = 100000,使用for循环和stream进行对比:
public static void main(String[] args) {
// 初始化10万条数据
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(String.valueOf(i));
}
// 开启计时器
StopWatch sw = new StopWatch();
sw.start("stream-1");
// 利用skip和limit进行过滤
list.stream()
.skip(1000)
.limit(1001)
.collect(Collectors.toList());
sw.stop();
sw.start("stream-2");
// 将所有条件写到一个filter中进行过滤
List<String> collect = list.stream()
.filter(str -> Integer.parseInt(str) >= 1000 && Integer.parseInt(str) <= 2000)
.collect(Collectors.toList());
sw.stop();
sw.start("stream-3");
// 将所有条件分开写到多个filter中进行过滤
List<String> collect1 = list.stream()
.filter(str -> Integer.parseInt(str) >= 1000)
.filter(str -> Integer.parseInt(str) <= 2000)
.collect(Collectors.toList());
sw.stop();
sw.start("for-1");
// 使用 for循环+if 进行过滤
ArrayList<String> strings = new ArrayList<>();
for (String s : list) {
if (Integer.parseInt(s) >= 1000 && Integer.parseInt(s) <= 2000) {
strings.add(s);
}
}
sw.stop();
System.out.println(sw.prettyPrint());
}
PK 结果(Stream 顺序流):
PK 结果(Stream 并行流,将stream()方法改为 parallelStream()):
第二局,Stream 的skip和limit函数取得胜利!但是在并行流下和for循环旗鼓相当,并且总耗时比顺序流要慢上不少。
Stream VS For - Round Three
假如 N = 1000000,使用for循环和stream进行对比:
public static void main(String[] args) {
// 初始化100万条数据
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(String.valueOf(i));
}
// 开启计时器
StopWatch sw = new StopWatch();
sw.start("stream-1");
// 利用skip和limit进行过滤
list.stream()
.skip(1000)
.limit(1001)
.collect(Collectors.toList());
sw.stop();
sw.start("stream-2");
// 将所有条件写到一个filter中进行过滤
List<String> collect = list.stream()
.filter(str -> Integer.parseInt(str) >= 1000 && Integer.parseInt(str) <= 2000)
.collect(Collectors.toList());
sw.stop();
sw.start("stream-3");
// 将所有条件分开写到多个filter中进行过滤
List<String> collect1 = list.stream()
.filter(str -> Integer.parseInt(str) >= 1000)
.filter(str -> Integer.parseInt(str) <= 2000)
.collect(Collectors.toList());
sw.stop();
sw.start("for-1");
// 使用 for循环+if 进行过滤
ArrayList<String> strings = new ArrayList<>();
for (String s : list) {
if (Integer.parseInt(s) >= 1000 && Integer.parseInt(s) <= 2000) {
strings.add(s);
}
}
sw.stop();
System.out.println(sw.prettyPrint());
}
PK 结果(Stream 顺序流):
PK 结果(Stream 并行流,将stream()方法改为 parallelStream()):
第三局,Stream 的skip和limit 取得胜利!并且在使用并行流的情况下效率得到了显著提升。
总结
注意:下面总结都有一个前提条件,以上 for 循环和 Stream 流中都只是对数据进行了过滤和重新收集,并没有其他操作,比如 IO 或者计算。
- 1 万数据以内,使用 for 循环的效率明显要比 Stream 流高一些,并且这个数据量不建议使用并行流。
- 10 万数据左右,使用 Stream 流的效率可能比 for 循环要高一些,取决于使用 Stream 中什么函数,比如专门为求范围提供的 skip、limit 进行范围筛选的效率就要比 filter 的效率更好一些,而将多个条件分开放入 filter 要比将条件一次性写在一个 filter 中效率更好一些。并且这个数据量也不建议使用并行流。
- 100 万数据左右,使用 Stream 流的效率更好一些,特别是在使用并行流的情况下。
个人理解: 在对于需要处理比较复杂筛选或者计算的场景下,建议使用 Stream 流,它可以提高代码的可读性使代码变得非常的简洁,并且功能非常的丰富可以适应很多场景。在对于数据量小并且筛选条件比较简单的场景下可以使用for循环,毕竟可以比Stream流快上好几毫秒的时间。