0Pricing
Java Academy · Урок

Ссылки на методы произвольного экземпляра

Ссылайтесь на метод экземпляра без указания получателя — это широко используется в операциях 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"));      // false

Comparator с произвольным экземпляром

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 — локальная установка не требуется.

Все уроки этого курса

  1. Ссылки на статические методы
  2. Ссылки на методы экземпляра конкретного объекта
  3. Ссылки на методы произвольного экземпляра
  4. Ссылки на конструкторы
← Назад к Java Academy