继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

链式编程

都要好好的ming
关注TA
已关注
手记 6
粉丝 0
获赞 0

强大的链式编程 Stream API :Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)

Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。

所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。


 

Lambda 表达式 本质是匿名方法

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Lambda表达式只能出现在目标类型为函数式接口的上下文中

表达式:   (参数列表)   →   {  语句块  };

比如:声明一个方法  

public int sum(int i,int j){
    return i+j;
}

转换成lambda表达式后可以写成

(int i,int j)→ i+j;

参数的类型也是可以省略的,Java编译器可以过根据上下文感知到参数类型:

(i,j)→  i+j;  或者  (i,j)→  { retrun i+j;}

可见:Lambda 表达式有三部分组成:参数列表 ,箭头(→) ,以及 语句块

接下来由浅入深通过四种简化方式简化一下:

 展开原码

Lambda表达式方法引用简化

java中的双冒号操作符   ::

定义

双冒号运算操作符是类方法的句柄,lambda表达式的一种简写

范式:   类名 ::  方法名

注意:

  1. 方法后面并没有()

  2. 懒加载方法是否调用要看调用方使用情况

有时候已经有其他方法实现了函数接口的方法了,那么我们可以直接引用此方法代替函数接口的实现方法,常见的引用形式有以下语法:

调用方法简化

静态方法引用:ClassName   ::   methodName
实例方法引用:object   ::            methodName
超类方法引用:super   ::            methodName
构造方法简化

构造方法引用:ClassName::new 

数组构造引用:TypeName[]::new

什么是流 Stream API

Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。

原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;

高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。

流的构成:

当我们使用一个流的时候,通常包括三个基本步骤:

      获取一个数据源(source) →  数据转换 →  执行操作获取想要的结果。

  1. 创建Stream;

  2. 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(**可以有多次转换**);

  3. 对Stream进行聚合(Reduce)操作,获取想要的结果;

每次转换原有的Stream对象不改变,返回一个新的Stream 对象(可以有多次转换),这样就允许对其操作可以像链条一样排列,变成一个通道。

第一步:获取数据源    创建stream

  • Collection接口的stream()或parallelStream()方法

  • 静态的Stream.of()、Stream.empty()方法

  • Arrays.stream(array, from, to)

  • 静态的Stream.generate()方法生成无限流,接受一个不包含引元的函数

  • 静态的Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数

  • Pattern接口的splitAsStream(input)方法

  • 静态的Files.lines(path)、Files.lines(path, charSet)方法

  • 静态的Stream.concat()方法将两个流连接起来

  • 。。。。

第二步: 中间操作(中间操作不会执行任何操作,直到执行了终止操作时,才会一次性执行所有中间操作 侧面说明了流是惰性的 :转换Stream  比如    筛选和过滤     映射

筛选和过滤

  • Stream<T> filter(Predicate<? super T> predicate) 

filter() : 接受一个lambda表达式 (自定以过滤条件 ,返回 boolean),从流中排除某些元素。

  • Stream<T> limit(long maxSize)

limit(maxSize):截取前maxSize元素的流。但已经满足返回添加,可发生短路,不再继续执行流

  • Stream<T> skip(long n)

skip(N): 跳过元素,返回一个扔掉了前个元素的流,如流中的元素不满足N 个,则返回一个空流。 与limit() 互补

  • Stream<T> distinct() 

distinct(): 筛选去重,通过流所生成元素的  hashCode() 和equals()   去除重复的元素。 需要重写类的 hashCode() 和equals() 方法

映射:

  • <R> Stream<R> map(Function<? super T, ? extends R> mapper);

map(): 接受一个函数 Function   作为参数,该函数会作用到每个元素上,并将其映射称为一个新的元素。然后返回一个Stream<R> ( 接收Lambda  ,将元素转换成其他形式或提取信息)

  • <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

flatmap() :   接受一个函数 Function   作为参数,将流Stream中的每一个值都换成另一个流Stream,然后将所有的流  合并成一个流 ,然后返回一个Stream<R> 

比较map() 和 flatmap方法可以类比  集合中的 add() 和 addAll() 方法。

排序:

  • Stream<T> sorted()
    sorted():  自然排序 ,根据Comparable 进行排序。

  • Stream<T> sorted(Comparator<? super T> comparator)  
    sorted(Comparator): 根据Comparator  排序,可自定义排序规则

第三步:终结操作

查找元素:

boolean allMatch(Predicate<? super T> predicate)

allMatch(Predicate):   流中所有的元素都能够满足 定义的断言规则  就会返回true ,若存在一个元素不满足断言规则,则返回false。

boolean anyMatch(Predicate<? super T> predicate)

anyMatch(Predicate): 流中任何一个元素能够 满足定义的断言规则 就会返回true ,若所有元素都不满足断言规则,则返回false。

boolean noneMatch(Predicate<? super T> predicate) 

noneMatch(Predicate): 流中所有元素都无法匹配 定义的断言规则 就会返回true,  若存在一个元素满足断言规则,则返回false。

Optional<T> findAny()

findFirst(): 返回第一个元素

Optional<T> findAny()

findAny() :返回任意元素,随机返回

组函数:

max(Comparator):返回指定比较规则 的最大值 对应的元素

min(Comparator):返回 指定比较规则 的最小值 对应的元素

count() :返回流中元素的个数


归约

T reduce(T identity, BinaryOperator<T> accumulator)     

reduce(a, fun) a为起始值,作为累积器的起点,reduce方法可以将该流中元素反复结合起来,得到一个新值 类型为T ,该值不可能为空,至少也是  起始值a

Optional<T> reduce(BinaryOperator<T> accumulator)   (可能为空的值需要封装进Optional 中

reduce(fun) 从流中计算某个值,接受一个二元函数作为累积器,从前两个元素开始持续应用它,累积器的中间结果作为第一个参数,流元素作为第二个参数。

可结合map形成 map-reduce 模式

收集

<R, A> R collect(Collector<? super T, A, R> collector)

collect(Collector) :将流转换为其他形式,接受一个收集器Collector,用于给stream中的元素做汇总方法

Collector接口中方法的实现决定了如何对流执行收集操作(如:收集到List  set  map),但是Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器的实例,具体方法与实例如下表:


    • Collectors.toList()    收集到list集合中

    • Collectors.toSet()    收集到set 集合中

    • Collectors.toCollection 收集到指定类型的集合中去, 比如收集到HashSet中   HashSet<String> hs=    ObjectStream.collect(Collectors.toCollection(HashSet::new ))

    • Collectors.toMap(fun1, fun2)   /  toConcurrentMap(fun1, fun2)                            两个fun用来产生键和值,若值为元素本身,则fun2为Function.identity()

    • Collectors.toMap(fun1, fun2, fun3) /    toConcurrentMap(fun1, fun2, fun3)       fun3用于解决键冲突,例如(oldValue, newValue) -> oldValue,有冲突时保

    • 还有 计算 平均值 averagingInt/averagingLong/avergingDouble 最大值maxBy  最小值minBy  总和summingInt/sunmmingLong/summingDouble   分组groupingBy   分区 partitioningBy   组函数合辑 summarizingInt

      等等方法

<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) 

collect(fun1, fun2, fun3)  :fun1转换流元素;fun2为累积器,将fun1的转换结果累积起来;fun3为组合器,将并行处理过程中累积器的各个结果组合起来 

 

forEach(fun)   遍历流中的元素
forEachOrdered(fun)  指定遍历的顺序,遍历流中的元素。 可以应用在并行流上以保持元素顺序
toArray()
toArray(T[] :: new)  返回正确的元素类型



 

 


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP