Референции за методи в Java

1. Общ преглед

Една от най-добре дошли промени в Java 8 беше въвеждането на ламбда изрази, тъй като те ни позволяват да се откажем от анонимните класове, значително намалявайки кода на шаблона и подобрявайки четливостта.

Препратките към методите са специален тип ламбда изрази . Те често се използват за създаване на прости ламбда изрази, като се позовават на съществуващи методи.

Има четири вида препратки към методите:

  • Статични методи
  • Инстанционни методи на определени обекти
  • Методи на инстанция на произволен обект от определен тип
  • Конструктор

В този урок ще изследваме препратки към методи в Java.

2. Позоваване на статичен метод

Ще започнем с много прост пример, като изписваме с главни букви и отпечатваме списък от низове :

List messages = Arrays.asList("hello", "baeldung", "readers!");

Можем да постигнем това, като използваме прост ламбда израз, извикващ директно метода StringUtils.capitalize () :

messages.forEach(word -> StringUtils.capitalize(word));

Или можем да използваме препратка към метод, за да се позовем на статичния метод с главни букви :

messages.forEach(StringUtils::capitalize);

Забележете, че препратките към методите винаги използват оператора :: .

3. Позоваване на инстанционен метод на определен обект

За да демонстрираме този тип справка за метод, нека разгледаме два класа:

public class Bicycle { private String brand; private Integer frameSize; // standard constructor, getters and setters } public class BicycleComparator implements Comparator { @Override public int compare(Bicycle a, Bicycle b) { return a.getFrameSize().compareTo(b.getFrameSize()); } }

И нека създадем обект BicycleComparator, за да сравним размерите на рамката на велосипеда:

BicycleComparator bikeFrameSizeComparator = new BicycleComparator();

Можем да използваме ламбда израз за сортиране на велосипеди по размер на рамката, но ще трябва да посочим два велосипеда за сравнение:

createBicyclesList().stream() .sorted((a, b) -> bikeFrameSizeComparator.compare(a, b));

Вместо това можем да използваме препратка към метод, за да предадем за нас параметъра на компилатора:

createBicyclesList().stream() .sorted(bikeFrameSizeComparator::compare);

Справочникът на метода е много по-чист и по-четлив, тъй като нашето намерение е ясно показано от кода.

4. Позоваване на инстанционен метод на произволен обект от определен тип

Този тип препратка към метод е подобен на предишния пример, но без да се налага да създавате персонализиран обект за извършване на сравнението.

Нека създадем списък с цели числа , който искаме да сортираме:

List numbers = Arrays.asList(5, 3, 50, 24, 40, 2, 9, 18);

Ако използваме класически ламбда израз, и двата параметъра трябва да бъдат предадени изрично, докато използването на референтен метод е много по-лесно:

numbers.stream() .sorted((a, b) -> a.compareTo(b)); numbers.stream() .sorted(Integer::compareTo);

Въпреки че все още е еднолинеен, референтът на метода е много по-лесен за четене и разбиране.

5. Препратка към конструктор

Можем да се позовем на конструктор по същия начин, по който се позоваваме на статичен метод в първия ни пример. Единствената разлика е, че ще използваме новата ключова дума.

Нека създадем масив Bicycle от списък String с различни марки:

List bikeBrands = Arrays.asList("Giant", "Scott", "Trek", "GT");

Първо ще добавим нов конструктор към нашия клас Bicycle :

public Bicycle(String brand) { this.brand = brand; this.frameSize = 0; } 

След това ще използваме нашия нов конструктор от референтен метод и ще направим масив Bicycle от оригиналния списък String :

bikeBrands.stream() .map(Bicycle::new) .toArray(Bicycle[]::new); 

Забележете как извикахме конструкторите Bicycle и Array, използвайки справка за метод, давайки нашия код много по-кратък и ясен външен вид.

6. Допълнителни примери и ограничения

Както видяхме досега, препратките към методи са чудесен начин да направим нашия код и намерения много ясни и четливи. Не можем обаче да ги използваме, за да заменим всички видове ламбда изрази, тъй като те имат някои ограничения.

Основното им ограничение е резултат от това, което е и най-голямата им сила: изходът от предишния израз трябва да съответства на входните параметри на сигнала на референтния метод .

Нека да видим пример за това ограничение:

createBicyclesList().forEach(b -> System.out.printf( "Bike brand is '%s' and frame size is '%d'%n", b.getBrand(), b.getFrameSize()));

Този прост случай не може да бъде изразен с препратка към метод, тъй като методът printf изисква 3 параметъра в нашия случай и използването на createBicyclesList (). ForEach () би позволило само препратката към метода да изведе един параметър ( обекта Bicycle ).

И накрая, нека разгледаме как да създадем функция за бездействие, която може да се препраща от ламбда израз.

В този случай ще искаме да използваме ламбда израз без да използваме параметрите му.

Първо, нека създадем метода doNothingAtAll :

private static  void doNothingAtAll(Object... o) { }

Тъй като това е метод на varargs, той ще работи във всеки ламбда израз, независимо от посочения обект или броя на параметрите, за които се предполага.

Сега нека го видим в действие:

createBicyclesList() .forEach((o) -> MethodReferenceExamples.doNothingAtAll(o)); 

7. Заключение

В този бърз урок научихме какви препратки към методите са в Java и как да ги използваме за замяна на ламбда изрази, като по този начин подобряваме четливостта и изясняваме намерението на програмиста.

Целият код, представен в тази статия, е достъпен в GitHub.