Java8发布了一系列高效的操作方式,其中lambda就是一个很重要的特性。譬如我们可以利用lambda代替匿名内部类,可以更方便的创建线程,更方便的使用接口。同时Java8还结合lambda定义了一系列常用且高效的api,如forEach,Stream,Optional等等。
Lambda的起源
Lambda起源于20世纪40年代,是一种数学表达式λ,也是一种函数演算。这在和面向对象,面向过程并称三大编程方式的函数式编程中用的极为广泛。
其实不止Java,C++也早已引入了Lambda编程,同时学习Lambda我们要知道λ的始祖是Lisp语言,它的出现要早于C和Java。
我们可以称lambda为函数式编程,什么是函数式编程呢?这个要从λ演算说起。lambda演算要求一切皆函数,参数是函数,返回值也是函数。有这个特点之后,就会给我们编程带来很大的便捷性。假如说我们方法的参数可以是函数,那么我们就可以把只有一个方法的接口作为参数传递到函数中,再进一步来说,我们就可以通过lambda演算来代替匿名内部类,这也是lambda演算在Java中最重要的一个应用。
Lambda的使用
对于Java8来说,它提供了三个基础的函数式接口,分别是Consumer
,Supplier
,Function
,这三个接口场景不同,分别对应着消费,生产和函数,这三个接口在Java的java.util.function包中
1. Function
这个是最经典的函数式接口,它的作用就表现出了函数根本的作用:输入入参,返回出参,即:R apply(T t)
。最常见的使用方式如下:
1 | // 因为只有一个入参,所以第一个括号中需要写一个参数,且类型为T |
我们知道juf包中也有一个比较重要的函数式接口:Predicate
,它的作用是输入入参,返回布尔值,即:boolean test(T t)
。乍一看是一个新接口,其实它只不过是Function
的特殊形式,下面的两个代码块作用是一样的:
1 | Predicate<String> predicate = (t) -> "test".equals(t); |
在JDK自带的包中,也有很多使用到Function
接口的方法,如我们在使用Stream
时经常希望拿到list中对象的某一字段,就会使用Stream#map(Function mapper)
,它通过map这个接口,将我们的参数进行了转化。
除了Predicate
之外,juf还对Function
做了其他的延伸,如BiFunction
,ToDoubleFunction
,ToDoubleBiFunction
等等,大家可以自行下去了解一下
2. Consumer
Consumer
对应着消费者,从字面意思来理解它的功能,应该是只有入参,没有出参的函数式接口:void accept(T t)
。最常见的使用方式如下:
1 | // 因为只有一个入参,所以第一个括号中需要写一个参数,且类型为T |
Consumer
也在JDK自带的很多包中使用,如我们常用的Iterable#forEach(Consumer action)
,它的作用就是传入集合中的元素,然后进行处理,不进行输出。除此之外,Optional#ifPresent(Consumer consumer)
也很好的解决了NPE的问题
同Function
一样,juf也对Consumer
做了相当多的扩展,如BiConsumer
, DoubleConsumer
等等
3. Supplier
Supplier
跟Consumer
是一对,Supplier
对应着生产者,它跟Consumer
恰好相反,没有函数入参,只有函数出参:R get()
。最常见的使用方式如下:
1 | // 因为没有入参,所以第一个括号中不应该有参数 |
相信大家在代码开发的过程中都非常恶心NPE,所以JDK提供了Optional
。Optional
会通过Supplier
来对NPE的异常进行重新抛出: Optional#orElseThrow(Supplier exception)
,或者是通过Optional#orElseGet(Supplier other)
去获得另一个非空的参数,这几个还是很不戳的
4. Custome
了解了上面的三种基础函数式接口后,我们甚至也可以自定义一些我们需要的函数式接口,如Comparator#compare(T o1, T o2)
,下面可以试着自定义一个
1 |
|
Lambda与设计模式
我们在日常开发工作中,常见的设计模式如策略模式,单例模式,工厂模式,模板方法模式,建造者模式,代理模式,观察者模式,责任链模式等等,我们如果把Lambda看成函数级别的接口的话,会大大简化程序的代码量的(其实也就是通过简化类的创建来简化代码量)
1. 责任链模式
1 | class ChainHandler { |
2. 观察者模式
1 | class Observer { |
3. 策略模式
1 | public String getSuitableEle(List<String> list, Predicate<String> strategy) { |
后记
Java中的lambda我自己之前用的时候仅限于调用Stream,Optional,forEach等JDK原生的接口,从来没有自己设计过对应的lambda,这次总结一下,也算是填补了之前的一个大空白