写给大忙人的javaSE8(3)-流操作使用总结

学而不思则罔,思而不学则殆。

温馨提示:这一接基本上是前面一节中的一些总结和使用注意事项,可以酌情跳过。

前面一节中,说明了常用的Stream操作的部分常用API,本节中,将这些api用一个例子整合起来使用。
1.api整合操作
先假设提出一个需求:
例如,我们现在有6个魔法师,他们来自不同的种族,不同的地区,不同的性别,甚至擅长各种各样的技能魔法。
任务:在魔法师队伍中找到人类魔法师,并计算出他们来自哪些地区。

按照以往的方式,在for循环中,根据race获取到魔法师是否为人类“homan”,并且并且将这些魔法师的来源地whence输出到一个Set,使用Set是因为,有可能两个或以上的魔法师来自同一个地区,但是我们这里的需求是,同一个地区不能出现两次。

Set sets = new HashSet<>();
for(int i = 0; i < magicians.size();i++) {
  if ("human".equals(magicians.get(i).getRace())) {
    sets.add(magicians.get(i).getWhence())
  } 
}

可以这么理解。
1.过滤出魔法师种族为人类的数据
2.找到魔法师的来源地
3.将魔法师来源放入 sets集合。

接下来。我们将上面这段for循环改成 Stream方式,来练习一下使用Stream的API是如何完成上面这个任务的。

//找出魔法师中 属于人类的魔法师
Set whences = magicians.stream()
        .filter(mg -> mg.getRace().equals("homan"))
        .map(mg -> mg.getWhence())
        .collect(Collectors.toSet());

实际上,Stream操作更能直观的表达出我们的意图,首先,filter找出race为人类“homan”的魔法师,使用map操作获取魔法师的来源地 whence,然后将这个Stream使用提早取值的方法 collect转换成一个 Set。现在,是不是觉得Stream或许可以在你的代码中替代哪些复杂的操作了?

2.重构以往的旧代码。

以往复杂的代码,在采用流的方式重构,重构过程中,每一步都能确保通过单元测试,以保证代码能够正常工作。

刚接触Stream时,可以先从for循环入手,
1.首先使用Stream的forEach方法替代掉旧代码中的for循环。
2.使用filter方式进行一些逻辑判定。
3.使用map,flatmap等方式替换一些业务逻辑
4.使用及早求值方法得到最终结果。

3.多次调用流的操作。

在前面的诸多例子中,我们大多时候都是用链式的方法调用Stream的api进行求值。但是你也可以每一步都强制采用及早求值法,不过不建议这么做。
例如我们找魔法师的例子中

//使用链式方法
Set whences = magicians.stream()
        .filter(mg -> mg.getRace().equals("homan"))
        .map(mg -> mg.getWhence())
        .collect(Collectors.toSet());

//每一步强制对函数求值,而不是将所有方法调用连接一起
//1.先过滤出种族为人类的魔法师
List magicianList = magicians.stream()
        .filter(mg -> mg.getRace()
        .equals("homan")).collect(Collectors.toList());

//2.将魔法师的来源地放入map
Set whencesSet = magicianList.stream()
        .map(mg -> mg.getWhence()).collect(Collectors.toSet());

毫无疑问,这种方也是可以达到目的的,不过该方法有以下几点区别。
1.代码可读性差,样板代码过多,隐藏了真正的业务逻辑。
2.效率差,每一步都要对流及早求值,生成新的集合。
3.代码充斥着一堆垃圾变量,他们只是用来保存中间结果,除此之外,毫无用处。
4.难于自动并行化处理。

不过,刚开始接触流的方式时,可能会不知不觉中写出类似的代码,若有发现时应及时纠正,避免习惯的养成。

4.正确使用Lambda表达式。
使用lambda表达式时,要尽量避免产生副作用,这一点非常重要。没有副作用的函数不会改变程序或外接状态。在lambda表达式中向控制台输出信息或者给变量{不是lambda表达式内部的变量}赋值也是一种副作用,而且更难察觉, 无论何时,将lambda表达式传给Stream上的高阶函数,都应该尽量避免副作用。唯一例外的事forEach方法,因为它是一个终结方法。

保持最好的心态,来迎接趣味人生

你可能感兴趣的:(写给大忙人的javaSE8(3)-流操作使用总结)