Подтвердить что ты не робот

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();
    }
});

Можно ли добиться того же самого результата с лямбда-выражениями? Я хотел бы сделать что-то вроде этого:

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

Но тогда я получу ошибку компиляции, говоря a cannot be resolved. Это потому, что Java рассматривает это как реализацию метода RowMapper#mapRow, а не CustomRowMapper#mapRow.

Как я могу сказать Java использовать мой CustomRowMapper вместо RowMapper через лямбда-выражения? Возможно ли это?

4b9b3361

Ответ 1

Вы можете расширить функциональный интерфейс и создать свой собственный:

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

Затем вы можете передать лямбду, которая является реализацией метода CustomRowMapper#mapRow() следующим образом:

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

Ответ 2

Lambdas не может реализовать абстрактные классы. Вот почему.

Существует обходное решение, упомянутое в статье, но оно не будет работать в вашем случае при попытке ссылаться на поле объекта. То, что вы можете сделать, помимо того, что придерживаетесь анонимных классов старой моды, - это подумать о том, как "вводить" А в ламу, например:

  • создать экземпляр объекта внутри лямбда;
  • создать объект лямбда-области;
  • сделать один одиночный.

Ответ 3

Это должно работать:

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

Вам нужно будет создать экземпляр вашего объекта A. Учитывая, что код, который вы показываете, ничего не изменит.

Чтобы ответить на более общий вопрос, не только опираясь на пример: Даже с актом вы не будете иметь доступа к частной переменной A, я склонен думать, что это связано с тем, как выписываются типы ламб.

И на самом деле я не думаю, что это шутливо: Лямбда должна быть без гражданства. (Вы можете сделать это с учетом контекста, но это не то, что я бы рекомендовал).