函数式方法的实现(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()两个方法中各自的处理逻辑提取成一个函数式接口作为公共方法的参数传递,这样的话解剖的过程被提取出来了,然后具体的处理逻辑也以调用处传递的匿名内部类的处理逻辑为准,于是就解决了这个问题,并提高了复用性。
@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()方法中通过匿名内部类的方式传递需要处理的逻辑。
@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>
: 接受两个输入参数,返回一个结果
还在测试中。。。详细使用会在后续更新!
文章内容若存在错误或需改进的地方,欢迎大家指正!非常感谢!