Lambda初探
(a, b) -> a + b
上述是Lambda的基本语法,这是一种函数式编程的思想,是Java8引入的一个新概念,也叫做匿名函数。当然这并不是Java独有,比如Javascript在ES6规范中引入的箭头函数,也是lambda的运用。
何为匿名函数
说到匿名,首先想到的是java中的匿名类和匿名对象,比如我们简单的创建线程的方法:
class MyThread implements Runnable{
@Override
public void run() {
System.out.println("hello lambda");
}
...
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
通过自定义类实现Runnable,并实现其中的run方法,即可创建新的线程。但是如果上述线程只是使用一次,那么自定义类MyThread
和对象mythread
就显得有点鸡肋。
有的时候我们只是单纯的想新建一个线程来执行我们的方法,但是又不想像上面那样新建一个类并创建对象,那么使用以下方式:
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("hello lambda");
}
}).start();
相较于之前的方式,上述代码明显简洁了很多,这里运用到的就是匿名对象。
观察上述代码,我们只想要的是一个新的Thread
来执行我们System.out.println("hello lambda")
方法,而其他的比如方法名是啥,我们其实都不关心,其实可以使用以下方式:
new Thread(() -> System.out.println("hello lambda")).start();
相较于之前,代码变得更简洁和灵活,这里使用的就是匿名函数。匿名对象是没有名称的对象,同理,匿名函数,就是没有声明名称的函数方法,而Lambda表达式就是表示匿名函数的一种方式:没有名称,但是有参数列表和函数主体。
Lambda表达式
在前面我们可以看到,使用匿名类需要写一些笨重的代码,显得繁琐的冗长。通过Lambda表达式,可以更优雅的实现我们的目的。比如利用Lambda可以简洁的定一个Comparator对象。
现在有Apple
这个类:
public Class Apple{
private int weight;
public int getWeight(){
return weight;
}
}
想要按照weight对Apple排序,可以使用匿名类的方式:
List<Apple> appleList = new ArrayList();
...
appleList.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple, a2)(
return a1.getWeight().compareTo(a2.getWeight());
)
})
使用了Lambda之后:
appleList.sort((Apple a1, Apple, a2) -> a1.getWeight().compareTo(a2.getWeight());
很明显,代码看起来更清晰了。下面,来看一看上述代码中Lambda的基本结构:
(Apple a1, Apple, a2) -> a1.getWeight().compareTo(a2.getWeight()
Lambda表达式由三个部分组成:
- 参数——使用Comparator中的compare方法的参数,传入两个苹果
- 箭头——将参数和主体分隔开
- Lambda主体——方法主体,比较两个苹果的重量,表达式也就是Lambda的返回值,返回类型为compare方法的返回值类型
可以看到,Lambda表达式语法很简单,不过,什么时候可以用Lambda呢。
上面的Runnable,Comparator
有一个相似点:都是接口,而且都只定义了一个抽象方法,这类接口叫做函数式接口。虽然Java8之后接口可以有默认方法,但只要接口只定义了一个抽象方法,就仍然是一个函数式接口,而Lambda表达式可以理解为函数式接口的一个具体实现的实例。
方法引用
Lambda已经很好的简化了我们的代码,但是,能否更简化呢?
答案是可以的,比如上文中的
(Apple a1, Apple, a2) -> a1.getWeight().compareTo(a2.getWeight()
可以简化为:
comparing(Apple::getWeight)
这样代码可读性似乎更高,明确表达了我们想通过Apple
的getWeight
来比较大小,这种写法叫做方法引用。
方法引用可以看作仅仅调用特定方法的Lambda的一种快捷写法。它的思想是:如果一个Lambda是直接调用某个现有的方法,那么最好是直接通过方法名去调用它,而不是描述如何去调用它。例如,上文中的Apple::getWeight
,就是使用分隔符::
来引用Apple
类的getWeight
方法,下面是一些Lambda的方法引用写法:
(Apple a) -> a.getWeight()
Apple::getWeight
(String s) -> System.out.println(s)
System.out::println
(str, i) -> str.substring(i)
String::substring
方法引用可以看作是针对一些仅设计单一方法的Lambda的语法糖,让我们在某些时候能够用更少的代码更好的表达我们的想法。
参考:《Java 8 实战》