一、Lambda表达式的概念
在Java8语言中引入了Lambda表达式,基于操作符" -> "实现,该操作符被称为Lambda操作符或箭头操作符;
Lambda表达式左侧:指定了Lambda表达式需要的参数列表,对应接口的抽象方法的形参列表;
Lambda表达式右侧:指定了Lambda体,即Lambda表达式要执行的功能,对应接口的抽象方法的实现逻辑;
Lambda表达式本身是一个匿名方法,常用于实现接口的抽象方法,然后生成接口实例赋值给接口变量或生成匿名实例直接赋值给函数传参,可以使代码形式更简洁、更灵活;
- 样例1
/// 常规表达
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("Lambda");
}
};
new Thread(runnable1).start();
/// Lambda表达式:匿名方法 -> 接口实例
Runnable runnable2 = () -> System.out.println("Lambda");
new Thread(runnable2).start();
/// Lambda表达式:匿名方法 -> 匿名实例
new Thread(() -> System.out.println("Lambda")).start();
- 样例2
/// 常规表达
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer num1, Integer num2) {
return Integer.compare(num1, num2);
}
};
int result1 = com1.compare(99, 100);
System.out.println(result1);
/// Lambda表达式:匿名方法 -> 接口实例
Comparator<Integer> com2 = (num1, num2) -> Integer.compare(num1, num2);
int result2 = com2.compare(99, 100);
System.out.println(result2);
二、Lambda表达式的使用
1、Lambda无参数,无返回值
@Test
public void test() {
new Thread(() -> System.out.println("Lambda")).start();
}
2、Lambda有参数,无返回值
3、Lambda参数类型可以省略,因为编译器可以“类型推断”
@Test
public void test() {
Consumer<String> consumer = (s) -> System.out.println(s);
consumer.accept("Lambda");
}
4、Lambda一个参数时,其外面的小括号可以省略
5、 Lambda需要多个参数,多条语句,有返回值
@Test
public void test() {
Comparator<Integer> comparator = (num1, num2) -> {
......
return num1.compareTo(num2);
};
System.out.println(comparator.compare(100, 99)); //100 99 1
}
6、Lambda体只有一条语句时,return 与大括号都可省略
@Test
public void test() {
Comparator<Integer> comparator = ((num1, num2) -> num1.compareTo(num2));
System.out.println(comparator.compare(99, 100)); //1
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("Lambda"); //Lambda
}
三、Lambda表达式的实战分析
这里基于Nacos2.4.2的源码文件ExternalConfigInfoPersistServiceImpl.java,对Lambda表达式的实战应用进行分析,代码如下:
- 实战1
protected TransactionTemplate tjt;
/**
* 新增配置信息
*/
@Override
public ConfigOperateResult addConfigInfo(final String srcIp, final String srcUser, final ConfigInfo configInfo,
final Map<String, Object> configAdvanceInfo) {
/// TransactionCallback的Lambda表达式执行事务
return tjt.execute(status -> {
try {
// 插入配置信息
long configId = addConfigInfoAtomic(-1, srcIp, srcUser, configInfo, configAdvanceInfo);
String configTags = configAdvanceInfo == null ? null : (String) configAdvanceInfo.get("config_tags");
// 插入配置标签
addConfigTagsRelation(configId, configTags, configInfo.getDataId(), configInfo.getGroup(), configInfo.getTenant());
Timestamp now = new Timestamp(System.currentTimeMillis());
// 插入历史配置信息
historyConfigInfoPersistService.insertConfigHistoryAtomic(0, configInfo, srcIp, srcUser, now, "I");
ConfigInfoStateWrapper configInfoCurrent = this.findConfigInfoState(
configInfo.getDataId(), configInfo.getGroup(), configInfo.getTenant());
if (configInfoCurrent == null) {
return new ConfigOperateResult(false);
}
return new ConfigOperateResult(configInfoCurrent.getId(), configInfoCurrent.getLastModified());
} catch (CannotGetJdbcConnectionException e) {
LogUtil.FATAL_LOG.error("[db-error] " + e, e);
throw e;
}
});
}
上述代码的 tjt.execute(status -> {…}); 其传参即为实现接口TransactionCallback抽象方法 T doInTransaction(TransactionStatus status);的Lambda表达式。其中,execute()函数的原型如下:
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
// action指向Lambda定义的匿名实例
return (T)((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
} else {
// 生成Lambda表达式要使用的传参status
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
// action指向Lambda定义的匿名实例,这里直接调用了Lambda定义的匿名函数doInTransaction(status), status为传参,由调用匿名函数的地方生成(如这里),result为返还值。
result = (T)action.doInTransaction(status);
} catch (Error | RuntimeException ex) {
this.rollbackOnException(status, ex);
throw ex;
} catch (Throwable ex) {
this.rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
TransactionCallback接口的定义如下:
@FunctionalInterface
public interface TransactionCallback<T> {
@Nullable
T doInTransaction(TransactionStatus status);
}
样例1中的 status -> {…} 即为抽象方法 T doInTransaction(TransactionStatus status);的实现主体。
- 实战2
/**
* 插入配置信息
*/
@Override
public long addConfigInfoAtomic(final long configId, final String srcIp, final String srcUser,
final ConfigInfo configInfo, Map<String, Object> configAdvanceInfo) {
ConfigInfoMapper configInfoMapper = mapperManager.findMapper(
dataSourceService.getDataSourceType(), TableConstant.CONFIG_INFO);
KeyHolder keyHolder = ExternalStorageUtils.createKeyHolder();
try {
// 插入配置信息
jt.update(
// TODO 运行时, 传参connection从哪里传送进来的 ???JdbcTemplate.execute()执行过程中,通过
// Connection con = DataSourceUtils.getConnection(this.obtainDataSource());获取连接并传进来,
// 更一般的,Lamba表达式的传参是在调用匿名函数的地方传进来的 !!!
connection -> createPsForInsertConfigInfo(
srcIp, srcUser, configInfo, configAdvanceInfo, connection, configInfoMapper
),
keyHolder);
Number number = keyHolder.getKey();
if (number == null) {
throw new IllegalArgumentException("insert config_info fail");
}
return number.longValue();
} catch (CannotGetJdbcConnectionException e) {
LogUtil.FATAL_LOG.error("[db-error] " + e, e);
throw e;
}
}
上述代码的 jt.update(connection -> …, keyHolder); 即为接口PreparedStatementCreator的抽象方法createPreparedStatement(Connection con)的实现主体。JdbcTemplate.update()的原型和接口PreparedStatementCreator的定义分别如下:
public int update(final PreparedStatementCreator psc, final KeyHolder generatedKeyHolder) throws DataAccessException {
Assert.notNull(generatedKeyHolder, "KeyHolder must not be null");
this.logger.debug("Executing SQL update and returning generated keys");
return updateCount((Integer)this.execute(psc, (ps) -> {
int rows = ps.executeUpdate();
List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
generatedKeys.clear();
ResultSet keys = ps.getGeneratedKeys();
if (keys != null) {
try {
RowMapperResultSetExtractor<Map<String, Object>> rse = new RowMapperResultSetExtractor(this.getColumnMapRowMapper(), 1);
generatedKeys.addAll((Collection)result(rse.extractData(keys)));
} finally {
JdbcUtils.closeResultSet(keys);
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("SQL update affected " + rows + " rows and returned " + generatedKeys.size() + " keys");
}
return rows;
}, true));
}
@FunctionalInterface
public interface PreparedStatementCreator {
PreparedStatement createPreparedStatement(Connection con) throws SQLException;
}
四、关于Lambda表达式的思考和总结
1、Lambda表达式本身在形式上是一个匿名方法,用于实现接口的抽象方法,最后以生成接口实例或生成匿名实例的方式使用;
2、生成的接口实例或匿名实例在最终使用时,还是以调用接口实例的抽象方法的方式使用的,如上述“实战1”中的 result = (T)action.doInTransaction(status);
3、Lamba表达式的传参的实际值是在调用接口实例的匿名函数的地方传进来的,使用Lambda表达式的地方只是定义了一个方法,并不传入实际参数;
1315

被折叠的 条评论
为什么被折叠?



