Ссылки на методы произвольного экземпляра
Ссылайтесь на метод экземпляра без указания получателя — это широко используется в операциях Stream.
«Ссылки на методы произвольного экземпляра» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Что такое ссылки на методы произвольного экземпляра
Ссылка на метод произвольного экземпляра использует ClassName::instanceMethod. Здесь первый аргумент функционального интерфейса служит получателем — каждый элемент становится объектом, для которого вызывается метод.
import java.util.*;
import java.util.stream.*;
List<String> names = List.of("alice","bob","carol");
// String::toUpperCase — receiver is each list element
List<String> upper = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upper); // [ALICE, BOB, CAROL]Как определяется получатель
Для ссылки на метод произвольного экземпляра Type::method первый параметр функционального интерфейса становится this (получателем):
// String::length matches Function<String, Integer>
// Equivalent to: s -> s.length()
Function<String, Integer> len = String::length;
System.out.println(len.apply("Java")); // 4
// String::isEmpty matches Predicate<String>
// Equivalent to: s -> s.isEmpty()
Predicate<String> isEmpty = String::isEmpty;
System.out.println(isEmpty.test("")); // trueШирокое применение в операциях с потоками
Ссылки на методы произвольного экземпляра чаще всего используются в конвейерах потоков:
List<String> words = List.of("Hello","","World","","Java");
// filter with String::isEmpty
long empty = words.stream().filter(String::isEmpty).count();
System.out.println(empty); // 2
// map with String::toLowerCase
words.stream()
.filter(s -> !s.isEmpty())
.map(String::toLowerCase)
.forEach(System.out::println);Стиль BiFunction для методов с двумя аргументами
Метод с двумя аргументами у типа соответствует BiFunction<T, U, R>, где T — получатель, а U — аргумент:
import java.util.function.*;
// String::startsWith → BiPredicate<String, String>
// receiver=first arg, argument=second arg
BiPredicate<String, String> starts = String::startsWith;
System.out.println(starts.test("JavaStream", "Java")); // true
System.out.println(starts.test("Python", "Java")); // falseComparator с произвольным экземпляром
String::compareTo соответствует Comparator<String> — два аргумента компаратора становятся получателем и параметром:
List<String> words = List.of("banana","apple","cherry");
List<String> sorted = words.stream()
.sorted(String::compareTo)
.collect(Collectors.toList());
System.out.println(sorted); // [apple, banana, cherry]Произвольный экземпляр пользовательского класса
Это работает с методами экземпляра любого класса, а не только типов JDK:
record Product(String name, double price) {
boolean isExpensive() { return price > 50; }
String label() { return name + " ($" + price + ")"; }
}
List<Product> products = List.of(
new Product("Widget", 9.99),
new Product("Gadget", 99.99),
new Product("Donut", 1.50)
);
products.stream()
.filter(Product::isExpensive)
.map(Product::label)
.forEach(System.out::println); // Gadget ($99.99)Отличие от конкретного экземпляра
Ключевое различие:
- Конкретный:
obj::method— obj всегда является получателем - Произвольный:
Type::method— каждый элемент IS получатель
String fixed = "prefix";
// Specific instance: fixed is always the receiver
Predicate<String> startsFixed = fixed::startsWith; // always checks 'prefix'.startsWith(arg)
// Arbitrary instance: each element is the receiver
Predicate<String> isEmpty = String::isEmpty; // each element.isEmpty()Ссылки на методы в коллекторах
Ссылки на методы произвольного экземпляра естественно сочетаются с коллекторами:
List<String> items = List.of(" hello "," world "," java ");
List<String> trimmed = items.stream()
.map(String::trim)
.collect(Collectors.toList());
System.out.println(trimmed); // [hello, world, java]Цепочки ссылок на методы
Ссылки на методы можно объединять с andThen/compose у Function:
Function<String, String> pipeline =
((Function<String, String>) String::trim)
.andThen(String::toUpperCase);
System.out.println(pipeline.apply(" hello world "));
// HELLO WORLDПодводный камень: перегруженные методы
Если метод перегружен, компилятор должен определить, какая перегрузка соответствует функциональному интерфейсу. При неоднозначности возникает ошибка компиляции — используйте лямбду, чтобы устранить неоднозначность:
// println is overloaded — which one?
// Consumer<String> c = System.out::println; // OK — infers println(String)
// Consumer<Object> c2 = System.out::println; // OK
// But if ambiguous:
// Function<Object,?> fn = System.out::println; // Error — println doesn't return a valueПроизводительность
Ссылки на методы и лямбды компилируются в один и тот же байт-код (через invokedynamic). Разницы в производительности нет — выбирайте более читаемый вариант. Большинство руководств по стилю рекомендует ссылки на методы, когда они ясно выражают намерение.
Быстрая проверка
Что представляет собой String::toUpperCase при использовании с .map()?
Итоги: ссылки на методы произвольного экземпляра
Основные выводы:
- Синтаксис: ClassName::instanceMethod — каждый элемент является получателем
- Соответствует функциональным интерфейсам, в которых получатель является первым параметром
- Чаще всего используется в .map(), .filter(), .sorted(), .forEach()
- Методы с двумя аргументами → BiFunction/BiPredicate, где элемент является получателем
- Разницы в производительности по сравнению с лямбдой нет — выбирайте более читаемый вариант
Часто задаваемые вопросы
Урок «Ссылки на методы произвольного экземпляра» бесплатный?
Да — полный текст урока «Ссылки на методы произвольного экземпляра» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Ссылки на методы произвольного экземпляра»?
Ссылайтесь на метод экземпляра без указания получателя — это широко используется в операциях Stream. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Ссылки на методы произвольного экземпляра»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Ссылки на статические методы
- Ссылки на методы экземпляра конкретного объекта
- Ссылки на методы произвольного экземпляра
- Ссылки на конструкторы