На самом деле, в обоих случаях компилятор "ругается" из-за несоответствия типов.
Сначала разберём ваш первый код. Вы пишете method reference для типа Function
, и пишете его правильно, но тип входного параметра у метода forEach
другой - это Consumer
.
Так выглядит функциональный интерфейс Function
:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
// and other methods
}
Его абстрактный метод принимает на вход значение и возвращает значение.
А вот так выглядит функциональный интерфейс Consumer
:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// and other methods
}
Его абстрактный метод принимает на вход значение и ничего не возвращает.
Лямбда-выражение для обоих методов может выглядеть совершенно идентично:
Function<String, String> capitalize = s -> StringUtils.capitalize(s);
Consumer<String> consumer = s -> StringUtils.capitalize(s);
В первом случае мы принимаем строку и возвращаем её, переведённую в верхний регистр, а во втором случае просто принимаем строку, но результат действия с ней не возвращается функцией.
Эти лямбда-выражения можно сократить до method reference, как вы и сделали для Function
:
Function<String, String> capitalize = StringUtils::capitalize;
Consumer<String> consumer = StringUtils::capitalize;
Теперь проверим предупреждения компилятора:
public static void main(String[] args) {
Function<String, String> function = StringUtils::capitalize; // method reference для типа Function
Consumer<String> consumer = StringUtils::capitalize; // method reference для типа Consumer
List<String> messages = Arrays.asList("how", "this", "works?");
messages.forEach(function); // ошибка, ведь передаём переменную типа Function
messages.forEach(consumer); // ошибки нет, ведь передаём переменную типа Consumer
messages.forEach(StringUtils::capitalize); // ошибки нет, так как автоматически предполагается тип Consumer
}
Теперь разберём ваш второй код. Вы пишете лямбда-выражение для интерфейса Supplier
, и пишете его правильно, но тип входного параметра у метода map
другой - это Function
.
public static void main(String[] args) {
Supplier<Integer> supplier = () -> 42; // лямбда-выражение для Supplier
List<String> messages = Arrays.asList("how", "this", "works?");
messages.stream().map(supplier).forEach(System.out::println); // ошибка, так как требуется тип Function
messages.stream().map(() -> 42).forEach(System.out::println); // ошибка, так как требуется тип Function
}
Supplier
просто выдаёт значение, не принимая никаких параметров. А Function
, как мы убедились выше, принимает параметр и возвращает значение. Код с корректным лямбда-выражением для типа Function
и поясняющими комментариями приведён ниже.
public static void main(String[] args) {
Supplier<Integer> supplier = () -> 42; // лямбда-выражение для Supplier
Function<String, Integer> function = s -> supplier.get(); // лямбда-выражение для Function: не просто возвращаем значение, но и принимаем параметр
List<String> messages = Arrays.asList("how", "this", "works?");
messages.stream().map(function).forEach(System.out::println); // работает
messages.stream().map(s -> supplier.get()).forEach(System.out::println); // работает
}