程序里的很多单一临时的接口都可以由一系列的通用接口替代,在调用的时候使用Lambda表达式会更加的方便和直观。
举个例子:你有一个查找文件的方法
public static List<File> findFiles(FileFilter filter)
由于查找的过程中需要一些限制条件(如:文件类型、文件大小),你需要让调用者传入一个接口,叫FileFilter
public static interface FileFilter{
boolean filter(File file);
}
在使用的过程中我们会使用匿名类的方式传入参数
findFiles(new FileFilter() {
@Override
public boolean filter(File file) {
return !file.getName().endsWith(".java");
}
});
直到这里,我们可能觉得还没有什么异样,但是当接口的方法定义多了或者需要传入接口的方法多了之后,那么代码量将会很大。所以,在Java8中,我们可以使用Lambda表达式来简化这些代码
findFiles((file) -> {
return !file.getName().endsWith(".java");
});
是不是简洁了许多。好了,这里是背景。接下来我们要说使用通用型的接口来配合Lamda表达式,在许多的回调或者监听器的参数当中,我们可以分为两个大类:有返回值和无返回值。有返回值的我们叫做传入一个函数(比如第三方库要求你返回一个结果),无返回值的我们叫做传入一个过程(比如Runnable里的run方法就是一个过程),上面的寻找文件方法就是传入的一个函数。其余的我们就只关心方法的参数个数了,这里我们大概认为有无参,1个参数,2个参数,3个参数,4个参数。不要问理论上有无限参数怎么办,那说明你这个方法设计得太搓了。下面看代码:函数的接口定义
public interface Func<R> {
R run();
}
指定了一个返回类型的泛型
public interface Func1<T, R> {
R run(T t);
}
指定了一个参数泛型和一个返回泛型
public interface Func2<T1, T2, R> {
R run(T1 t1, T2 t2);
}
这是两个参数个数和一个返回,过程函数就少了返回而已:
public interface Proc {
void run();
}
无参
public interface Proc1<T> {
void run(T t);
}
一个参。好了,接下来我们改造上面的文件方法
public static List<File> findFiles(Func1<File, Boolean> filter)
调用同样用Lambda。
我为什么要讲这些,因为我目前比较主张回调按需监听,而不是我要用你的类,我就必须一股脑实现你的接口,然后有些不用的接口,我还必须放在那(不要说适配器模式,这个要建多少适配器)。我建议一个类或者一个方法的回调零散化,所有的回调当作是一个C#里面的代理或者是C里面的函数指针,按需传入。上面的Func和Proc就是一种通用的定义方式。
可能你的库会面临两种用户,1.先使用再看文档的用户,这种用户最喜欢一开始先找这个库的快速使用方式,然后该继承的继承,该实现接口的实现接口,他们并不知道你的库有什么必要的功能或者一些可选的功能,他们只管实现你定义的接口就好。2.与1相反的用户,这种用户使用你的类库会先了解有什么功能,然后按需添加或使用。我们今天讲的就应该是面对第二种用户。
再说说当下比较流行的链式调用,说白了就是根据你脑子里的过程,一直点点点就点完了,写起很爽,但调试有那么点点蛋疼,今天讲的这个就是链式调用的一小部分。
有点乱,这些文章本来就是记录一些零星的东西,大家看看就好~