Stream流粗解

Stream流粗解

  • 声明性——更简洁,更易读
  • 可复合——更灵活
  • 可并行——性能更好

案例传送门:Stream流使用案例

  • 通过对交易的各项业务查询熟悉流的使用
Map<Dish.Type, List<Dish>> dishesByType = menu.stream().collection(groupingBy(Dish::getType));

流简介

简短定义:从支持数据处理操作的源生成的元素序列。

  • 元素序列:类似于集合,流也提供了一个接口,可以访问特定元素类型的一组有序值。与集合不同,集合的主要目的是以特定的时间和空间复杂度存储和访问元素(如ArrayList和LinkedList)。流的主要目的在于表达计算。集合讲的是数据,流讲的是计算。
  • 源: 流会使用一个提供数据的源,如集合、数组或输入/输出资源。从有序集合生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致。
  • 数据处理操作:流的数据处理功能类似于数据库的操作,以及函数式编程语言的常用操作,如filter、map、reduce、find、match、sort等。流操作可以顺序执行,也可以并行执行
  • 流水线:很多流操作本身会返回一个流,所以多个操作就可以链起来,形成一个流水线。
  • 内部迭代:与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的。

示例如下,结果为:[pork, beef, chicken]

List<String> threeHighCalorDishNames 
					= menu.stream() //源为menu,是一个列表,在Stream流案例中的Dish类可以看到定义
						  /**
						   * Stream<T> filter(Predicate<? super T> predicate),steam流可用的一个操作,接收一个Predicate接口对象
						   * boolean test(T t),Predicate函数式接口定义的抽象方法,签名为 T -> booean
						   * 经过filter操作(筛选卡路里高于300的)得到新流
						   */
						  .filter(d -> d.getCalories() > 300) 
						  /**
						   * <R> Stream<R> map(Function<? super T, ? extends R> mapper),steam流可用的一个操作,接收一个Function接口对象
						   * R apply(T t),Function函数式接口定义的抽象方法,签名为 T -> R
						   * 经过map操作(映射为菜名)得到新流
						   */
						  .map(Dish::getName)
						  /**
						   * Stream<T> limit(long maxSize),steam流可用的一个操作,接收一个long型整数
						   * 经过limit操作(只选择前三个)得到新流
						   */
						  .limit(3)
						  /**
						   * 返回一个list
						   */
						  .collect(Collectors.toList());

System.out.println(threeHighCalorDishNames);

流与集合

集合:是一个内存中的数据结构,它包含数据结构中目前所有的值——集合中的每个元素都得先算出来才能添加到集合中。

  • 可比喻为DVD,视频已经完全存储到了DVD中。

流:是在概念上固定的数据结构(不能添加或删除元素),其元素时按需计算的,就像一个延迟创建的集合:在按需的一步步操作完成后才创建集合。

  • 可比喻为在线流媒体,缓存一部分看一部分,按需操作。
  • 也可比喻为用浏览器进行互联网搜索,假设搜索到多条匹配项,而可以得到一个流仅展示10个,点击下一页可展示接下来的10个,每次请求都是10个。

只能遍历一次

和迭代器类似,流只能遍历一次。遍历完成后,就称这个流已经被消费掉了。如下代码:

List<String> title = Arrays.asList("Java8", "Lambda", "Steam");
Stream<String> s = title.stream();
/**
 * Stream: void forEach(Consumer<? super T> action);
 * Consumer: void accept(T t);
 */
s.forEach(System.out::println);
s.forEach(System.out::println);

结果如图:只会遍历一次,第二次遍历就抛出了异常,说明流已经被消费掉了。
在这里插入图片描述

外部迭代与内部迭代

使用Collection接口需要用户去做迭代(比如for-each),这称为外部迭代。相反,Streams库使用内部迭代——它帮你把迭代做了,还把得到的流存在了某个地方,只需要给出函数说要干什么就可以了。如下分别是集合和流的代码,说明了这种区别。

  • 集合:用for-each循环外部迭代
List<String> names = new ArrayList<>();
for (Dish d : menu) { // 显示顺序迭代菜单列表
	names.add(d.getName()); // 提取名称并将其添加到累加器
}
  • 集合:用背后的迭代器做外部迭代
List<String> names = new ArrayList<>();
Iterator<Dish> iterator = menu.iterator();
while (iterator.hasNext()) {
    Dish d = iterator.next();
    names.add(d.getName());
}
  • 流:内部迭代
List<String> names = menu.stream()
                .map(Dish::getName) // 传递行为,用getName方法参数化map,提取菜名
                .collect(Collectors.toList());
集合:外部迭代,必须一个一个处理

你:“索菲亚,我们把玩具收起来吧。地上还有玩具吗?”
索菲亚:“有,球。”
你:“好,把球放进盒子里。还有吗?”
索菲亚:“有,娃娃。”
你:“好,把娃娃放进盒子里。还有吗?”

索菲亚:“没了,没有了。”
你:“好,我们收完了。”

流:内部迭代,可以很好的并行处理,索菲亚可以一手球一手娃娃

你:“索菲亚,把地上的玩具都收起来。”
索菲亚:“好的。”

流操作

  • 中间操作:从源获取流开始,可以进行多个类似于filter、sorted方法等中间操作,这些操作的结果还是流。
  • 终端操作:经过一系列的中间操作后,最后使用一个终端方法,从流的流水线生成结果,该结果为其他非流的值,如List、Integer等,甚至可以是void。
  • 使用流:
    • 一个数据源(如集合)来执行一个查询;
    • 一个中间操作链,形成一条流的流水线;
    • 一个终端操作,执行流水线,并能生成结果。

使用流,具体案例点此

筛选和切片
filter

Stream接口支持filter方法,该操作接受一个谓词作为参数,并返回一个包含符合谓词的元素的流。

List<Dish> vegetarianMenu = menu.stream()
								.filter(Dish::isVegetarian)
								.collect(toList());
distinct

Stream接口支持distinct方法,该操作会返回一个元素各异的流。

List<Integer> numbers = Arrays.asList(1,2,1,3,3,2,4);
numbers.stream()
	   .filter(i -> i % 2 == 0)
	   .distinct()
	   .forEach(System.out::println);
limit

Stream接口支持limit(n)方法,该方法返回一个不超过给定长度的流。

List<Dish> dishes = menu.stream()
						.filter(d -> d.getCalories() > 300)
						.limit(3)
						.collect(toList());
skip

Stream接口支持skip(n)方法,与limit方法互补,返回一个丢掉前n元素的流。

List<Dish> dishes = menu.stream()
						.filter(d -> d.getCalories() > 300)	
						.skip(2)
						.collect(toList());	
映射

Stream接口支持map和flatMap方法,接收一个函数作为参数,这个函数会作用到流的每个元素,并将其映射成一个新的元素。

map
flatMap
查找和匹配
anyMatch
allMatch
findAny
findFirst
规约
reduce
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值