一个絮叨的工作笔记,不想看废话的直接从 自定义@FunctionalInterface 往下看吧
最近在学习spring-boot源码的时候发现了一个特殊的语法。
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
// 获得 ServletContextInitializer 对象
return this::selfInitialize;
}
懵逼了好久,后才查询了之后才知道上面内容等价于
return new ServletContextInitializer() {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
selfInitialize(servletContext);
}
};
}
为什么会等价于这个呢?对于程序员永远要对新的事物抱有兴趣,然后我就去找了找这个语法还有什么别的用处。
首先根据网上的说法::的作用是,左边是类,又变是类中的方法,简单的例子
public class DaiTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("1","2","3","4");
// 在循环中将每个循环出来的内容,调用DaiTest.print的方法
list.forEach(DaiTest::print);
}
public static void print(String s) {
System.out.print(s);
}
}
执行的结果是
1234
使用IDEA的时候点击::会发现跳转到了一个新的接口上,会发现这就是函数式接口
@FunctionalInterface
public interface Consumer<T> {
/**
*
* @param t the input argument
*/
void accept(T t);
/**
*
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
所以发现之前的代码
public static void main(String[] args) {
List<String> list = Arrays.asList("1","2","3","4");
// 在循环中将每个循环出来的内容,调用DaiTest.print的方法
list.forEach(DaiTest::print);
}
等价于
public static void main(String[] args) {
List<String> list = Arrays.asList("1","2","3","4");
// 在循环中将每个循环出来的内容,调用DaiTest.print的方法
Consumer<String> consumer = DaiTest::print;
list.forEach(consumer);
}
可以看出来可以根据输入参数和输出参数的不同返回不同的function方法,那么我们看看到底什么是函数式接口
Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。
@FunctionalInterface注释的约束同时也是函数式接口的约束
看文字实在是不知道怎么理解,那么下面我们做几个例子看看。
首先我们有个类,有如下方法
public class DaiTest {
public String getStr(String str) {
System.out.println("接收的参数:" + str);
return "456";
}
public Boolean getBo(String str) {
return false;
}
public Integer getInt(String str) {
System.out.println("接收的参数:" + str);
return 1;
}
public Long getLong(String str) {
return 1L;
}
public Object getOb(String str) {
return new Object();
}
public DaiTest() {
System.out.println("开始创建DaiTest");
}
}
创建3个@FunctionalInterface,分别对应getStr、getInt和构造函数的入参、出参
@FunctionalInterface
public interface TestFunction {
String getfunction(String str);
}
@FunctionalInterface
public interface TestIntFunction {
Integer getfunction(String str);
}
@FunctionalInterface
public interface TestObjFunction {
DaiTest getfunction();
}
然后执行main方法中的代码
public static void main(String[] args) {
DaiTest test = new DaiTest();
TestFunction testFunction = test::getStr;
TestIntFunction getInt = test::getInt;
TestObjFunction aNew = DaiTest::new;
String testFunction1 = testFunction.getfunction("testFunction");
System.out.println("运行TestFunction结束");
Integer getInt1 = getInt.getfunction("getInt");
System.out.println("运行TestIntFunction结束");
DaiTest getfunction = aNew.getfunction();
System.out.println("运行TestObjFunction结束");
}
最后返回结果是
接收的参数:testFunction
运行TestFunction结束
接收的参数:getInt
运行TestIntFunction结束
开始创建DaiTest
运行TestObjFunction结束
可以看到我们调用接口的方法,实际上调用的是DaiTest类方法的引用