JavaRush/Курси/Java Syntax Zero/Функціональний метод

Функціональний метод

Відкрита

1. Функціональні методи

Якщо інтерфейс має тільки один метод, змінній цього типу-інтерфейсу можна присвоїти значення, задане лямбда-виразом (лямбда-функцією). Такі інтерфейси стали називати функціональними інтерфейсами (після додавання в Java підтримки лямбда-функцій).

Наприклад, у Java є інтерфейс Consumer<Тип> (Consumer == Споживач), який містить метод accept(Тип obj). Навіщо ж потрібен цей інтерфейс?

У Java 8 у колекцій з'явився метод forEach(), який дає змогу для кожного елемента колекції виконати якусь дію. І от саме для передавання дії в метод forEach() і використовується функціональний інтерфейс Consumer<T>.

Отак можна вивести всі елементи колекції на екран:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Привіт", "як", "справи?");

list.forEach( (s) -> System.out.println(s) );
Виведення всіх елементів колекції (з використанням лямбда-виразу)

Компілятор перетворить цей код на такий:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Привіт", "як", "справи?");

list.forEach(new Consumer<String>()
{
   public void accept(String s)
   {
      System.out.println(s);
   }
});
Виведення всіх елементів колекції (з використанням анонімного класу)

Перший запис однозначно коротший за другий. І хоча читати код із лямбда-виразами непросто, читати код з анонімними внутрішніми класами часом іще складніше.


19
Задача
Java Syntax Zero,  19 рівень2 лекція
Недоступна
Знайомство з foreach
Знайомство з foreach
19
Задача
Java Syntax Zero,  19 рівень2 лекція
Недоступна
Прощання з foreach
Прощання з foreach

2. Посилання на метод

Натомість наш код із лямбда-виразом можна скоротити ще більше.

По-перше, можна випустити дужки навколо параметра s:

list.forEach( (s) -> System.out.println(s) );
Було
list.forEach( s -> System.out.println(s) );
Стало

Так можна робити, тільки якщо параметр один. Якщо параметрів декілька, потрібно використовувати дужки.

А по-друге, можна записати так:

list.forEach( System.out::println );
Найкомпактніший запис

Це все той самий запис. Зверніть увагу, що після println немає дужок.

Тут записано той самий код — виклик методу:

об'єкт::метод
x -> об'єкт.метод(x)

Подумайте самі: ми хотіли для кожного елемента колекції list виконувати якусь дію. Якщо ця дія — виклик однієї функції (як-от println()), було б розумно просто передати функцію в метод як параметр.

А як пояснити компілятору, що функцію потрібно саме передати, а не викликати? Для цього перед іменем методу ставимо не крапку, а дві двокрапки: одна двокрапка вже зайнята в тернарному операторі.

Це й є найпростішим і найкомпактнішим записом.


19
Задача
Java Syntax Zero,  19 рівень2 лекція
Недоступна
Знайомство з посиланнями на методи
Знайомство з посиланнями на методи
19
Задача
Java Syntax Zero,  19 рівень2 лекція
Недоступна
Прощання з посиланнями на методи
Прощання з посиланнями на методи

3. Конструктор

Посилання на методи за допомогою подвійної двокрапки дуже зручно використовувати, коли ми працюємо з потоками вводу-виведення. Ви переконаєтеся в цьому трохи згодом.

А наразі поговорімо про три популярні способи передачі посилання на метод:

Посилання на метод об'єкта

Для того щоб передати посилання на метод об'єкта, потрібно записати код такого формату: об'єкт::метод.
Цей код є еквівалентним коду x -> об'єкт.метод(x).

Об'єктом можуть бути такі спеціальні змінні, як this і super.

Посилання на метод класу

Для того щоб передати посилання на статичний метод, потрібно записати код такого формату: клас::метод. Цей код буде перетворено на код x -> клас.метод(x);

Посилання на конструктор

Конструктор за своєю поведінкою чимось схожий на статичний метод класу, тому на нього теж можна передати посилання. Відповідний код має такий вигляд: клас::new.

Наприклад, можна обійти стирання типів у колекцій і передати в метод toArray() посилання на конструктор, який створить потрібний масив: toArray( int[]::new );


19
Задача
Java Syntax Zero,  19 рівень2 лекція
Недоступна
Перетворення списку на масив
Перетворення списку на масив
Коментарі (7)
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Олександр
Рівень 102
1 березня 2025, 21:43
Є інший варіант задання посилання на метод об'єкта.
Назва класу::назва методу экземпляра
У такому разі перший параметр функціонального інтерфейсу виконує роль об'єкта, а інші параметри будуть параметрами методу, викликаного для цього об'єкта. Приклад:
interface ForString {
    boolean check(String s1, String s2);
}
public class SingleLambda {
    public static void main(String[] args) {
        System.out.print("Equals: ");
        //"Hello" виступає як об'єкт, на якому викликається метод equals("Hi"). "Hello". equals ("Hi");
        //Метод функціонального інтерфейсу має два параметри, метод equals має один параметр
        isTrue(String::equals, "Hello","Hi");
        System.out.print("Contains: ");
        // Те, що і вище, тільки для contains("el"). "Hello".contains("el");
        isTrue(String::contains, "Hello", "el");
        Test test = new Test();
        System.out.print("firstBiggerLength: ");
        // Звичайний визов через об'єкт
        // два параметри у методі функціонального інтерфейсу, два параметри у методі firstHaveBiggerLength
        isTrue(test::firstHaveBiggerLength, "Hello","Hi");
    }

    static void isTrue(ForString obj, String s1, String s2) {
        if(obj.check(s1, s2)) System.out.println("True");
        else System.out.println("False");
    }
}
class Test{
    boolean firstHaveBiggerLength(String string1, String string2){
        return string1.length() > string2.length();
    }
}
17 січня 2024, 20:46
мда, є один мем який на всі 100% підходить до цієї лекції)
Elder_HD Працює в UPCExpert
20 червня 2023, 20:21
Дякую, що так поглиблено пояснили за абстрактні класи, лямбди функції, посилання на методи! Видно, що на цьому рівні дуже пропрацьований матеріал, особисто для тих хто вчить Java як першу мову програмування. Впевнений, що цієї інфи на стільки достатньо, що тепер навіть не потрібно йти вивчати матеріал на інших ресурсах (ютуб, книги). P.S. до цього утримувався від критики лекцій у квестах. Але тут не то, що важко для сприйняття, а просто інформація подана як аксіома - "ось тримайте, просто запам'ятайте і використовуйте"
Микита
Рівень 89
Expert
15 червня 2023, 13:41
чому при запуску кода останнього завдання в IDE не спрацьовує команда? return strings.toArray(String[]::new); IDE дає помилку "String[] is not a functional interface" команда return strings.toArray(new String [] {}); спрацьовує
FAUST_ua
Рівень 29
1 жовтня 2022, 19:28
На мій погляд дещо поверхнево пояснено.
RomanH
Рівень 29
17 січня 2022, 15:38
Знайомство з foreach обов'язково через println!
Vasia
Рівень 26
5 вересня 2022, 21:48
Ні, пішло з print