相关阅读:
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(四)枚举(enum)和常量定义,工厂类使用对比
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
JAVA编程思想(四)Builder模式经典范式以及和工厂模式如何选?
HikariPool源码(二)设计思想借鉴
人在职场(一)IT大厂生存法则接口中只有一个抽象方法的接口称为函数式接口。函数式接口可以通过@FunctionalInterface注解来修饰,也可以不使用该注解,只要接口只有一个抽象方法则可。
import java.util.function.Consumer; public class Service { // 方法入参为函数式接口,函数定义为消费Event public void exec(Consumer<Event> consumer) { Event event = new Event(1001, "get data from cache."); consumer.accept(event); } } // event通知消费类,消费event的方式是将event发出去 public class EventNotify { // 方法名并不重要,不需要和函数式接口方法名一致,只要参数和返回值一致则可 public void send(Event event) { System.out.println("send event: " + event.toString()); } } // event记录消费类,消费event的方式是将event记录下来 public class EventLogger { // 方法名并不重要,不需要和函数式接口方法名一致,只要参数和返回值一致则可 public static void log(Event event) { System.out.println("log event: " + event.toString()); } } public class Event { private int eventId; private String content; public Event(int eventId, String content) { this.eventId = eventId; this.content = content; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("eventId=").append(eventId).append(", "); builder.append("content=").append(content); return builder.toString(); } } 复制代码
public class FunctionDemo { public static void main(String[] args) { Service service = new Service(); EventNotify eventNotify = new EventNotify(); // 使用类实例::方法名传入函数,这里必须使用类实例,是因为这个方法声明为非静态方法 service.exec(eventNotify::send); // 使用类::方法名传入函数,这里可以使用类而非类实例,是因为这个方法声明为静态方法 service.exec(EventLogger::log); } } 复制代码
输出:
send event: eventId=1001, content=get data from cache. log event: eventId=1001, content=get data from cache. 复制代码
看到这里,很多人会想,从这个例子看,函数式接口并没有什么优势,不用函数式接口,使用接口实现类也能实现啊.
2.3.1. 消费者直接实现接口方法
class NonFunctionEventNotify<Event> implements Consumer<Event> { @Override public void accept(Event event) { System.out.println("send event: " + event.toString()); } } // 事件记录类,消费event的方式是将event记录下来 class NonFunctionEventLogger<Event> implements Consumer<Event> { @Override public void accept(Event event) { System.out.println("log event: " + event.toString()); } } 复制代码
2.3.2. 使用接口实现类
public class FunctionDemo { public static void main(String[] args) { Service service = new Service(); NonFunctionEventNotify nonFunctionEventNotify = new NonFunctionEventNotify(); // 传入实现类实例 service.exec(nonFunctionEventNotify); NonFunctionEventLogger nonFunctionEventLogger = new NonFunctionEventLogger(); // 传入实现类实例 service.exec(nonFunctionEventLogger); } } 复制代码
可见,不用函数式接口也能实现对应功能,那为啥还要使用函数式接口呢?
2.3.2. 函数式接口和接口实现方式差异以及优点
差异如下:
实现方式 | 掺入参数 | 实现接口 | 方法名 |
---|---|---|---|
函数式接口 | 可直接传入静态方法,省去类实例化动作 | 不需要实现任何接口 | 没有要求,只要方法入参和出参一样则可 |
接口实现类 | 必须有类实例,传入类实例的方法 | 需要实现指定接口 | 必须同接口方法完全一样 |
通过对比,函数式接口的优势就大大体现出来了。
注:Java提供的函数式接口已经能满足大部分使用场景,这些接口可以在java.util.function包下找到。
end.