函数式编程、函数式接口、兰姆达表达式、方法引用、stream

函数式编程

参考文章:函数式编程_春风一慕的博客-CSDN博客_函数式编程
特点:
1. 纯函数:函数的执行没有副作用;返回值仅依赖输入参数
2. 高阶函数:函数的参数可以是一个或多个函数;函数的返回值也可以是一个函数
3. 兰姆达表达式;方法引用



package com.example.demo;

import org.assertj.core.util.Lists;

import javax.sound.midi.SysexMessage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 参考:https://blog.csdn.net/EQuaker/article/details/86561781
 *       https://www.cnblogs.com/yunqing/p/9221117.html
 * 1. 函数式编程:(两个特点)
 *      可以把函数作为参数传递给另一个函数,也就是所谓的高阶函数
 *      可以返回一个函数,这样就可以实现闭包或者惰性计算(闭包:A函数返回B函数,B函数使用了A中的变量,则相当于扩大了A中变量的作用范围;放回方法,可以延迟执行)
 * 2. 函数式接口(只有一个抽象方法,可以有多个默认实现方法或静态方法)
 *      Consumer<T>:消费性接口
 *      Supplier<T> 供给型接口
 *      Function<T,R> 函数型接口
 *      Predicate<T> 断言型接口
 *      Comparator<T> 比较器接口,一般用于集合、流中的对象排序等操作中自定义比较规则,(a,b)-> a-b ;a是后一个元素,b是前一个元素,满足计算结果大于0时保留原顺序,小于0时交换顺序
 * 3. 兰姆达表达式(函数式接口的实现)
 *      (参数,一个时可省略括号) -> {函数实现,一条语句可以不用括号及返回return}
 * 4. 方法引用(进一步简化lambda表达式的声明)
 *      objectName::instanceMethod
 *      ClassName::staticMethod
 *      ClassName::instanceMethod   (把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。)
 * 5. 流stream
 *          1).Stream是元素的集合,这点让Stream看起来用些类似Iterator;
 *          2).可以支持顺序和并行的对原Stream进行汇聚的操作;(直接告诉程序要做什么,如转换成大写,怎么做(如并行还是串行等)让计算机自己决定)
 *    使用步骤:stream创建、转换、聚合(Reduce)
 *    (转换操作都是lazy的,多个转换操作只会在汇聚操作(见下节)的时候融合起来,一次循环完成。
 *    我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,
 *    在汇聚操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。)
 *    (汇聚操作(也称为折叠)接受一个元素序列为输入,反复使用某个合并操作,把序列中的元素合并成一个汇总的结果。
 *    比如查找一个数字列表的总和或者最大值,或者把这些数字累积成一个List对象。Stream接口有一些通用的汇聚操作,
 *    比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()。)
 *
 */
public class TestLamda {

    public static void main(String[] args){
//        testStream();
        testConsumer(10,(i) -> System.out.println(i*10));
    }

    static void testConsumer(int i,Consumer<Integer> consumer){
        consumer.accept(i);
    }

    public static void testStream(){
        //1. 创建:Collection(集合子类).stream();Stream.of;generate;iterate
        //2. 转换:distinct;filter;map;flatMap;peek;limit;skip;
        //3. 汇聚:
        //          1)可变汇聚:collect      2)其他汇聚:reduce;count;allMatch;anyMatch;findFirst;noneMatch;max;min
        List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
        Stream.generate(() -> Math.random());
        Stream.generate(Math::random);
        Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);
        System.out.println("result:  "+nums.stream().filter(s -> s == null).count());
        System.out.println("sum is:"+nums.stream().filter(num -> num != null).distinct().mapToInt(num -> num * 2)
                .peek(System.out::println).skip(2).limit(4).sum());
        //汇聚
        List<Integer> nums2 = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
        List<Integer> numsWithoutNull = nums2.stream().filter(num -> num != null).
                collect(() -> new ArrayList<Integer>(),//生成容器
                        (list, item) -> list.add(item),//元素添加到容器
                        (list1, list2) -> list1.addAll(list2));//多个结果容器合并操作
        List<Integer> numsWithoutNull2 = nums2.stream().filter(num -> num != null).
                collect(Collectors.toList());
        List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
        System.out.println("ints sum is:" + ints.stream().reduce((sum, item) -> sum + item).get());

    }


}

反应式流

* 是一种基于数据流和变化传递的声明式的编程范式。流是数据的一种存在形态,可以基于流进行处理(类似于流水线),jdk8的stream主要关注的是流的创建、转换、汇聚,也是声明式编程的思想,相比于命令式编程(传统的通过顺序、分支、循环等控制处理过程),声明式编程只需要开发人员告诉程序数据应该做何种处理(如map\reduce),至于如何去处理(并行穿行、什么时机处理等等),不需要开发人员关心。反应式是一种消息驱动的异步处理模式,采用背压模型,谁慢谁主动,可以再push和pull之间切换,消费者慢于生产者时,消费者主动pull,生产者慢于消费者时,生产者push消息,采用这种模型不会使得过快的生产者压制消费者。

* 反应式流一是管理跨异步边界的流数据交换(即数据在线程间传递),二是避免消息消费者缓存任意数量的数据(引入背压模式)。

* 异步处理时(消息驱动),当消费者能力大于生产者效率时,消费者只需等待不会影响系统的正常运行。生产者效率大于消费者时,有两种处理方案:1.改变消费者,消费者引入无界缓冲区,实际上无法实现;2.改变生产者,降低生产者的效率,以避免较快的生产者不会压制消费者,这就是背压模式。

* jdk1.9在juc的flow下引入了反应式流的四大接口,但官方不推荐使用,可以认为是更高版本的特性。从代码结构上看,反应式流包含reactive-streamsreactive-streams-tck两部分,reactive-streams是一组接口规范,包含了包含反应式流必要的操作和实体,tck是技术兼容包,为实现reactive-stream api提供帮助。1.9反应式流和1.8stream均是声明式编程,1.8stream是同步的,1.9反应式流是异步的,侧重于消息的产生和消费。

* 反应式流是一种编程范式,目前具体实现的框架有rxjava2(兼容了反应式流和rxjava,使用麻烦),Reactor是基于反应式流规范的反应式编程库,是spring5反应式编程(webflux)的基础,由于1.8兰姆达表达式的特性可以发挥Reactive Streams规范的强大特性,当前reactor要求jdk最低1.8。jdk1.9Flow也是jdk对反应式流规范的一种实现

* Webflux(Reactor)中的Mono、Flux都是Publisher的实现,Mono包含0-1个元素,Flux包含0-N个元素

reactive-stream api包含四个接口:

//发布者
public  interface  Publisher < T > {
	public  void  subscribe(Subscriber <?super  T >  s);
}

//订阅者
public  interface  Subscriber < T > {
	public  void  onSubscribe(Subscription  s);
	public  void  onNext(T  t);
	public  void  onError(Throwable  t);
	public  void  onComplete();
}

//表示Subscriber消费Publisher发布的一个消息的生命周期
public interface Subscription {
	public void request(long n);
	public void cancel();
}

//处理器,表示一个处理阶段,它既是订阅者也是发布者,并且遵守两者的契约
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
	
}

* 执行过程:

Publisher,即发布者,是有序消息的生产者。它根据收到的请求向订阅者发布消息。

Subscriber,即订阅者,从发布者那里订阅并接收消息。发布者向订阅者发送订阅令牌(Subscription)。使用订阅令牌,订阅者可以从发布者那里请求多个消息。当消息元素准备就绪时,发布者向订阅者发送多个或更少的元素。然后订阅者可以再次请求更多的消息元素,或取消订阅。一个发布者可能需要处理来自多个订阅者的请求。

         Subscription(订阅费),订阅令牌。当订阅请求成功时,发布者将其传递给订阅者。订阅者使用订阅令牌与发布者进行交互,例如请求更多的消息元素或取消订阅。

Processor,即处理器,充当订阅者和发布者的处理阶段。Processor 接口继承了 Publisher和 Subscriber 接口。它用于转换发布者/订阅者管道中的元素。Processor<T, R>会将来自于发布者的 T 类型的消息数据,接收并转换为 R 类型的数据,并将转换后的 R 类型数据发布给订阅者。一个发布者可以拥有多个处理者

JDK中带的发布者类java.util.concurrent.SubmissionPublisher

    SubmissionPublisher能够以反应流的方式生成元素(消息),并以异步方式发布元素(消息)。

* 代码示例:

1.处理器类

 

2. 订阅者

3. 测试类

* 参考文章:

反应式流 Reactive Streams 入门介绍 - 知乎

​​​​​​反应式流 - Reactive Stream丶Java教程网-IT开发者们的技术天堂

​​​​​​https://www.csdn.net/tags/NtzaYgysNzY3Mi1ibG9n.html

[webflux与mvc](Reactor-Netty与Spring WebFlux解读 之 第一章 为什么需要Spring WebFlux - 知乎)

// todo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值