Java 8 lambda和带抽象类的接口扩展

时间:2014-06-20 09:24:52

标签: java spring lambda java-8

假设我想声明Spring的RowMapper,但不创建动态类,而是实现一个实现RowMapper的抽象类。这是我的方法签名:

SqlProcedure#declareRowMapper(RowMapper<?> rowMapper);

CustomRowMapper.java:

public abstract class CustomRowMapper<T> implements RowMapper<T> {
    protected A a = new A();
}

旧的Java方式是写:

sqlProc.declareRowMapper(new CustomRowMapper<Object>() {
    @Override
    public Object mapRow(ResultSet rs, int rowNum) {
        a.doSomething(rs, rowNum);
        return new Object();
    }
});

是否可以使用lambda表达式实现相同的功能?我想做这样的事情:

sqlProc.declareRowMapper((rs, rowNum) -> {
    a.doSomething(rs, rowNum);
    return new Object();
});

但是我会收到编译错误a cannot be resolved。这是因为Java认为这是RowMapper#mapRow方法的实现,而不是CustomRowMapper#mapRow

如何通过lambda表达式告诉Java使用CustomRowMapper而不是RowMapper?这甚至可能吗?

3 个答案:

答案 0 :(得分:12)

Lambdas无法实现抽象类。 Here is why

文章中提到了一些解决方法,但在您尝试引用对象字段时,它不适用于您的情况。除了坚持老式的匿名课程,你能做的就是思考如何将“注入”给lamda,例如:

  • 实例化lambda中的对象;
  • 创建lambda范围的一部分;
  • 制作某种单音。

答案 1 :(得分:9)

您可以扩展功能界面并创建自己的界面:

@FunctionalInterface
public interface CustomRowMapper<T> implements RowMapper<T> {
    static A a = new A();
}

然后,您可以传递一个lambda,这是CustomRowMapper#mapRow()方法的实现,如下所示:

CustomRowMapper myCustomRowMapperLambda = (rs, rowNum) -> {
    a.doSomething(rs, rowNum);
    return new Object();
};
sqlProc.declareRowMapper(myCustomRowMapperLambda);

答案 2 :(得分:3)

这应该有效:

sqlProc.declareRowMapper((rs, rowNum) -> {
    new A().doSomething(rs, rowNum);
    return new Object();
});

你必须实例化你的对象A.鉴于你所展示的代码,这不会改变一件事。

回答更一般的问题而不仅仅依赖于例子: 即使使用演员你也无法访问私有变量A,我倾向于认为这是由于lamdbas的类型是如何被感染的。

事实上,我认为这并不是一件好事:一个lambda应该是无国籍的。 (你可以使用上下文使其有状态,但这不是我推荐的内容。)