Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Лямбда Java 8 и расширение интерфейсов с абстрактным классом

Автор вопроса: jeremijaОтветов: 3

Скажем, я хочу объявить 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 с помощью лямбда-выражений? Это вообще возможно?

javaspringjava-8lambda

Ответы

Ответ 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, я склонен думать, что это связано с тем, как выводятся типы лямбдов.

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы