函数是一个数学上的概念,表示一个集合和另一个集合的映射关系,这种关系我们在编程的时候通过箭头函数((input)->{expression})来表示,就是函数式编程。箭头的左边表示输入集合,右边表示这种映射关系,最终整个函数的结果代表函数表达式的输出。
关于函数表达式的一些概念(纯函数、函数副作用、合成柯里化)这里就不做详细介绍了,因为我觉得在java中使用lambda表达式,理解上一段落就可以了,以个人在目前实践中的经验来看不可避免会有函数副作用,主要是指在对集合的迭代操作的时候。
在java中函数式编程在两个地方使用起来很方便,一个是匿名函数,一个是集合的stream操作。
本文主要介绍匿名函数,匿名函数。
函数式接口:只有一个方法的接口。只要是函数式接口,都可以通过匿名函数来实现。例如java多线程的接口:
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Runable接口只有一个方法,那就是run,像这样的接口都可以通过匿名函数实现,下面分别展示了通过匿名类和匿名函数来实现多线程的例子:
Thread
//匿名类
Thread anonymousClassThread=new Thread(new Runnable() {
@Override
public void run() {
int count=1;
while (count<5){
System.out.println("anonymousClassThread:"+count);
count++;
try {
Thread.sleep(1000);
}catch (InterruptedException e){
}
}
}
});
//匿名函数
Thread anonymousFunctionThread=new Thread(()->{
int count=1;
while (count<5){
System.out.println("anonymousFunction:"+count);
count++;
try {
Thread.sleep(100);
}catch (InterruptedException e){
}
}
});
anonymousClassThread.start();
anonymousFunctionThread.start();
可以看出相对于匿名类的使用,匿名函数在使用上更加直观、简洁、也很易用。从这个例子上也可以看出最好在实现匿名函数的时候养成把函数写成纯函数的好处,那就是栈信息全部在函数内部,如果在不是纯函数,就会在多线程中引发同步的相关的问题。
也可以在平时的实践中,定义一些函数式接口,通过匿名函数轻便实现该接口:
interface IFunctionCase{
void func(String arg);
}
class FunctionCaseClass{
public void funcTest(IFunctionCase f){
System.out.println("before");
f.func("test");
System.out.println("after");
}
}
通过匿名函数轻松实现接口:
FunctionCaseClass functionCaseClass=new FunctionCaseClass();
functionCaseClass.funcTest((arg)->System.out.println("a "+arg));
functionCaseClass.funcTest((arg)->System.out.println("b "+arg));
在java.util.function中,也有一些内置的函数式接口,这些函数式接口在jdk内置的lambda表示中被广泛的使用,主要包含下面四类:
1.Function 返回一个新值
2.Consumer 不返回值
3.Supplier 没有输入,返回一个
4.Predicate 返回一个布尔值
带Bi前缀的表示有多个输入的场景
网友评论