Java 回调函数入门指南导读回调函数是编程中的重要概念在事件处理、异步编程、框架设计中广泛应用。本文将通过简单易懂的例子带你快速掌握 Java 回调函数的使用方法。 目录一、什么是回调函数二、生活化的理解三、代码示例详解四、运行结果五、回调函数的应用场景六、进阶使用 Consumer 函数式接口七、总结一、什么是回调函数 定义回调函数Callback Function是指将一个函数或方法作为参数传递给另一个函数在适当的时机被调用执行。 核心特点特点说明函数作为参数方法可以接收其他方法作为参数延迟执行传入的方法不会立即执行而是在特定时机执行控制反转调用方决定具体实现被调用方负责调用时机 通俗理解“你调用我我执行完后回调你提供的方法”二、生活化的理解 生活中的例子场景数星星的故事想象这样一个场景小明要数星星主要逻辑但是 - 数之前需要搬椅子前置操作 - 数完之后要搬回椅子后置操作传统方式小明自己搬椅子 → 数星星 → 搬回椅子回调方式小明专注数星星搬椅子的事交给别人做小明说“我只负责数星星搬椅子的事你调用者自己决定怎么做”这就是回调的思想将某些操作委托给调用者去实现。三、代码示例详解3.1 定义回调接口后置回调接口/** * 后置方法接口 * * 作用定义一个在后置阶段执行的回调方法 */FunctionalInterface// 推荐添加表示这是一个函数式接口publicinterfaceHouZhi{/** * 后置方法 */voidhouZhiMethod();}前置回调接口/** * 前置方法接口 * * 作用定义一个在前置阶段执行的回调方法 */FunctionalInterfacepublicinterfaceQianZhi{/** * 前置方法 */voidqianZhiMethod();} 关键点说明FunctionalInterface声明这是一个函数式接口只能有一个抽象方法可以使用 Lambda 表达式编译器会检查是否符合规范3.2 核心业务类/** * 计数开始类 * * 职责执行主要的计数逻辑并在适当时机调用回调方法 */publicclassCountStart{/** * 开始计数方法 * * param num 要数的次数 * param qianZhi 前置回调数之前做什么 * param houZhi 后置回调数之后做什么 */publicvoidbegin(intnum,QianZhiqianZhi,HouZhihouZhi){/* 1. 执行前置方法 */if(qianZhi!null){System.out.println(【准备阶段】);qianZhi.qianZhiMethod();}/* 2. 执行主要逻辑 */System.out.println(【开始数星星】);for(inti0;inum;i){System.out.println(数星星i);try{Thread.sleep(500);// 模拟数星星的时间间隔}catch(InterruptedExceptione){e.printStackTrace();}}/* 3. 执行后置方法 */if(houZhi!null){System.out.println(【收尾阶段】);houZhi.houZhiMethod();}System.out.println(✨ 完成);}} 代码要点要点说明空指针检查if (qianZhi ! null)避免传入 null 时报错执行顺序前置 → 主要逻辑 → 后置职责分离CountStart 只负责调用不关心具体实现3.3 测试类方式一使用 Lambda 表达式推荐⭐/** * 测试类 */publicclassTest{publicstaticvoidmain(String[]args){// 创建 CountStart 实例CountStartcountStartnewCountStart();// 调用 begin 方法传入两个 Lambda 表达式作为回调countStart.begin(5,// 前置回调数星星之前做的事()-System.out.println(搬出一把椅子并坐上去),// 后置回调数完星星后做的事()-System.out.println(把椅子搬回屋子里));}}方式二使用匿名内部类传统方式publicclassTest{publicstaticvoidmain(String[]args){CountStartcountStartnewCountStart();countStart.begin(5,newQianZhi(){OverridepublicvoidqianZhiMethod(){System.out.println(搬出一把椅子并坐上去);}},newHouZhi(){OverridepublicvoidhouZhiMethod(){System.out.println(把椅子搬回屋子里);}});}}方式三使用方法引用publicclassTest{// 定义具体的方法publicstaticvoidprepareChair(){System.out.println(搬出一把椅子并坐上去);}publicstaticvoidcleanupChair(){System.out.println(把椅子搬回屋子里);}publicstaticvoidmain(String[]args){CountStartcountStartnewCountStart();// 使用方法引用countStart.begin(5,Test::prepareChair,Test::cleanupChair);}} Lambda 表达式优势对比三种方式方式代码量可读性推荐度Lambda 表达式⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐匿名内部类⭐⭐⭐⭐⭐⭐⭐方法引用⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐✅建议优先使用 Lambda 表达式或方法引用代码更简洁四、运行结果 控制台输出【准备阶段】 搬出一把椅子并坐上去 【开始数星星】 数星星0 数星星1 数星星2 数星星3 数星星4 【收尾阶段】 把椅子搬回屋子里 ✨ 完成 执行流程图┌─────────────────┐ │ 调用 begin() │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 执行前置回调 │ ← qianZhi.qianZhiMethod() │ 搬出椅子 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 执行主要逻辑 │ ← for 循环数星星 │ 数星星 0-4 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 执行后置回调 │ ← houZhi.houZhiMethod() │ 搬回椅子 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 完成 │ └─────────────────┘五、回调函数的应用场景 实际开发中的常见用途5.1 事件监听器// Android 按钮点击事件button.setOnClickListener(newView.OnClickListener(){OverridepublicvoidonClick(Viewv){// 回调方法按钮被点击时执行Toast.makeText(context,按钮被点击了,Toast.LENGTH_SHORT).show();}});// 简化为 Lambdabutton.setOnClickListener(v-Toast.makeText(context,按钮被点击了,Toast.LENGTH_SHORT).show());5.2 异步任务回调// 网络请求回调interfaceNetworkCallback{voidonSuccess(Stringresponse);voidonFailure(Stringerror);}publicvoidfetchData(NetworkCallbackcallback){newThread(()-{try{StringresponsehttpGet(url);callback.onSuccess(response);// 成功回调}catch(Exceptione){callback.onFailure(e.getMessage());// 失败回调}}).start();}5.3 模板方法模式// 数据库操作模板publicvoidexecuteTransaction(RunnablebeforeCommit,RunnableafterCommit){try{// 1. 开启事务connection.setAutoCommit(false);// 2. 执行业务逻辑由调用者实现// ...// 3. 提交前回调if(beforeCommit!null){beforeCommit.run();}// 4. 提交事务connection.commit();// 5. 提交后回调if(afterCommit!null){afterCommit.run();}}catch(SQLExceptione){connection.rollback();thrownewRuntimeException(e);}}5.4 Spring 中的回调// JdbcTemplate 使用回调jdbcTemplate.execute((Connectioncon)-{// 前置操作System.out.println(获取数据库连接);// 主要逻辑PreparedStatementpscon.prepareStatement(SELECT * FROM users);ResultSetrsps.executeQuery();// 后置操作资源关闭rs.close();ps.close();returnnull;});六、进阶使用 Consumer 函数式接口 优化方案Java 8 提供了内置的函数式接口可以直接使用无需自定义接口importjava.util.function.Consumer;publicclassCountStart{/** * 使用 Consumer 接口 */publicvoidbegin(intnum,ConsumerStringbefore,ConsumerStringafter){// 前置回调if(before!null){before.accept(准备开始);}// 主要逻辑for(inti0;inum;i){System.out.println(数星星i);}// 后置回调if(after!null){after.accept(已完成);}}}// 使用示例publicclassTest{publicstaticvoidmain(String[]args){CountStartcountStartnewCountStart();countStart.begin(5,msg-System.out.println(【前置】msg - 搬出椅子),msg-System.out.println(【后置】msg - 搬回椅子));}} 常用函数式接口接口方法用途Runnablerun()无参无返回值ConsumerTaccept(T)有参无返回值SupplierTget()无参有返回值FunctionT,Rapply(T)有参有返回值PredicateTtest(T)判断条件七、总结 核心知识点回顾概念说明回调函数作为参数传递的函数在特定时机被调用实现方式接口 Lambda 表达式 / 方法引用核心思想控制反转调用者决定具体实现优点灵活、可扩展、解耦✅ 回调函数的优势优势说明灵活性高调用者可以自定义行为代码解耦主要逻辑与辅助逻辑分离易于扩展新增功能无需修改核心代码符合开闭原则对扩展开放对修改封闭⚠️ 注意事项空指针检查始终检查回调是否为 null异常处理回调中的异常可能影响主流程执行时机明确回调在什么时候被执行线程安全多线程环境下注意线程安全问题 最佳实践// ✅ 推荐做法publicvoidexecute(Runnablecallback){if(callback!null){try{callback.run();}catch(Exceptione){// 记录日志log.error(回调执行失败,e);}}}// ❌ 不推荐publicvoidexecute(Runnablecallback){callback.run();// 可能 NullPointerException} 扩展阅读函数式接口Java 8 新特性Lambda 表达式简化匿名类的写法方法引用::运算符的使用设计模式策略模式、观察者模式、模板方法模式异步编程CompletableFuture、Reactive Streams