【Java8新特性】02 函数式接口和Lambda表达式实战练习:环绕执行模式使行为参数化

简介: 【Java8新特性】02 函数式接口和Lambda表达式实战练习:环绕执行模式使行为参数化

Java8 由Oracle在2014年发布,是继Java5之后最具革命性的版本。  


Java8吸收其他语言的精髓带来了函数式编程,lambda表达式,Stream流等一系列新特性,学会了这些新特性,可以让你实现高效编码优雅编码。


01  引入实例


首先引入一个实际的例子,我们常常会写一个dao类来操作数据库,比如查询记录,插入记录等。


下面的代码中实现了查询和插入功能(引入Mybatis三方件):

public class StudentDao {
    /**
     * 根据学生id查询记录
     * @param id 学生id
     * @return 返回学生对象
     */
    public Student queryOne(int id) {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession session = null;
        try {
            session = sqlSessionFactory.openSession();
            // 根据id查询指定的student对象
            return session.selectOne("com.coderspace.mapper.student.queryOne", id);
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }
    /**
     * 插入一条学生记录
     * @param student 待插入对象
     * @return true if success, else return false
     */
    public boolean insert(Student student) {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession session = null;
        try {
            session = sqlSessionFactory.openSession();
            // 向数据库插入student对象
            int rows = session.insert("com.coderspace.mapper.student.insert", student);
            return rows > 0;
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }
  }


观察上面的两个方法可以发现:


return session.selectOne("com.coderspace.mapper.student.queryOne", id);


int rows = session.insert("com.coderspace.mapper.student.insert", student);

除了上面这两行,其他的代码都是一样的,都是先获取session,然后执行核心操作,最后关闭session。


获取session和关闭session这段代码围绕着具体的核心操作代码,我们可以称这段代码为模板代码。


假如又来了一个需求,需要实现删除student方法,那么你肯定会copy上面的获取session和关闭session代码,这样做有太多重复的代码,作为一名优秀的工程师肯定不会容忍这种事情的发生。


02  环绕执行模式使行为参数化


怎么解决呢?现在请出我们的主角:环绕执行模式使行为参数化。


啥叫行为参数化?上面例子中我们已经观察到了,除了核心操作代码其他代码都是一模一样,那我们是不是可以将核心操作代码作为入参传入模板方法中,根据不同的行为分别执行。


变量对象很容易作为参数传入,行为可以采用lambda表达式传入。


下面开始重构之前的例子,主要可以分为三步:

(1)定义函数式接口;

(2)定义模板方法;

(3)传递lambda表达式


所有的环绕执行模式都可以套用上面这三步公式。


第一步:定义函数式接口

@FunctionalInterface
public interface DbOperation<R> {
    /**
     * 通用操作数据库接口
     * @param session 数据库连接session
     * @param mapperId 关联mapper文件id操作
     * @param params 操作参数
     * @return 返回值,R泛型
     */
    R operate(SqlSession session, String mapperId, Object params);
}

定义了一个operate抽象方法,接收三个参数,返回泛型R。


第二步:定义模板方法


DbOperation是一个函数式接口,作为入参传入:

public class CommonDao<R> {
    public R proccess(DbOperation<R> dbOperation, String mappperId, Object params) {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession session = null;
        try {
            session = sqlSessionFactory.openSession();
            // 核心操作
            return dbOperation.operate(session, mappperId, params);
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }
  }


第三步:传递lambda表达式

// 根据id查询学生
String mapperId = "com.coderspace.mapper.student.queryOne";
int studentNo = 123;
CommonDao<Student> commonDao = new CommonDao<>();
// 使用lambda传递具体的行为
Student studentObj = commonDao.proccess(
        (session, mappperId, params) -> session.selectOne(mappperId, params),
        mapperId, studentNo);
// 插入学生记录
String mapperId2 = "com.coderspace.mapper.student.insert";
Student student = new Student("coderspace", 1, 100);
CommonDao<Boolean> commonDao2 = new CommonDao<>();
// 使用lambda传递具体的行为
Boolean successInsert = commonDao2.proccess(
        (session, mappperId, params) -> session.selectOne(mappperId, params),
        mapperId2, student);

实现了上面三步,假如要实现删除方法,CommonDao里面一行代码都不用改,只用在调用方传入不同的参数即可实现。


环绕执行模式在现实环境中大有用途,如果你发现几行易变的代码外面围绕着一堆固定的代码,这个时候你应该考虑使用lambda环绕执行模式了。


相关文章
|
5月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
761 157
|
5月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
5月前
|
安全 Java 开发者
告别NullPointerException:Java Optional实战指南
告别NullPointerException:Java Optional实战指南
319 119
|
5月前
|
Java Go 开发工具
【Java】(9)抽象类、接口、内部的运用与作用分析,枚举类型的使用
抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接 口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类abstract static不能同时修饰一个方法。
278 1
|
6月前
|
人工智能 Java API
Java AI智能体实战:使用LangChain4j构建能使用工具的AI助手
随着AI技术的发展,AI智能体(Agent)能够通过使用工具来执行复杂任务,从而大幅扩展其能力边界。本文介绍如何在Java中使用LangChain4j框架构建一个能够使用外部工具的AI智能体。我们将通过一个具体示例——一个能获取天气信息和执行数学计算的AI助手,详细讲解如何定义工具、创建智能体并处理执行流程。本文包含完整的代码示例和架构说明,帮助Java开发者快速上手AI智能体的开发。
2242 8
|
6月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
212 11
|
6月前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
997 12
|
6月前
|
Java 开发者
Java并发编程:CountDownLatch实战解析
Java并发编程:CountDownLatch实战解析
543 100
|
6月前
|
存储 前端开发 Java
【JAVA】Java 项目实战之 Java Web 在线商城项目开发实战指南
本文介绍基于Java Web的在线商城技术方案与实现,涵盖三层架构设计、MySQL数据库建模及核心功能开发。通过Spring MVC + MyBatis + Thymeleaf实现商品展示、购物车等模块,提供完整代码示例,助力掌握Java Web项目实战技能。(238字)
754 0
|
7月前
|
Java 编译器 API
Java Lambda表达式与函数式编程入门
Lambda表达式是Java 8引入的重要特性,简化了函数式编程的实现方式。它通过简洁的语法替代传统的匿名内部类,使代码更清晰、易读。本文深入讲解Lambda表达式的基本语法、函数式接口、方法引用等核心概念,并结合集合操作、线程处理、事件回调等实战案例,帮助开发者掌握现代Java编程技巧。同时,还解析了面试中高频出现的相关问题,助你深入理解其原理与应用场景。