从一行源代码延伸到函数式接口
读dubbo源码的时候,看到了这样一行代码,一开始有点懵,这是函数式编程啊,里面用到了函数式接口,而且还嵌套了两层,为了搞明白其中的作用,特意复习了一下jdk8中的函数式接口。
ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.computeIfAbsent(url, k -> new ConcurrentHashMap<>());
ChildListener zkListener = listeners.computeIfAbsent(listener, k ->(parentPath, currentChilds) -> ZookeeperRegistry.this.notify(url, k, toUrlsWithEmpty(url, parentPath, currentChilds)));
函数式接口
JDK8中引入了@FunctionInterface,这个注解表示这是一个函数式接口。函数式接口定义为,一个接口中只含有一个抽象方法,那么这个接口就可以当作函数式接口进行使用,而注解@FunctionInterface并不是必须的,它只是起到一个标识作用,这样其他人看到这个注解就知道了,不会在接口中添加其他抽象方法,同时这个注解,编译器也会帮助我们(多个抽象方法会报错)。
只能有一个抽象方法,但是可以添加其他的静态方法、default方法。 JDK8中的static、default方法 JDK8函数式接口介绍
函数接口使用
Lambda表达式式使用函数式接口的最好工具,其实它就是定义了一个匿名类来实现接口。我们可以将lambda表达式赋值给某个变量,然后可以就当成一个变量来处理,也可以作为其他方法的参数。(和python闭包有点类似)
举个例子:
Funcation f = (k) -> k;
f.apply("test");
上面的k,在真正的调用的时候会是真正传入方法的参数【也就是test】
回到开头
我们回到最开始的那行代码,如果你看过老的版本的代码你会立马明白这其他的作用,两段代码功能一样,但是老代码需要14行,而使用lambda和函数式接口只需要2行。
让我们把开头的代码,转换自己的类,然后测试一下
第一种情况
ConcurrentMap<String, Person> map = Maps.newConcurrentMap();
// 先使用最匿名类
map.computeIfAbsent("k1", new Function<String, Person>() {
@Override
public Person apply(String s) {
// s是map的key=1,这个是创建key=1的value
Person person = new Person("jay");
System.out.printf("map的key=%s,对应的value=%s\n", s, person);
return person;
}
});
输出:map的key=k1,对应的value=Person:[name=jay]
第二种情况
ConcurrentMap<String, Person> map = Maps.newConcurrentMap();
// 使用lambda
map.computeIfAbsent("k2", s -> {
Person person = new Person("green");
System.out.printf("map的key=%s,对应的value=%s\n", s, person);
return person;
});
输出:map的key=k2,对应的value=Person:[name=green]
第三种情况
// 使用lambda,并且我们把value的类型改成函数式
ConcurrentMap<String, PersonFunction> map2 = Maps.newConcurrentMap();
// 这里有两个函数式接口,
// 第一个是computeIfAbsent的参数,用于创建map2的value
// 第二个是map2的value,因为是一个函数式接口的类型
PersonFunction pf = map2.computeIfAbsent("k1", s -> k -> k.toUpperCase());
String bigName = pf.upperName("jim");
System.out.println(bigName);
输出:JIM
第一次使用computeIfAbsent的参数创建了k1的value,一个PersonFunction类型的对象。这个对象是lamdba表达式
k -> k.toUpperCase()
本文使用 mdnice 排版