Ссылки на методы
Оператор ссылки на метод ::
используется для ссылки на методы функционального интерфейса. Это компактная и простая форма лямбда-выражения.
Лямбда-выражения используются для создания анонимных методов.
Чаще всего мы выполняем некоторые операции внутри лямбда-выражения. Иногда, однако, лямбда-выражение не делает ничего, кроме вызова существующего метода. В этих случаях часто понятнее обращаться к существующему методу по имени.
Поэтому всякий раз, когда вы используете лямбда-выражение для обращения к методу, вы можете сделать то же самое, используя ссылку на метод. Замените лямбда-выражение на ссылку на метод, и все работает!
Ссылки на методы позволяют вам сделать это. Они представляют собой компактные, удобные для чтения лямбда-выражения для методов, у которых уже есть имя.
Ссылка на метод — это замечательная возможность, появившаяся в Java 8. Помимо использования преимуществ функционального программирования, одним из самых больших преимуществ использования ссылки на метод является то, что она минимизирует количество строк кода даже больше, чем лямбда-выражения.
Ссылки на метод — это особый тип лямбда-выражений. Они часто используются для создания простых лямбда-выражений путем ссылки на существующие методы.
Пример 01: Строки в верхнем регистре
import java.util.Arrays;
import java.util.List;
class Main {
public static void main(String[] args) {
List<String> fruits =
Arrays.asList("Apple", "Banana", "guava", "grapes");
fruits.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
}
Мы могли бы использовать лямбда-выражение внутри терминальной операции .forEach(...)
, как показано ниже.
fruits.stream()
.map(String::toUpperCase)
.forEach(fruit -> System.out.println(fruit));
Но синтаксис ссылок на методы чист и прост. Приведенный выше синтаксис лямбда-выражения рефакторингован с помощью ссылки на метод следующим образом.
.forEach(System.out::println);
Пояснение
Давайте подробно рассмотрим, чего мы пытаемся достичь в приведенном выше фрагменте.
-
У нас есть список фруктов.
-
В результате цепочки
.stream()
коллекция объектовString
преобразуется вStream
объектов String. -
Теперь нам нужно связать
.stream()
с промежуточными операциями, такими как.map(...)
, которая использует ссылку на метод,String::toUpperCase
для перевода всех элементов потока в верхний регистр. -
Наконец, мы связали его с терминальной операцией
.forEach(...)
, которая также использует ссылку на метод для печати данных.
Чтобы понять, что означают промежуточные и терминальные операции в API потоков, прочтите эти статьи hashnode для лучшего понимания.
-
Введение в Java Streams API.
-
Как работает API потоков? Глубокое погружение в поток потоковых операций.
От лямбда-выражений к ссылкам на методы
Вот несколько примеров того, как мы можем заменить лямбда-выражения ссылками на методы.
Далее мы рассмотрим различные виды ссылок на методы, их использование, пример фрагмента кода и объяснение.
Виды ссылок на методы
Существует четыре вида ссылок на методы.
-
Ссылки на статические методы.
-
Ссылка на методы экземпляров конкретных объектов.
-
Ссылка на метод экземпляра произвольного объекта определенного типа.
-
Ссылка на конструктор.
Общий синтаксис
Итак, общий синтаксис для всех этих видов ссылок на методы выглядит следующим образом.
class/object::method
1. Ссылка на статический метод
Ссылка на статический метод относится к статическому методу класса. Мы можем использовать ссылку на метод для прямого вызова статических методов. Синтаксис ссылки на статический метод выглядит следующим образом.
Синтаксис
Это классический синтаксис, в котором за именем класса следует статический метод, на который вы пытаетесь сослаться.
className::staticMethodName
Код
Пример фрагмента кода, который объясняет, как вызываются статические методы с помощью ссылок на методы.
Book
POJO с конструктором, геттерами и сеттерами.
class Book {
String title;
String author;
Integer year;
Integer copiesSoldInMillions;
Double rating;
Double costInEuros;
public Book(String title, String author, Integer year, Integer copiesSoldInMillions, Double rating, Double costInEuros) {
this.title = title;
this.author = author;
this.year = year;
this.copiesSoldInMillions = copiesSoldInMillions;
this.rating = rating;
this.costInEuros = costInEuros;
}
public String getTitle() {
return title;
}
public Double getRating() {
return rating;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + ''' +
", author='" + author + ''' +
", year=" + year +
", copiesSoldInMillions=" + copiesSoldInMillions +
", rating=" + rating +
", costInEuros=" + costInEuros +
'}';
}
}
BookDatabase
для внедрения фиктивных данных.
import java.util.Arrays;
import java.util.List;
public class BookDatabase {
public static List<Book> getAllBooks() {
return Arrays.asList(
new Book("Don Quixote", "Miguel de Cervantes", 1605, 500, 3.9, 9.99),
new Book("A Tale of Two Cities", "Charles Dickens", 1859, 200, 3.9, 10.0),
new Book("The Lord of the Rings", "J.R.R. Tolkien", 2001, 150, 4.0, 12.50),
new Book("The Little Prince", "Antoine de Saint-Exupery", 2016, 142, 4.4, 5.0),
new Book("The Dream of the Red Chamber", "Cao Xueqin", 1791, 100, 4.2, 10.0)
);
}
}
Далее следует класс BookApplication
, который выполняет императивное программирование или мутации переменной book внутри цикла for-loop с использованием ссылки на статический метод.
import java.util.List;
public class BookApplication {
public static int compareByTitle(Book first, Book second) {
return first.getTitle().compareTo(second.getTitle());
}
public static int compareByRating(Book first, Book second) {
return first.getRating().compareTo(second.getRating());
}
public static void main(String[] args) {
List<Book> books = BookDatabase.getAllBooks();
System.out.println("SORT BASED ON RATINGS: ");
books.sort(BookApplication::compareByRating);
books.stream()
.map(book -> book.getTitle() + " -> " + book.getRating())
.forEach(System.out::println);
System.out.println("---------");
System.out.println("SORT BASED ON TITLES: ");
books.sort(BookApplication::compareByTitle);
books.stream()
.map(book -> book.getTitle() + " -> " + book.getRating())
.forEach(System.out::println);
}
}
Вывод:
Приведенный выше код, фрагмент выводит на консоль следующее.
SORT BASED ON RATINGS:
Don Quixote -> 3.9
A Tale of Two Cities -> 3.9
The Lord of the Rings -> 4.0
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4
---------
SORT BASED ON TITLES:
A Tale of Two Cities -> 3.9
Don Quixote -> 3.9
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4
The Lord of the Rings -> 4.0
2. Ссылка на метод экземпляра конкретного объекта
Ниже приведен пример ссылки на метод экземпляра конкретного объекта:
Синтаксис:
Это другой синтаксис, в котором используются экземпляры конкретного объекта, за которыми следует статический метод, на который вы пытаетесь сослаться.
object::staticMethodName
Код
Пример фрагмента кода, который объясняет, как вызываются статические методы с помощью ссылок на методы.
Для простоты я не буду дублировать здесь классы
Book
иBookDatabase
, на них я ссылался в приведенном выше примере.
Итак, перейдем непосредственно к классу BookApplication
.
import java.util.List;
public class BookApplication {
public static void main(String[] args) {
List<Book> books = BookDatabase.getAllBooks();
BookApplication bookApplication = new BookApplication();
System.out.println("SORT BASED ON RATINGS");
books.sort(bookApplication::compareByRating);
books.stream()
.map(book -> book.getTitle() + " -> " + book.getRating())
.forEach(System.out::println);
System.out.println();
System.out.println("SORT BASED ON TITLES: ");
books.sort(bookApplication::compareByTitle);
books.stream()
.map(book -> book.getTitle() + " -> " + book.getRating())
.forEach(System.out::println);
}
public int compareByTitle(Book first, Book second) {
return first.getTitle().compareTo(second.getTitle());
}
public int compareByRating(Book first, Book second) {
return first.getRating().compareTo(second.getRating());
}
}
Вывод:
Приведенный выше код, сниппет выводит на консоль следующее.
SORT BASED ON RATINGS
Don Quixote -> 3.9
A Tale of Two Cities -> 3.9
The Lord of the Rings -> 4.0
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4
SORT BASED ON TITLES:
A Tale of Two Cities -> 3.9
Don Quixote -> 3.9
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4
The Lord of the Rings -> 4.0
Ссылка на метод bookApplication::compareByRating
вызывает метод compareByRating
, который является частью объекта bookApplication
. JRE определяет тип аргументов метода, которыми в данном случае являются (Book book
).
Приведенное выше простое объяснение является таким же и для этой ссылки метода bookApplication::compareByTitle
.
3. Ссылка на метод экземпляра произвольного объекта определенного типа.
Ниже приведен пример ссылки на метод экземпляра произвольного объекта определенного типа.
Код
Метод 01
import java.util.Arrays;
import java.util.List;
class Main {
public static void main(String[] args) {
List<String> fruits =
Arrays.asList("Banana", "Grapes", "guava", "apples");
fruits.sort(String::compareToIgnoreCase);
fruits.forEach(System.out::println);
}
}
Выход:
apples
Banana
Grapes
guava
Эквивалентное лямбда-выражение для ссылки на метод String::compareToIgnoreCase
будет иметь формальный список параметров (String a, String b)
, где a
и b
— произвольные имена, используемые для лучшего описания данного примера. Ссылка на метод вызовет метод a.compareToIgnoreCase(b)
.
Аналогично, ссылка на метод String::concat
вызовет метод a.concat(b)
.
Подход 02
import java.util.Arrays;
import java.util.List;
class Main {
public static void main(String[] args) {
List<Integer> numbers =
Arrays.asList(11, 4, 2, 8, 9, 10, 32, 22, 20, 17);
numbers.stream()
// .sorted((a, b) -> a.compareTo(b)) lambda way
.sorted(Integer::compareTo)
.forEach(s -> System.out.print(s + " "));
}
}
Выход:
2 4 8 9 10 11 17 20 22 32
4. Ссылка на конструктор
Ссылки на конструктор — это специализированные формы ссылок на методы, которые ссылаются на конструкторы класса. Они могут быть созданы с помощью className и ключевого слова new.
Синтаксис
className::new
Код
public class BookApplication {
public static void main(String[] args) {
BookService bookService = Book::new;
Book book = bookService.getBook(
"The Little Prince",
"Antoine de Saint-Exupery",
2016, 142,
4.4,
5.0);
System.out.println(book);
}
}
Выход:
Book{title='The Little Prince', author='Antoine de Saint-Exupery', year=2016, copiesSoldInMillions=142, rating=4.4, costInEuros=5.0}
Вот и все, что вам нужно знать о ссылках на методы в Java. Счастливого кодинга ?.
Читать далее
-
Введение в Java Streams API
-
Как работает API потоков? Глубокое погружение в поток потоковых операций
-
Функциональное программирование и парадигмы программирования в Java
-
Императивный и декларативный стили программирования