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);
}
});
Перший запис однозначно коротший за другий. І хоча читати код із лямбда-виразами непросто, читати код з анонімними внутрішніми класами часом іще складніше.
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()
), було б розумно просто передати функцію в метод як параметр.
А як пояснити компілятору, що функцію потрібно саме передати, а не викликати? Для цього перед іменем методу ставимо не крапку, а дві двокрапки: одна двокрапка вже зайнята в тернарному операторі.
Це й є найпростішим і найкомпактнішим записом.
3. Конструктор
Посилання на методи за допомогою подвійної двокрапки дуже зручно використовувати, коли ми працюємо з потоками вводу-виведення. Ви переконаєтеся в цьому трохи згодом.
А наразі поговорімо про три популярні способи передачі посилання на метод:
Посилання на метод об'єкта
Для того щоб передати посилання на метод об'єкта, потрібно записати код такого формату: об'єкт::метод
.
Цей код є еквівалентним коду x -> об'єкт.метод(x)
.
Об'єктом можуть бути такі спеціальні змінні, як this
і super
.
Посилання на метод класу
Для того щоб передати посилання на статичний метод, потрібно записати код такого формату: клас::метод
. Цей код буде перетворено на код x -> клас.метод(x);
Посилання на конструктор
Конструктор за своєю поведінкою чимось схожий на статичний метод класу, тому на нього теж можна передати посилання. Відповідний код має такий вигляд: клас::new
.
Наприклад, можна обійти стирання типів у колекцій і передати в метод toArray()
посилання на конструктор, який створить потрібний масив: toArray( int[]::new );
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ