王一三学习笔记 | Java8新特性Lambda表达式

时间:2021-05-02 18:50:43

目前,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改进的集合框架,这个下次再接着说。