- 函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。
- 2014年3月Oracle所发布的java8(jdk1.8)中加入了Lambda表达式,是一个十分重要的新特性。
以Runnable接口的实现为例
Lambda表达式
由三部分组成:一些参数、一个箭头和一段代码,格式如下:
说明:
- 参数列表就是抽象方法中的参数列表,没有就空着
- 箭头表示把参数传递给后面的方法体
- 大括号里是重写抽象方法的方法体
- Lambda的整体就和匿名内部类的整体一样,返回的是一个实现类或者子类对象,相当于:
- 省去一个实现类,用匿名内部类来完成重写,整体返回一个实现类或者子类对象
- 再省去了匿名内部类,就要用Lambda表达式来完成重写,整体也是返回一个实现类或者子类对象
有个疑惑:匿名内部类后面可以相当于实现类或者子类对象调用方法使用,但是Lambda表达式就不支持
我的理解:毕竟单独的一个Lambda根本就看不出到底是重写了哪个类的方法,所以Lambda表达式需要在特定环境中才能知道到底属于哪个对象,才能调用相应的方法。
Lambda表达式通常用来简化匿名内部类。带参带返回值的Lambda也一样:
比方说这里,只有特定的环境才知道这个Lambda表达式重写的是Comparator接口。
Lambda的省略格式
凡是根据上下文推导出来的内容,都可以省略书写(可推导即可省略)
可省略的内容有:
- 参数列表的数据类型
- 如果只有一个参数,括号也可省略
- 代码中的大括号、分号以及return关键字(这三个要省略必须一起省略,要么就别省略)
省略格式的使用前提:【必须具有接口(无论是内置接口还是自定义接口),且接口中有且仅有一个抽象方法(要满足可推导性)】,也就是必须要唯一确定。
函数式接口
- jdk8之后出现的新特性
- 函数式接口在Java中是指:有且仅有一个抽象方法的接口。
- 函数式接口中可以有其它方法包括默认、静态、私有等方法,但抽象方法只能有一个。
- 在Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
可以为接口提供一个注解:@FunctionalInterface,用来检测该接口是否是一个函数式接口。
如果是,编译成功;
如果编译失败,则说明这不是一个函数式接口。
这就不是一个函数式接口,所以报错,去掉一个抽象方法就可以啦。
函数式接口的使用
两种使用方式:
- 作为方法的参数,只要参数是一个函数式接口,就可以传递Lambda表达式
public class MyFunctionalInterfaceTest {
public static void main(String[] args) {
//传递实现类对象
show(new MyFunctionalInterfaceImpl());
System.out.println("=============================");
//直接使用匿名内部类
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("我是函数式接口的匿名内部类");
}
});
System.out.println("=============================");
//使用Lambda表达式简化匿名内部类
show(() -> {
System.out.println("我是函数式接口的Lambda表达式");
});
System.out.println("=============================");
//使用Lambda表达式简化形式
show(() -> System.out.println("我是函数式接口的Lambda表达式的简化格式"));
}
//函数式接口作为方法的参数
public static void show(MyFunctionalInterface myinter){
myinter.method();
}
}
- 作为方法的返回值类型。如果一个方法的返回值类型是一个函数式接口,那么可以直接返回一个Lambda表达式
public class LambdaPractice02 {
public static void main(String[] args) {
String[] str = {"aaa","bb","ccccccc","d"};
System.out.println(Arrays.toString(str));
//调用排序方法sort,传递返回的Lambda表达式
Arrays.sort(str,getCompartor());
System.out.println(Arrays.toString(str));
}
public static Comparator<String> getCompartor(){
/* //返回一个匿名内部类
return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
};*/
/*//也可以直接返回一个Lambda表达式
return (String o1, String o2) -> {
return o2.length() - o1.length();
};*/
//也继续简化Lambda表达式
return (o1, o2) ->o2.length() - o1.length()
}
}
既然知道了Lambda表达式的使用需要函数式接口,那么问题就来了,在开发过程中哪来那么多的函数式接口来给我们用呢?有哪些接口是函数式接口呢?这个问题似乎让Lambda表达式看起来没有什么用武之地……
老实讲,虽然JDK8提供了多个函数式接口
比如:生产型Supplier<T>接口、消费型Consumer<T>接口等、判断型Predicate<T>接口、类型转换Function<T,R>接口等
但是,我在用他们的时候觉得很绕,与其用它们来处理数据,还不如直接定义一个方法来处理。比如利用Supplier接口求数组元素最大值:
我完全可以直接定义个方法来处理,而且代码可读性更好,上面使用Lambda式让代码读起来更杂乱。
晕……那Lambda表达式有啥用???????我觉得比较好的地方在于可以简化匿名内部类,有些地方确实是会使用匿名内部类,此时就可以用Lambda表达式来替换。还是感觉用处不是很大的样子………………
还有个方法引用可以了解下,自行百度……