Java 的 @FunctionalInterface 以及Lamda

背景

在使用MockMvc的时候我们通常会见到类似下面的表达

1
2
3
4
mockMvc.perform(MockMvcRequestBuilders.get("/some_api_endpoint")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].user_id").value("123"));

andExpect()到底是个什么东西?为什么里面传了函数之后返回结果还能继续调用自身?

经过翻阅文档我们发现,MockMvc.perform 返回一个ResultActions的instance。
而这个ResultActions则是一个接口。

1
2
3
4
5
6
7
8
9
public interface ResultActions {

ResultActions andExpect(ResultMatcher matcher) throws Exception;

ResultActions andDo(ResultHandler handler) throws Exception;

MvcResult andReturn();

}

这样就解释了为什么可以继续调用自身。

那么这个ResultMatcher是个什么东西?

1
2
3
4
5
6
7
8
9
10
11
@FunctionalInterface
public interface ResultMatcher {
void match(MvcResult result) throws Exception;
static ResultMatcher matchAll(ResultMatcher... matchers) {
return result -> {
for (ResultMatcher matcher : matchers) {
matcher.match(result);
}
};
}
}

于是引出了这个文章的最终话题,@FunctionalInterface到底是什么?

@FunctionalInterface和Java8 Lamda

其实理解了@FunctionalInterface对理解Lamda很有帮助,因为Lamda的本质是匿名函数。
@FunctionalInterface字如其名,是函数的接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
@FunctionalInterface
interface FunctionPointer {
void helloWorld(String subject, String name);
}

private static void helloFromFunction(String subject, String name, FunctionPointer functionPointer){
functionPointer.helloWorld(subject, name);
}

private static void hello(String subject, String name){
System.out.println("Hello " + subject + ", I'm " + name + ". ");
}

public static void main(String[] args) {
helloFromFunction("world", "wrongwrong", (subject, name) -> System.out.println("Hello " + subject + ", I'm " + name + "."));
helloFromFunction("world", "wrongwrong", Main::hello);
}
}

上面的代码,我们用@FunctionalInterface标注了FunctionPointer, 于是任何我们定义的函数,只要符合其中定义的void helloWorld(string, string)的调用规则,都可以用FunctionPointer.helloWorld来调用。

概念上来说,一个@FunctionalInterface只能有一个抽象函数, 所以我们定义void hello(string, string)的时候并不需要声明我这个函数实现了FunctionPointer中的helloWorld这个方法。

甚至,我们只需在使用的时候带入一个匿名函数。

1
helloFromFunction("world", "wrongwrong", (subject, name) -> System.out.println("Hello " + subject + ", I'm " + name + "."));

这个就是Lamda的本质了。