这里介绍过一些lamda表达式的基本用法。

这一篇谈一下自己对lamda表达式的一些感悟。

 

1.困惑

不知道大家有没有这种感觉,看源码尤其是一些框架代码,只要是有lamda表达式或者匿名内部类的地方,就容易头晕,经常看着看着就晕了。。。

之前看公司框架层代码的时候差点晕死。。。

这是为啥?不都TM是代码吗?

我想过这个问题,可能是这个原因。

在没有lamda表达式(包含匿名内部类)的时候,我们都是顺着一个函数一直往下看的,也就是说是按照一个完整的调用链在看,在一个函数里发生了一次调用,我们可以看到调用的函数名,传入的参数,获取的返回值。这是一个很正常的逻辑。

但是有了lamda表达式呢?

可以举个例子,下面是一段spring jdbcTemplate的代码:

@Nullable
public <T> T query(PreparedStatementCreator psc, @Nullable final PreparedStatementSetter pss, final ResultSetExtractor<T> rse) throws DataAccessException {
Assert.notNull(rse, "ResultSetExtractor must not be null");
this.logger.debug("Executing prepared SQL query");
return this.execute(psc, new PreparedStatementCallback<T>() {
@Nullable
public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
ResultSet rs = null;

Object var3;
try {
if (pss != null) {
pss.setValues(ps);
}

rs = ps.executeQuery();
var3 = rse.extractData(rs);
} finally {
JdbcUtils.closeResultSet(rs);
if (pss instanceof ParameterDisposer) {
((ParameterDisposer)pss).cleanupParameters();
}

}

return var3;
}
});
}

这一看是不是又有点晕?

lamda表达式与一般的函数调用不一样,它本质是一个匿名内部类,但是这里不说底层实现,直说应用层面的。当我们看到了一个lamda表达式时,我们还不知道它何时被调用,需要点到将它作为入参的函数里才能知道调用情况,比如传了什么参数,返回值怎么用的等等。这就与之前的顺序完全相反了。

之前,我们都是先看到调用点,如果感兴趣再点进去看具体实现。

这下倒好,有了lamda表达式,更常见的情况是,先看到了函数的实现,却不知道它是怎么被调用的,需要返回到将lamda表达式作为入参的函数里才行,这时可能又忘记了lamda表达式是怎么实现的了,还得点回来。所以看到lamda表达式会比较晕,因为它不符合我们之前的阅读习惯。明白了这一点,以后阅读lamda表达式可能会好点。

 

2.为什么要用lamda表达式?

java没出现lamda表达式的时候不也好好的吗?

这个问题等价于:为什么要用接口或者匿名内部类?

我们设计一个函数或者模块时,如果想留下一些可定制的或者扩展的点,往往就需要匿名内部类,说白了就是抽象。这个其实就是模板设计模式。我设计一个函数,它执行若干步骤,然后返回一个结果。但是其中某些步骤,我不写死,而是作为扩展点让调用函数的人来定制。这个定制体现在两点:

1)我写代码时,针对这个扩展点,我不用具体类型,只是调用一个接口;

2)这个接口是我的方法的参数,调用方可以通过匿名内部类提供一个接口的实现来定制。

也就是我完成的这个函数可以按照调用方的意愿来定制。

很多框架都是这种模式,像spring,stream,listener等等。

有了lamda表达式总比直接用匿名内部类在代码上简洁了很多(我不觉得理解上简单,毕竟匿名内部类我可以直接看到参数类型)。