编程中使用Lambda表达式是典型的函数式编程风格。我的理解是,Java 8增加Lambda表达式的主要目的是简化编程,提高代码的可读性。可以想象:没有Lambda表达式的Java语言里,除了基本类型之外,一切参数都是class,都必须要有对应的class/interface的定义,哪怕只是临时使用的一次性的代码。这种情况会造成大量的boilerplate code,对程序员不够友好。而且单单从可读性来说,Lambda表达式既简洁又容易理解,使得代码的可读性大大增加。
先看一个例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class BaseController { protected ResultResponse createErrorResponse (Throwable e) { ResultResponse response = new ResultResponse (); response.setStatus(ResultStatus.failed); response.setMessageField(ResultResponseKeys.Error.name(), e.getMessage()); return response; } } public class OverviewController extends BaseController { public ResultResponse query (String timeSlot, String[] catalogs) { try { ResultResponse resultResponse = new ResultResponse (ResultStatus.success); for (String catalog : catalogs) { String result = overviewHandler.query(OverviewCatalog.valueOf(catalog), timeSlot); resultResponse.setMessageField(catalog, result); } return resultResponse; } catch (Exception e) { return this .createErrorResponse(e); } } public ResultResponse listCatalog () { try { ResultResponse resultResponse = new ResultResponse (ResultStatus.success); resultResponse.setMessageField("catalogs" , this .overviewHandler.getCatalogs()); return resultResponse; } catch (Exception e) { return this .createErrorResponse(e); } } }
有如上的这样一组方法,方法的基本逻辑都是做一些操作返回ResultResponse类型的对象,当发生异常时,构建一个表达异常的ResultResponse对象并返回。诚然,我们可以在这种类的每个方法里面,每次都写一个”try… catch…”,但是这样的做法显然不符合DRY原则(Note: Literal repeat is repeat, structural repeat is still repeat. 而解决后者是函数式编程语言的强项 )。在函数式编程语言中,解决这个问题很简单:只要定义一个统一处理函数,它接受一个业务函数作为参数,在它的内容里面去执行传入的业务函数并使用”try…catch…”来处理异常情况,然后每一个具体的业务方法提供业务函数的实现,再将业务函数的实现作为参数调用统一处理函数即可。但在Java语言里却很难有这么简洁的实现方法,直到Java支持了Lambda表达式。
我的第一直觉是这么做的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public interface JobExecutor <T> { public T execute () throws Exception; } public class BaseController { protected ResultResponse createErrorResponse (Throwable e) { ResultResponse response = new ResultResponse (); response.setStatus(ResultStatus.failed); response.setMessageField(ResultResponseKeys.Error.name(), e.getMessage()); return response; } public ResultResponse execute (JobExecutor<ResultResponse> executor) { try { return executor.execute(); } catch (Exception e) { return this .createErrorResponse(e); } } public class OverviewController extends BaseController { public ResultResponse query (String timeSlot, String[] catalogs) { return this .execute(() -> { ResultResponse resultResponse = new ResultResponse (ResultStatus.success); for (String catalog : catalogs) { String result = overviewHandler.query(OverviewCatalog.valueOf(catalog), timeSlot); resultResponse.setMessageField(catalog, result); } return resultResponse; }); } public ResultResponse listCatalog () { return this .execute(() -> { ResultResponse resultResponse = new ResultResponse (ResultStatus.success); resultResponse.setMessageField("catalogs" , this .overviewHandler.getCatalogs()); return resultResponse; }); } }
代码简洁了很多。代码简洁的意义不仅在于代码量的减少,更在于可读性的增加和可维护性的大大提高。
但改完之后,我觉得还有一个问题,就是新增的”JobExecutor”类。这个接口类本身其实只是提供了一个方法签名。而在Java中使用Lambda表达式的场景里一定会大量用到这样的类。所以感觉上,这种类应该由JDK来提供。我google了一下,果然如此。请参考这里 。JDK提供了各种签名的接口以供类似情况的使用,具体请参考这里 。
最终代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import java.util.function.Supplier;public class BaseController { protected ResultResponse createErrorResponse (Throwable e) { ResultResponse response = new ResultResponse (); response.setStatus(ResultStatus.failed); response.setMessageField(ResultResponseKeys.Error.name(), e.getMessage()); return response; } public ResultResponse execute (Supplier<ResultResponse> executor) { try { return executor.get(); } catch (Exception e) { return this .createErrorResponse(e); } } } public class OverviewController extends BaseController { public ResultResponse query (String timeSlot, String[] catalogs) { return this .execute(() -> { ResultResponse resultResponse = new ResultResponse (ResultStatus.success); for (String catalog : catalogs) { String result = overviewHandler.query(OverviewCatalog.valueOf(catalog), timeSlot); resultResponse.setMessageField(catalog, result); } return resultResponse; }); } public ResultResponse listCatalog () { return this .execute(() -> { ResultResponse resultResponse = new ResultResponse (ResultStatus.success); resultResponse.setMessageField("catalogs" , this .overviewHandler.getCatalogs()); return resultResponse; }); } }
如果非要说Java Lambda表达式的缺点,我想最主要的就是:Java本身是一种vorbose的基于class的静态类型语言,它的Lambda表达式的实现本质上是一种语法糖(syntactic sugar)。为了实现这种语法糖,Java VM做了大量的背后工作(比如”在运行期生成接口的相关实现类 “),而这其中的原理并不是一目了然的,这一点对初学者容易造成理解上的困难。相比而言,函数式编程语言中的lambda表达式的原理就很简单且容易理解。不过对Java来说,这也是没有办法的办法吧!