Ссылки на методы не соответствуют функциональным интерфейсам, но компиляция не приводит к ошибкам ... Это разработано?

1

В нижеприведенном фрагменте оба метода forEach() компилируются:

public static void main(String[] args)
{
    BigDecimal spent = BigDecimal.ZERO;
    Stream.of(BigDecimal.ONE, BigDecimal.TEN).forEach(spent::add);

    Set<BigDecimal> set = new HashSet<>();
    Stream.of(BigDecimal.ONE, BigDecimal.TEN).forEach(set::add);
}

Я знаю о безумии первого примера (BigDecimal является неизменным); проблему здесь нет:

  • Stream forEach() берет Consumer в качестве аргумента, а подпись SAM (примечание: Single Abstract Method) говорит, что он возвращает void;
  • однако BigDecimal .add() возвращает BigDecimal, а Set .add() (на самом деле Collection) возвращает boolean;
  • поэтому подпись обоих методов выше не соответствует Consumer;
  • но оба примера скомпилированы.

Но это не компилируется:

// whatever is returned; BigDecimal.ZERO, null... -> compile error
Stream.of(BigDecimal.ONE).forEach(b -> { return false; });

Это по дизайну?

Теги:
java-8

1 ответ

3
Лучший ответ

Помните, что тип возврата не является частью сигнатуры метода. Для вашего первого случая мы переходим к оценке времени выполнения лямбда-выражения.

Тело метода имеет эффект оценки лямбда-тела, если оно является выражением или исполнением лямбда-тела, если оно является блоком; если ожидается результат, он возвращается из метода.

Что касается второго случая

Если результат типа функции void, тело лямбда является выражением оператора или блоком, совместимым с void.

которого у вас нет, т.е. Тип функции Consumer#accept(Object) void, но ваше тело лямбда не является выражением оператора или не совместимым с void блоком. Это блок, совместимый с ценностью.

Это по дизайну?

Я сказал да. Во втором случае вы явно заявляете, что возвращаете значение. Но это не допускается методом целевого функционального интерфейса.

В вашем первом фрагменте

Stream.of(BigDecimal.ONE, BigDecimal.TEN).forEach(spent::add);

вы просто обладаете большей гибкостью. Выражение может иметь побочные эффекты, и вы можете игнорировать возвращаемое значение.

  • 1
    «возвращаемый тип не является частью сигнатуры метода» <- ну, извините, но CallSite не согласен, как, например, и MethodType ; хотя я могу понять часть «результат ожидаем», я не согласен с вышеупомянутым утверждением ...
  • 1
    @fge Вы имеете в виду типы java.lang.invoke ? Что они говорят?
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню