• Java-回调函数


    在这里插入图片描述

    什么是回调

    函数调用可以分为三种模式,串行调用、异步调用、回调。这三种都是日常开发中常见到的方式。

    一个方法执行完,再执行下一个,串行逻辑会阻塞线程执行流程,等到所有逻辑执行结束,线程才会结束。

    异步执行是非阻塞类型。在主线程中,可以通过new Thread的方式异步执行逻辑,通过Thread执行的逻辑不会阻塞主流程。类似日志上报,发送kafka消息等,都可以通过异步的方式处理。

    回调,就是客户程序A调用服务程序B中的一个函数F_B,然后B又在某个时候反过来调用A中的某个函数F_A,对于A来说,这个F_A便叫做回调函数。一般说来,A不会自己调用F_A,A提供F_A的目的就是让B来调用它。由于B并不知道A提供的F_A姓甚名谁,所以A会约定F_A的接口规范,然后由A提前通过B的一个函数R告诉B自己将要使用F_A函数,这个过程称为回调函数的注册,R称为注册函数。

    下面举个通俗的例子: 某天,我打电话向你请教问题,当然是个难题,你一时想不出解决方法,于是我们约定:等你想出办法后打手机通知我 。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。

    例子中加粗的两部分说明这是一个“异步+回调“的过程,异步便是我给你打完电话,没有等你相处结果,回调是你在想到办法之后通知我。这里我的手机号就相当提前在你这注册的回调函数,你处理完成之后,直接调用函数来通知我。

    通过在工作中的场景,自认为回调和异步更搭配。另外就是写框架性的代码,回调用的会多一些。

    java中回调的应用

    可以想象一个场景,有数据库需要回填某些数据,数据回填之后要将数据修改数量,结束时间等进行记录。

    这个场景是不是和例子比较像,都是主线程下发一个任务,子线程完成任务之后,通知主线程执行其他操作。可以看下代码

    首先定义一个回调接口

    //接口可以接收多个入参,有一个出餐
    public interface FuncCallback<P, R> {
        R call(P... p);
    }
    
    • 1
    • 2
    • 3
    • 4

    然后定义数据处理类,这个类的入参除了数据处理中需要的参数外,还需要有回调类

    public class DbDataFresh {
        /**
        * 数据处理执行逻辑,dataType,operator为业务逻辑需要的参数
        * FuncCallback callback 是绑定的回调接口。这样绑定之后,
        * 任意一个调用DbDataFresh.fresh的程序,都可以指定逻辑处理结束之后的回调
        * 在fresh方法中可以指定通过修改callback.call调用顺序,控制回调时机
        */
        public void fresh(Integer dataType, String operator, FuncCallback callback) {
            //do fresh, get data change count
            int total = 100;
    
            //callback call
            callback.call(total, System.currentTimeMillis());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    我们再看一下程序的主入口

    public class UserHandleMain {
          private static final DbDataFresh dbDataFresh = new DbDataFresh();
    
          public static void main(String[] args) {
                //调用DbDataFresh.fresh方法,同时绑定回调
                //回调函数使用fresh方法传回来的数据进行其他逻辑处理
                dbDataFresh.fresh(1, "system", new FuncCallback() {
                @Override
                public Object call(Object[] p) {
                      if (p == null || p.length == 0) {
                            return "handle empty";
                      }
                      //遍历处理结果
                      StringBuilder res = new StringBuilder();
                      for (Object o : p) {
                            res.append(o.toString()).append("_");
                      }
                      System.out.println(res.toString());
                      return res.toString();
                }
                });
    
                //使用lambda方式,这种貌似是比较常见到的
                dbDataFresh.fresh(1, "system", p -> {
                      if (p == null || p.length == 0) {
                      return "handle empty";
                      }
                      //遍历处理结果
                      StringBuilder res = new StringBuilder();
                      for (Object o : p) {
                      res.append(o.toString()).append("_");
                      }
                      System.out.println(res.toString());
                      return res.toString();
                });
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    参考

    Java-接口回调-掘金
    Java接口回调-csdn

  • 相关阅读:
    Docker 环境 Nacos2 MySQL8
    分布式id(1)
    小程序学习
    【NodeJs-5天学习】第二天篇① ——fs文件系统
    子集生成算法:给定一个集合,枚举所有可能的子集
    ffmpeg推流+NGINX(RTMP)+VLC-QT拉流(Win7)
    阿里云yum源和tuna源
    使用node-cmd重启electron
    ESP8266-Arduino网络编程实例-ESP-Now点对点双向通信(Two Way)
    Packed Ciphertexts in LWE-based Homomorphic Encryption:解读
  • 原文地址:https://blog.csdn.net/believe__dream/article/details/126512573