Lambda表达式的概念和使用

一、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表达式的地方只是定义了一个方法,并不传入实际参数;

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值