王一三学习笔记 | 什么是Lambda表达式
目前,Java 8已经被广泛的使用。Java 8的一大亮点是引入了Lambda表达式。对于不了解Lambda表达式的程序员来说,使用Lambda表达式的难度还不小。很多程序员认为,Lambda表达式难于阅读,维护起来成本很大,Java 8为什么要引入这个东东?
其实引入Lambda表达式的目的是要去掉JAVA语法中过于冗余的代码,让代码更加简洁,所以认为Lambda表达式难于阅读是因为你还不懂Lambda表达式的语法。下面我们先看一个使用Lambda表达式例子:
// Java 8之前:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8, too much code for too little to do");
}
}).start();
//Java 8方式:
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
通过上面例子,可以看面,Java的对象比较“重量级”,其实真正有用的代码就一行,但还是要实例化一个类,但上面的例子中,代码是少了,但是也看不懂了。那我们先来了解一下Lambda表达式。
Lambda表达式不是Java发明的概念,在其它的编程语言中早已使用,是因为确实可以简化代码加快开发效率被Java添加进来的。Lambda表达式本质上是一个匿名方法。下面让我们看一下例子:
public int add(int x, int y) {
return x + y;
}
转成Lambda表达式就是:
(int x, int y) -> x + y;
参数类型也可以省略,Java编译器会根据上下文推断出来,写成如下的形式:
(x, y) -> x + y;或者 (x, y) -> { return x + y; }
可见Lambda表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。
上面例子里的Lambda表达式没有参数,也没有返回值(相当于一个方法接受0个参数,返回void,其实就是Runnable里run方法的一个实现):
() -> { System.out.println("Hello Lambda!");
如果只有一个参数且可以被Java推断出类型,那么参数列表的括号也可以省略:
c -> { return c.size(); }
上面的例子中,除了用到了Lambda表达式,还用到了Functional Interface(函数式接口,以下简称FI),FI的定义其实很简单:任何接口,如果只包含唯一一个抽象方法,那么它就是一个FI。为了让编译器帮助我们确保一个接口满足FI的要求(也就是说有且仅有一个抽象方法),Java8提供了@FunctionalInterface注解。下面是Java SE 7中已经存在的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.beans.PropertyChangeListener
除此之外,Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,例如:
Predicate——接收T对象并返回boolean
Consumer——接收T对象,不返回值
Function——接收T对象,返回R对象
Supplier——提供T对象(例如工厂),不接收值
UnaryOperator——接收T对象,返回T对象
BinaryOperator——接收两个T对象,返回T对象
除了上面的这些基本的函数式接口,我们还提供了一些针对原始类型(Primitive type)的特化(Specialization)函数式接口,例如IntSupplier和LongBinaryOperator。(我们只为int、long和double提供了特化函数式接口,如果需要使用其它原始类型则需要进行类型转换)同样的我们也提供了一些针对多个参数的函数式接口,例如BiFunction,它接收T对象和U对象,返回R对象。
通过上面的介绍,是不是可以理解上面例子的代码了?有不了解的给我留言,
Java中除了在函数式接口中使用lambdas表达式,还有使用lambda表达式的方法引用和使用lambda改进的集合框架,这个下次再接着说。