时间:2021-05-19
前言
前段时间公司书架多了一本《Java8 实战》,毕竟久闻lambda的大名,于是借来一阅。这一看,简直是惊为天人啊,lambda,stream,java8里简直是满脑子骚操作,看我的一愣一愣的。我甚至是第一次感觉到了什么叫优雅。
本文主要介绍java8中的流处理,看看java8是怎么愉快的玩耍集合的,让我们来一起感受java8的魅力吧!
我就随便举个例子,看看Stream有多优雅。
// 对苹果按颜色汇总并绩数量Map<String, Long> appleCount = apples.stream() .collect(groupingBy(Apple::getColor, counting()));// 过滤掉颜色为黑色的苹果,并汇总好苹果的总金额Double sum = apples.stream() .filter(i->"black".equals(i.getColor())) .collect(toList);一、lambda表达式
虽然本文重点是stream,但是stream中需要传递lambda表达式,所以简单介绍一下lambda表达式。lambda表达式其实就是匿名函数(anonymous function),是指一类无需定义标识符的函数或子程序。
java中匿名函数的表现形式,只留下入参和方法体中的内容
// 普通函数public void run(String s){ System.out.print(s+"哈哈");}// 我不要名字啦!!!(s)->System.out.print(s+"哈哈")诶,过去我们都用对象调方法的,你弄这个没名的东西啥时候用啊?
java中我们通过函数式接口来使用这种匿名函数。
函数式接口
1.java中只包含一个未实现方法的接口。其中可以有与Object中同名的方法和默认方法(java8中接口方法可以有默认实现)。
2.java中函数式接口使用@FunctionalInterface进行注解。Runnable、Comparator都是函数式接口。
3.java.util.function包下为我们提供很多常用的函数式接口,例如Function等。
用法举例:
// 实现Runnable中的run方法,替代匿名内部类。Runnable r = ()->System.out.print("哈哈");// 作为参数传递。new Thread(()-> System.out.println("haha")).start();ArrayList<Apple> list = new ArrayList<>();list.forEach(i-> System.out.println(i.getWeight()));// 简化策略模式public static List<Apple> filterApples(List<Apple> inventory,ApplePredicate p){ List<Apple> apples = new ArrayList<>(); for(Apple apple : inventory){ if(p.test(apple)){ apples.add(apple); } } return apples;}public class BigApple implement ApplePredicate{ @Override public boolean test(Apple a){ if(a.getWeight>10){ return a } }}// 这是个简单的策略模式,根据用户的需要,创建不同的接口ApplePredicate实现类,调用时传入不同的实现类就可以,但问题是如果需求过多,创建的实现类也会很多,过于臃肿不方便管理。xx.filterApple(inventory,new BigApple);// 使用lambda表达式,不在需要创建BigApple类xx.filterApple(inventory,i->(i.getWeight>10));使用lambda表达式可以简化大量的模板代码,并且可以向方法直接传递代码。
总之
方法出参入参来自函数式接口
好了,不多啰嗦了,如果感兴趣推荐下面的文章或《Java8实战》的前三章。
1.Lambda表达式有何用处?如何使用?
2.java8实战
二、Stream
流是什么?
Java API的新成员,它允许你使用声明式方式处理数据集合(类似sql,通过查询语句表达,而不是临时编写一个实现)。
如果有人说lambda表达式不易于理解,那还勉强可以接受(其实过于复杂的lambda缺失不好阅读,但通常lambda不会做太复杂的实现),但流真的非常的易懂易用。这个语法糖真的是甜死了。
注意事项:
1.流只能使用一次,遍历结束就代表这个流被消耗掉了
2.流对集合的操作属于内部迭代,是流帮助我们操作,而不是外部迭代
3.流操作包含:数据源,中间操作链,终端操作三个部分。
基础流操作
Apple::getPrince<=>i -> i.getPrince()可以看做是仅涉及单一方法的语法糖,效果与lambda表达式相同,但可读性更好。
同理
下面列表为常见操作
中间
操作 类型 作用 函数描述 函数 filter 中间 过滤 T -> boolean Predicate sorted 中间 排序 (T,T)->int Comparator map 中间 映射 T->R Function<T,R> limit 中间 截断 distinct 中间 去重,根据equals方法 skip 中间 跳过前n个元素
终端
操作 类型 作用 forEach 终端 消费流中的每个元素,使用lambda进行操作 count 终端 返回元素个数,long collect 终端 将流归约成一个集合,如List,Map甚至是Integer
筛选与切片
归约操作reduce
List<Integer> integers = Arrays.asList(12, 3, 45, 3, 2,-1);// 有初始值的叠加操作Integer reduce = integers.stream().reduce(3, (i, j) -> i + j);Integer reduce2 = integers.stream().reduce(5, (x, y) -> x < y ? x : y);// 无初始值的叠加操作Optional<Integer> reduce1 = integers.stream().reduce((i, j) -> i + j);// 无初始值的最大值Optional<Integer> reduce4 = integers.stream().reduce(Integer::min);// 无初始值的最大值Optional<Integer> reduce5 = integers.stream().reduce(Integer::max);// 求和Optional<Integer> reduce6 = integers.stream().reduce(Integer::sum);reduce做的事情是取两个数进行操作,结果返回取下一个数操作,以次类推。
Optional是java8引入的新类,避免造成空指针异常,在集合为空时,结果会包在Optional中,可以用isPresent()方法来判断是否为空值。
无初始值的情况下可能为空,故返回Optional
中间
操作 类型 作用 函数描述 函数 flatmap 中间 使通过的流返回内容 T -> boolean Predicate
终端
操作 类型 作用 anyMatch 终端 返回boolean,判断是否有符合条件内容 noneMatch 终端 返回boolean,判断是否无符合条件内容 allMatch 终端 返回boolean,判断是全为符合条件内容 findAny 终端 Optional,随机找一个元素返回 findFirst 终端 Optional,返回第一个元素 reduce 终端 Optional(T,T)->T 归约操作
数值流
包装类型的各种操作都会有拆箱操作和装箱操作,严重影响性能。所以Java8为我们提供了原始数值流。
// 数值流求平均值OptionalDouble average = apples.stream() .mapToDouble(Apple::getPrice) .average();// 数值流求和OptionalDouble average = apples.stream() .mapToDouble(Apple::getPrice) .sum();// 数值流求最大值,没有则返回2double v = apples.stream() .mapToDouble(Apple::getPrice) .max().orElse(2);// 生成随机数IntStream s = IntStream.rangeClosed(1,100);下面列表为常见数值流操作操作
中间
操作 类型 作用 rangeClosed(1,100) 中间 生成随机数(1,100] range(1,100) 中间 生成随机数(1,100) boxed() 中间 包装成一般流 mapToObj 中间 返回为对象流 mapToInt 中间 映射为数值流
终端,终端操作与List一般流类似
构建流
值创建
Stream<String> s = Stream.of("java","python");数组创建
int[] i = {2,3,4,5};Stream<int> = Arrays.stream(i);由文件生成,NIO API已经更新,以便利用Stream API
Stream<String> s = Files.lines(Paths.get("data.txt"),Charset.defaultCharset());由函数创建流:无限流
// 迭代Stream.iterate(0,n->n+2) .limit(10) .forEach(System.out::println);// 生成,需要传递实现Supplier<T>类型的Lambda提供的新值Stream.generate(Math.random) .limit(5) .forEach(System.out::println);三、总结
至此,本文讲述了常见的流操作,目前排序、筛选、求和、归约等大多数操作我们都能实现了。与过去相比,操作集合变的简单多了,代码也变的更加简练明了。
目前Vert.x,Spring新出的WebFlux都通过lambda表达式来简化代码,不久的将来,非阻塞式框架的大行其道时,lambda表达式必将变的更加重要!
至于开篇见到的分组!!!下篇文章见~
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
一:知识付费现在都9102年了,知识付费一直更新迭代,还是有着巨大的潜力,比如喜马拉雅,得到,知乎会员等等,都捉住了知识付费的风口,赚得盆满钵满。你可能会说,这
前言Java8中提供了Stream对集合操作作出了极大的简化,学习了Stream之后,我们以后不用使用for循环就能对集合作出很好的操作。本文将给大家详细介绍关
这个还用问吗?看他是外销哪里的了,要是外销中国的,你是中国人你就适合你用。内销的吗?依次推测。因品质或者规格原因,出口货物自出口放行之日起1年内原状退货复运进境
你要沒有提升过题目?你常常优化标题?都9102了!优化关键词的关键你还不知道?那样查验题目再做优化关键词不危害权重值还能提高访问者! 许多店家提到题目就头
1.增强for概述增强for循环,也叫Foreach循环,用于数组和容器(集合类)的遍历。使用foreach循环遍历数组和集合元素时,无需获得数组和集合长度,无