Скажем, я хочу объявить 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 с помощью лямбда-выражений? Это вообще возможно?
Ответ 1 · рейтинг 9 · Konstantin Yovkov
Вы можете расширить функциональный интерфейс и создать свой собственный:
@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 · рейтинг 12 · user2418306
Лямбды не могут реализовывать абстрактные классы. и вот почему.
В статье упоминается обходной путь, но он не будет работать в вашем случае, поскольку вы пытаетесь сослаться на поле объекта. Что вы можете сделать, кроме того, что придерживаетесь старомодных анонимных классов, так это подумать, как "внедрить" A в лямбду, например:
- создать экземпляр объекта внутри лямбды;
- создать A вне лямбда-области;
- сделать синглтон какой-то.
Ответ 3 · рейтинг 3 · benzonico
Это должно работать:
sqlProc.declareRowMapper((rs, rowNum) -> {
new A().doSomething(rs, rowNum);
return new Object();
});
Вам нужно будет создать экземпляр вашего объекта A. Учитывая код, который вы показываете, это ничего не изменит.
Чтобы ответить на более общий вопрос, не полагаясь исключительно на пример: даже с приведением вы не получите доступ к частной переменной A, я склонен думать, что это связано с тем, как выводятся типы лямбдов.
И на самом деле я не думаю, что это желательно для: лямбда должна быть без гражданства. (Вы можете сделать это с учетом контекста, но я бы не рекомендовал это делать).