========================================
原始代码
========================================
RoleService 类有删除角色和锁定角色两个函数.

@Service
public class RoleService { @Autowired
RoleDao roleDao; /**
* 删除指定的角色
* @param roleId
*/
public void deleteRole(Long roleId) {
Optional<Role> oldRole = roleDao.getRole(roleId);
if (oldRole.isPresent()) {
roleDao.delete(roleId); //1: 不同点
} else {
throw new BusinessException(String.format("Cannot find the role record for id [%d]", roleId));
}
} /**
* 锁定指定的角色
* @param roleId
*/
public void lockRole(Long roleId) {
Optional<Role> oldRole = roleDao.getRole(roleId);
if (oldRole.isPresent()) {
roleDao.lock(roleId) //2: 不同点
} else {
throw new BusinessException(String.format("Cannot find the role record for id [%d]", roleId));
}
}
}

问题分析:
可以看到上面这两个函数逻辑完全一致, 仅仅是最终调用的函数不同, 应该能优化, 一个思路是: 将框架部分封装为一个公用函数,  deleteRole() 和 lockRole() 函数调用该公共函数, 并将最终的 action 想法儿传进去.
如果是 C#, 因为有 delegate, 很容易做到; 如果是 Python的话, 那就更容易了, 直接将函数作为参数即可. 但 Java 不允许以函数作为参数, 处理起来要麻烦一些.

Java具体优化思路:虽然 Java 不允许以函数作为实参, 但是我们先将函数封装为类, 然后将类对象作为实参传进去.
具体实现方式有:
1. Java  8 之前,  利用 Runnable 或 Callable 接口作为公共函数的形参, 实参可以用真实的实现类, 也可以使用匿名类. 
2. Java 8 , 可以使用 java.util.function.Consumer 等接口作为公共函数的形参, 实参可以用真实的实现类, 也可以使用匿名类, 也可以使用 lambda 表达式.

显然最简洁的组合是: 使用 Java 8 中 java.util.function.Consumer 等接口作为公共函数的形参, 使用 lambda 做实参.

========================================
Java 8 内置的 Functional 接口
========================================
java.util.function 包中包含了一些常用的 Functional Interface, 而且都支持泛型. 所谓Functional Interface接口就是只有一个虚函数的接口. 主要的接口包括:
Consumer 接口, 该接口主要函数有一个形参, 没有返回值.
Function 接口, 该接口主要函数有一个形参, 可以有返回值.
Supplier 接口, 该接口主要函数没有形参, 但有返回值.
Predicate 接口, 该接口主要函数接受一个参数, 返回布尔型值.

正如上面所讲, Functional Interface接口就是只有一个虚函数的接口, 没什么特别之处, 我们也很容易自定义一个, 定义方式也和普通的Interface一样, 当然最好加上 @FunctionalInterface 注解, 这样如果不小心声明了多个虚函数, 编译时会报错.

Functional Interface 典型用法不是: 先声明一个接口, 然后在编写一个实现类.  而是: 用来声明函数的形参, 或者用来声明一个变量,  然后使用lambda表达式进行赋值. 

有了这一功能, Java 8 也具有一定的函数式编程特性.

========================================
重构后的代码
========================================

@Service
class RoleService2 {
@Autowired
RoleDao roleDao; /** 提取出的公共函数, 先判断指定角色是否存在, 若存在则继续执行某个动作, 若不存在直接抛出异常
* @param roleId
* @param action
*/
private void checkAndDo(Long roleId, java.util.function.Consumer<Long> action) {
Optional<Role> oldRole = roleDao.getRole(roleId);
if (oldRole.isPresent()) {
action.accept(roleId);
} else {
throw new BusinessException(String.format("Cannot find the role record for id [%d]", roleId));
}
} private void internalLock(Long roleId) {
roleDao.updateRoleState(roleId, RoleStateEnum.LOCKED);
} public void lockRole(Long roleId) {
checkAndDo(roleId, (rId) -> internalLock(rId));
} public void deleteRole(Long roleId) {
checkAndDo(roleId, (rId) -> roleDao.updateRoleState(rId, RoleStateEnum.DELETED));
}
}

使用 functional interface 和 lambda 表达式来优化代码的更多相关文章

  1. Lambda表达式常用代码示例

    Lambda表达式常用代码示例 2017-10-24 目录 1 Lambda表达式是什么2 Lambda表达式语法3 函数式接口是什么  3.1 常用函数式接口4 Lambdas和Streams结合使 ...

  2. Java疯狂讲义笔记——Lambda表达式

    Java8新增的Lambda表达式 [特性]支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例. [组成部分]1,形参列表 ...

  3. Lambda表达式(一)入门认识篇

    Lambda表达式(一)入门认识篇 Lambda简介 Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极 ...

  4. 07_Java8新增的Lambda表达式

    [Lambda表达式概述] Lambda表达式支持将代码块作为方法参数,Lambda表达式允许将使用简洁的代码来创建只有一个抽象方法的接口的实例.(这种接口称为函数式接口) [入门实例] packag ...

  5. Java 8新特性探究(一) JEP126特性lambda表达式和默认方法

    Lambda语法 函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是只包含一个方法的接口.比如Java标准库中的java.la ...

  6. Java函数式编程和lambda表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于 ...

  7. lambda表达式的应用例子和JavaSE 8特性

    在JavaSE 8 引入了lambda表达式,lambda表达式的引入带来的好处是:通过语法上的改进,减少开发人员需要编写和维护的代码数量.这个在下面使用和不使用lambda的对比中可以清晰看出来. ...

  8. <JAVA8新增内容>关于匿名内部集合和lambda表达式

    要想说清楚JAVA中的Lambda表达式,必须想讲一下匿名内部类来帮助理解本质. 一.匿名内部类 匿名内部类适合创建那种只需要一次使用的类,例如前面介绍命令模式时所需要的Command对象,匿名内部类 ...

  9. 对比讲解lambda表达式与传统接口函数实现方式

    在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应该都掌握了,实际上还是存在大量的 ...

随机推荐

  1. 在Linux系统中同步更新我们的Github博客

    原理介绍 类似于版本管理,我们把我们的hexo博客文件系统在Github上建立一个分支,通过管理分支提交最新的博客文件系统,保证我们博客框架的更新.然后我们基于最新的博客框架,撰写文章,进行Githu ...

  2. velocity模板引擎 -- java.io.FileNotFoundException: velocity.log (Permission denied)

    问题原因是velocity的日志框架导致(velocity是使用自己封装的日志框架记录日志的),velocity在初始化Logger时,如果没有读取到配置文件,则会使用默认的velocity.log做 ...

  3. [已决解]关于Hadoop start-all.sh启动问题

    问题一:出现Attempting to operate on hdfs namenode as root 写在最前注意: 1.master,slave都需要修改start-dfs.sh,stop-df ...

  4. koa-router 源码由浅入深的分析(7.4.0版本的)

    首先简单的介绍下什么koa-router,为什么要使用它,可以简单看下上一篇文章. 了解koa-router 首先我们来看下koa-router的源码的基本结构如下,它是由两部分组成的: ------ ...

  5. Lightoj 1128 - Greatest Parent

    Gate 倍增模板,在一个严格小根堆中,给定$x,y$,求$x$的祖先中$≥y$的最高点. 注意清零 #include<cstdio> #include<iostream> # ...

  6. Locust:简介和基本用法

    我个人在性能测试工作中,负载生成工具使用的大多都是jmeter,之前学习python时顺带了解过python开源的性能测试框架locust. 这篇博客,简单介绍下locust的使用方法,仅供参考... ...

  7. iOS开发基础-九宫格坐标(4)

    对iOS开发基础-九宫格坐标(3)的代码进行进一步优化. 新建一个 UIView 的子类,并命名为 WJQAppView ,将 appxib.xib 中的 UIView 对象与新建的视图类进行关联. ...

  8. 相约南湖,南京都昌信息亮相南湖HIT论坛

    金秋十月,雨过南湖水似油 ,烟雾蒙蒙净长空 2017年10月15日, 南湖HIT论坛迎来了第六届.本次论坛吸引了500名来自全国各地医疗机构.卫生行政主管部门的信息化主管和医疗IT企业的精英,齐聚嘉兴 ...

  9. keepalived--小白博客

    一.HA集群中的相关术语 1.节点(node) 运行HA进程的一个独立主机,称为节点,节点是HA的核心组成部分,每个节点上运行着操作系统和高可用软件服务,在高可用集群中,节点有主次之分,分别称之为主节 ...

  10. Java的selenium代码随笔(5)

    //以下七种方法主要用于生成年.月.日.小时.分钟和秒的信息,用于生成保存截图的文件目录名和文件名/** 格式化输出日期* * @return 返回字符型日期*/public static Strin ...