函数式方法的实现(JDK8+)

1、使用场景

例:在业务中难免会有对象嵌套的情况,下面就是模拟对象属性嵌套对象的一个简单Demo,在真实场景中,肯定会有复杂嵌套。我就以下面简单的Demo为例,来讲述函数式方法的实现。

在methodA()和methodB()两个方法中存在着相同的校验,而且最终对目标的处理逻辑却不同,此时按照常规的解决办法肯定是将两个方法中相同的校验部分提取成公共的方法,然后在两个方法中在进行调用,若经过的了校验才在每个方法中执行各自不同的逻辑。

但是,这里有一个问题,若提取了公共校验方法并接受A的对象为参数,那么在校验方法中肯定是需要一层一层的解出来嵌套的对象E并进行校验。然后在methodA()和methodB()方法中肯定会先调用校验方法并传递对象a,经过校验之后再对对象E的属性进行操作。此时问题来了,此时在methodA()和methodB()方法中是没有对A对象进行一层一层的解出来E对象的,所以也就是说当经过校验之后,还需要在各自的方法里在进行一次解剖的操作,此时不就代码不又重复了吗?你可能会想,下面这个直接使用a.getB().getC().getD().getE()一行代码不就拿到了E对象了吗?在下面这个Demo中是这样的,但是若嵌套的对象中包含集合和单实例对象混合呢或者其他更加复杂的嵌套呢,这样的话一行就解决不了了。于是,在这个场景下,我们应该使用公共的函数式方法,也就是将methodA()和methodB()两个方法中各自的处理逻辑提取成一个函数式接口作为公共方法的参数传递,这样的话解剖的过程被提取出来了,然后具体的处理逻辑也以调用处传递的匿名内部类的处理逻辑为准,于是就解决了这个问题,并提高了复用性。

java 复制代码
@Slf4j
public class Test1 {
    public static void main(String[] args) {
        methodA();
        methodB();
    }

    private static void methodA() {
        A a = new A(new B(new C(new D(new E("Y", 24)))));
        B b = a.getB();
        if (b == null){
            return;
        }
        C c = b.getC();
        if (c == null){
            return;
        }
        D d = c.getD();
        if (d == null){
            return;
        }
        E e = d.getE();
        if (e == null){
            return;
        }
        if ("Y".equals(e.getName())){
            e.setAge(20);
        }
        log.info("methodA方法:" + e);
    }

    private static void methodB() {
        A a = new A(new B(new C(new D(new E("Y", 18)))));
        B b = a.getB();
        if (b == null){
            return;
        }
        C c = b.getC();
        if (c == null){
            return;
        }
        D d = c.getD();
        if (d == null){
            return;
        }
        E e = d.getE();
        if (e == null){
            return;
        }
        processString(a, e -> {
            if (18 == e.getAge()){
                e.setName("N");
            }
        });
        log.info("methodB方法:" + e);
    }
}

@Data
@AllArgsConstructor
class A{
    private B b;
}

@Data
@AllArgsConstructor
class B{
    private C c;
}

@Data
@AllArgsConstructor
class C{
    private D d;
}

@Data
@AllArgsConstructor
class D{
    private E e;
}

@Data
@AllArgsConstructor
class E{
    private String name;
    private Integer age;
}

2、结合 java.util.function 包下的Consumer接口实现函数式方法

Java 在 java.util.function 包中提供了许多内置的函数式接口,**Consumer<T>就是其中一个,它接受一个输入参数,然后无返回结果。上述Demo即可结合Consumer<T>**实现函数式方法的提取。

在下面的代码中实现了一个processString方法,该方法接收两个参数,第一个参数是A对象,第二个参数是Consumer 接口。泛型的类型是在processString方法中最终要对谁进行处理,也就是 accept接口的入参类型,然后在methodA()和methodB()方法中通过匿名内部类的方式传递需要处理的逻辑。

java 复制代码
@Slf4j
public class Test1 {
    public static void main(String[] args) {
        methodA();
        methodB();
    }

    private static void methodA() {
        A a = new A(new B(new C(new D(new E("Y", 18)))));
        processString(a, e -> {
            if ("Y".equals(e.getName())){
                e.setAge(20);
            }
        });
        log.info("methodA方法:" + a.getB().getC().getD().getE());
    }

    private static void methodB() {
        A a = new A(new B(new C(new D(new E("Y", 18)))));
        processString(a, e -> {
            if (18 == e.getAge()){
                e.setName("N");
            }
        });
        log.info("methodB方法:" + a.getB().getC().getD().getE());
    }

    private static void processString(A a, Consumer<E> strProcessor) {
        B b = a.getB();
        if (b == null){
            return;
        }
        C c = b.getC();
        if (c == null){
            return;
        }
        D d = c.getD();
        if (d == null){
            return;
        }
        E e = d.getE();
        if (e == null){
            return;
        }
        // 执行接收到的不同处理逻辑
        strProcessor.accept(e);
    }
}

3、java.util.function 包中其他的函数式接口

  • Function<T,R>: 接受一个输入参数,返回一个结果
  • Predicate<T>: 接受一个输入参数,返回布尔值
  • Consumer<T>: 接受一个输入参数,无返回结果
  • Supplier<T>: 无输入参数,返回一个结果
  • BiFunction<T,U,R>: 接受两个输入参数,返回一个结果

还在测试中。。。详细使用会在后续更新!

文章内容若存在错误或需改进的地方,欢迎大家指正!非常感谢!

相关推荐
ABB自动化8 分钟前
for AC500 PLCs 3ADR025003M9903的安全说明
服务器·安全·机器人
努力学习的小廉15 分钟前
深入了解linux系统—— 进程池
linux·运维·服务器
年老体衰按不动键盘16 分钟前
快速部署和启动Vue3项目
java·javascript·vue
咖啡啡不加糖21 分钟前
Redis大key产生、排查与优化实践
java·数据库·redis·后端·缓存
liuyang-neu25 分钟前
java内存模型JMM
java·开发语言
秃头菜狗38 分钟前
各个主要目录的功能 / Linux 常见指令
linux·运维·服务器
利刃大大38 分钟前
【在线五子棋对战】二、websocket && 服务器搭建
服务器·c++·websocket·网络协议·项目
UFIT1 小时前
NoSQL之redis哨兵
java·前端·算法
刘 大 望1 小时前
数据库-联合查询(内连接外连接),子查询,合并查询
java·数据库·sql·mysql
怀旧,1 小时前
【数据结构】6. 时间与空间复杂度
java·数据结构·算法