《java 8 实战》读书笔记 -第四章 引入流

发布时间:2019-11-19 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了《java 8 实战》读书笔记 -第四章 引入流脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

第四章 引入流

一、什么是流

流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。就现在来说,你可以把它们看成遍历数据集的高级迭代器。此外,流还可以透明地并行处理,你无需写任何多线程代码。

下面两段代码都是用来返回低热量的菜肴名称的,并按照卡路里排序,一个是用Java 7写的,另一个是用Java 8的流写的。

之前(Java 7):

List<Dish> lowCaloricDishes = new ArrayList<>();  for(Dish d: menu){   if(d.getCalories() < 400){   lowCaloricDishes.add(d);   }  }  Collections.sort(lowCaloricDishes, new Comparator<Dish>() {  public int compare(Dish d1, Dish d2){   return Integer.compare(d1.getCalories(), d2.getCalories());   }  });  List<String> lowCaloricDishesName = new ArrayList<>();  for(Dish d: lowCaloricDishes){   lowCaloricDishesName.add(d.getName());  } 

在这段代码中,你用了一个“垃圾变量”lowCaloricDishes。它唯一的作用就是作为一次
性的中间容器。在Java 8中,实现的细节被放在它本该归属的库里了。

之后(Java 8):

import static java.util.Comparator.comparing;  import static java.util.stream.Collectors.toList;  List<String> lowCaloricDishesName =   menu.stream()   .filter(d -> d.getCalories() < 400)   .sorted(comparing(Dish::getCalories))  .map(Dish::getName)   .collect(toList()); 

为了利用多核架构并行执行这段代码,你只需要把stream()换成parallelStream()

List<String> lowCaloricDishesName =   menu.parallelStream()   .filter(d -> d.getCalories() < 400)   .sorted(comparing(Dishes::getCalories))   .map(Dish::getName)   .collect(toList()); 

按照Map里面的类别对菜肴进行分组。

Map<Dish.Type, List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType)); 
其他库:Guava、apache和lambdaj
为了给Java程序员提供更好的库操作集合,前人已经做过了很多尝试。比如,Guava就是谷歌创建的一个很流行的库。它提供了multimaps和multisets等额外的容器类。Apache Commons Collections库也提供了类似的功能。Mario Fusco编写的lambdaj受到函数式编程的启发,也提供了很多声明性操作集合的工具。

流到底是什么呢?简短的定义就是“从支持数据处理操作的生成的元素序列”。

  • 元素序列——就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。因为集合是数据结构,所以它的主要目的是以特定的时间/空间复杂度存储和访问元素(如ArrayList 与 LinkedList)。但流的目的在于表达计算,比如你前面见到的filter、sorted和map。集合讲的是数据,流讲的是计算。我们会在后面几节中详细解释这个思想。
  • ——流会使用一个提供数据的源,如集合、数组或输入/输出资源。 请注意,从有序集合生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致。
  • 数据处理操作——流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等。流操作可以顺序执行,也可并行执行。

eg: 选出3条卡路里高于300的菜肴的菜肴的名字

import static java.util.stream.Collectors.toList;  List<String> threeHighCaloricDishNames =   menu.stream()   .filter(d -> d.getCalories() > 300)  .map(Dish::getName)  .limit(3)         //筛选(filter)、提取(map)或截断(limit)  .collect(toList());  System.out.println(threeHighCaloricDishNames);  //在调用collect之前,没有任何结果产生,实际上根本就没有从menu里选择元素

二、流与集合

《java 8 实战》读书笔记 -第四章 引入流

  • 和迭代器类似,流只能遍历一次。遍历完之后,我们就说这个流已经被消费掉了。
  • 使用Collection接口需要用户去做迭代(比如用for-each),这称为外部迭代。 相反,Streams库使用内部迭代——它帮你把迭代做了,还把得到的流值存在了某个地方,你只要给出一个函数说要干什么就可以了。

《java 8 实战》读书笔记 -第四章 引入流

三、流操作

java.util.stream.Stream中的Stream接口定义了许多操作。它们可以分为两大类:

  • 中间操作
    可以连接起来的流操作称为中间操作,诸如filter或sorted等

《java 8 实战》读书笔记 -第四章 引入流

  • 终端操作
    关闭流的操作称为终端操作,其结果是任何不是流的值,比如List、Integer,甚至void

《java 8 实战》读书笔记 -第四章 引入流

eg:(注意循环合并)

    List<String> names =       menu.stream()       .filter(d -> {       System.out.println("filtering" + d.getName());       return d.getCalories() > 300;       })       .map(d -> {       System.out.println("mapping" + d.getName());       return d.getName();       })       .limit(3)       .collect(toList());      System.out.println(names); 

此代码执行时将打印:

    filtering pork      mapping pork      filtering beef      mapping beef      filtering chicken      mapping chicken      [pork, beef, chicken] 

尽管filter和map是两个独立的操作,但它们合并到同一次遍历中了(我们把这种技叫作循环合并)。

四、使用流

流的使用一般包括三件事:

  • 一个数据源(如集合)来执行一个查询;
  • 一个中间操作链,形成一条流的流水线;
  • 一个终端操作,执行流水线,并能生成结果。

脚本宝典总结

以上是脚本宝典为你收集整理的《java 8 实战》读书笔记 -第四章 引入流全部内容,希望文章能够帮你解决《java 8 实战》读书笔记 -第四章 引入流所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。