Наследование @FunctionalInterface

Скажем, у меня есть следующий интерфейс:

@FunctionalInterface
public interface First {
   int fun(int a);
}

а также

@FunctionalInterface
public interface Second extends First {
   default int fun(int a) { fun(a, a); }

   int fun(int a, int b);
}

Затем, если у меня где-то есть метод, который принимает First, я могу сделать, например:

methodThatTakeFirst(val -> val + 1);

Но я также хочу иметь возможность передавать Second, например:

methodThatTakeFirst((v1, v2) -> v2 * v2);

Однако это работает только в том случае, если я использую лямбду следующим образом:

methodThatTakeFirst((Second) (v1, v2) -> v2 * v2);

Мой вопрос: есть ли способ разработать этот шаблон без необходимости приведения лямбда-выражений к субинтерфейсу? Или что было бы самым элегантным способом справиться с этими сценариями?


person AndresQ    schedule 07.11.2017    source источник
comment
...Зачем тебе это? Какой цели это послужило бы? Почему бы вам просто не определить default функции в вашем функциональном интерфейсе для обработки дополнительного поведения вместо того, чтобы навязывать то, что выглядит как ненужное наследование?   -  person Makoto    schedule 08.11.2017
comment
Без приведения компилятор не может сделать вывод, что вам нужна лямбда-реализация Second. Приведение типов — лучший/самый простой способ сообщить об этом компилятору, поэтому приведение типов является наиболее элегантным способом справиться с этим сценарием.   -  person Andreas    schedule 08.11.2017
comment
@Makoto хорошая мысль, предположим, что First из библиотеки, которую нельзя изменить, но можно расширить.   -  person AndresQ    schedule 08.11.2017
comment
Даже если First нельзя изменить, что дает передача реализации Second, особенно лямбда-выражения? Единственное, что метод methodThatTakeFirst() может разумно сделать со своим аргументом, — это вызвать метод fun(int a), который по умолчанию используется в Second. Вам лучше определить конкретную реализацию First и передать ее обычный экземпляр.   -  person John Bollinger    schedule 08.11.2017
comment
иногда я хочу передать лямбду, которая использует оба параметра, иногда только один   -  person AndresQ    schedule 08.11.2017


Ответы (2)


Вы можете перегрузить methodThatTakeFirst, чтобы он также принимал экземпляр Second в качестве аргумента, и делегировать methodThatTakeFirst(First first):

void methodThatTakeFirst(First first) {
    // play with first
}

void methodThatTakeFirst(Second second) {
    methodThatTakeFirst((First) second); // casting necessary
}

Приведение имеет решающее значение, так что компилятор фактически делегирует methodThatTakeFirst(First first), иначе вы получите StackOverflowError.

Хороший это дизайн или нет, я не знаю, но я думаю, что это выходит за рамки этого вопроса.

person fps    schedule 08.11.2017

Может быть, просто добавить еще одну лямбду?

  void secondMethod(Second second) {
      methodThatTakeFirst(x-> second.fun(x,x)); 
  }
person dehasi    schedule 08.11.2017