CodeGym /Kurslar /JAVA 25 SELF /Method References (::): metodlara istinadlar

Method References (::): metodlara istinadlar

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Method reference (rus dilində — metod istinadı) Java-da mövcud metodu (və ya konstruktoru) funksional interfeysin həyata keçirilməsi kimi ötürməyə imkan verən xüsusi sintaksisdir. Əgər imzalar üst-üstə düşürsə, metodu lambda ifadəsi gözlənilən yerə “ötürmək” olar.

Sintaksis:

Sinif::metod
obyekt::metod
Sinif::new

Əgər lambda “yolda” yazılan kiçik funksiyadırsa, method reference sadəcə “artıq mövcud olan metodu ötür” deməkdir. Bu, resepti yenidən yazmaq əvəzinə reseptin səhifəsinə keçid verməyə bənzəyir.

Sadə nümunə

Bunun əvəzinə:

list.forEach(s -> System.out.println(s));

Belə yaza bilərsiniz:

list.forEach(System.out::println);

Qısa və oxunaqlıdır, elə deyilmi?

2. Method reference növləri

Metod istinadlarının dörd əsas forması var. Bax bunlar — və daha artığı lazım deyil.

Statik metoda istinad

Sintaksis: Sinif::statikMetod

Nümunə:

Function<Integer, String> intToString = String::valueOf;
System.out.println(intToString.apply(123)); // "123"

Eyni şey lambda ilə:

Function<Integer, String> intToString = i -> String.valueOf(i);

Obyektin qeyri-statik metoduna istinad

Sintaksis: obyekt::metod

Nümunə:

PrintStream printer = System.out;
Consumer<String> consumer = printer::println;
consumer.accept("Salam, dünya!");

Lambda ilə ekvivalentdir:

Consumer<String> consumer = s -> printer.println(s);

Sinifin qeyri-statik metoduna istinad

Sintaksis: Sinif::metod

Burada funksional interfeysin birinci parametri metodun çağırılacağı obyektə çevrilir.

Nümunə:

Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Java")); // 4

Burada String::length bu funksiyaya çevrilir: (String s) -> s.length()

Konstruktor istinadı

Sintaksis: Sinif::new

Nümunə:

Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> list = listSupplier.get();

Lambda ilə ekvivalentdir:

Supplier<ArrayList<String>> listSupplier = () -> new ArrayList<>();

3. Method reference nə vaxt istifadə olunmalıdır?

Lambda sadəcə mövcud metodu əlavə məntiq olmadan çağırırsa, method reference istifadə etmək rahatdır — kod daha qısa və oxunaqlı olur.

Nümunə: siyahının sıralanması

Bunun əvəzinə:

List<String> names = Arrays.asList("İvan", "Petr", "Anna");
names.sort((a, b) -> a.compareToIgnoreCase(b));

Belə yaza bilərsiniz:

names.sort(String::compareToIgnoreCase);

Nümunə: kolleksiyaların emalı

Bunun əvəzinə:

list.forEach(s -> System.out.println(s));

Ümumiyyətlə çox qısa:

list.forEach(System.out::println);

Nümunə: elementlərin çevrilməsi

Bunun əvəzinə:

List<String> numbers = Arrays.asList("1", "2", "3");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Belə mümkündür:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Stream API və util sinfi Collectors barədə daha ətraflı 30-cu səviyyədə öyrənəcəksiniz :P

4. Method reference və lambda ifadələrinin müqayisəsi

Ekvivalentlik

Method reference və lambda ifadəsi çox vaxt bir-birini əvəz edə bilər. İmzalar üst-üstə düşdükdə hər ikisi funksional interfeysi həyata keçirir.

Nümunə:

Consumer<String> c1 = s -> System.out.println(s);
Consumer<String> c2 = System.out::println;

Method reference nə vaxt daha yaxşıdır?

  • Lambda mövcud metodu əlavə məntiq olmadan sadəcə çağırdıqda.
  • Xüsusən uzun çağırış zəncirlərində oxunaqlılığı artırmaq üçün.
  • Açıqca göstərmək istəyəndə: “burada sadəcə metod çağırışı var”.

Method reference nə zaman uyğun deyil?

  • Əlavə məntiq (doğrulama, şərtlər, səhv emalı) lazım olduqda.
  • Parametrləri metod çağırışından əvvəl çevirmək/transformasiya etmək gərəkəndə.

Nümunə:

list.forEach(s -> {
    if (s != null) System.out.println(s);
});
// Burada method reference uyğun deyil, yalnız lambda.

5. Təcrübə: lambda ifadələrini method reference ilə yenidən yazmaq

Nümunə 1: Heyvan adlarının çıxarılması

List<String> animals = Arrays.asList("Pişik", "İt", "Tutuquşu");
animals.forEach(animal -> System.out.println(animal));

Belə olur:

animals.forEach(System.out::println);

Nümunə 2: Sətirləri ədədlərə çevirmək

List<String> numbers = Arrays.asList("10", "20", "30");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Belə olur:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Nümunə 3: Obyektlərin ada görə sıralanması

List<Animal> animalList = ...;
animalList.sort((a, b) -> a.getName().compareTo(b.getName()));

Belə olur:

animalList.sort(Comparator.comparing(Animal::getName));

Burada Animal::getName — sinifin qeyri‑statik metoduna istinaddır.

Nümunə 4: Konstruktor vasitəsilə obyektlərin yaradılması

Supplier<Dog> dogFactory = () -> new Dog();
Dog dog = dogFactory.get();

Belə olur:

Supplier<Dog> dogFactory = Dog::new;
Dog dog = dogFactory.get();

6. İmza uyğunlaşdırılması necə işləyir

Method reference yalnız o halda istifadə oluna bilər ki, metodun imzası funksional interfeysin abstrakt metodu ilə üst-üstə düşsün.

@FunctionalInterface
interface IntToString {
    String convert(int value);
}

public class Demo {
    public static String intToHex(int value) {
        return Integer.toHexString(value);
    }

    public static void main(String[] args) {
        IntToString converter = Demo::intToHex;
        System.out.println(converter.convert(255)); // ff
    }
}

Burada Demo::intToHex uyğundur, çünki int qəbul edir və String qaytarır.

7. Method reference və parametrləri olan konstruktorlar

Konstruktor parametrlər qəbul edirsə belə, imzalar uyğun gəldiyi müddətdə method reference istifadə oluna bilər.

@FunctionalInterface
interface AnimalFactory {
    Animal create(String name);
}

class Animal {
    private String name;
    public Animal(String name) { this.name = name; }
    public String getName() { return name; }
}

AnimalFactory factory = Animal::new;
Animal cat = factory.create("Barsik");
System.out.println(cat.getName()); // Barsik

8. Method reference istifadə edərkən tipik səhvlər

Xəta №1: İmzaların uyğunsuzluğu.
Əgər metodun imzası interfeysin abstrakt metodu ilə üst-üstə düşmürsə, kompilyator xəta verəcək. Məsələn, interfeys iki parametr gözləyir, amma istinad bir parametrli metoda yönəlir.

Xəta №2: Sinifin qeyri-statik metoduna obyekt olmadan istinad.
Sinif::metod formasını istifadə edəndə interfeysin birinci parametri çağırışın obyekti olur. Parametrlərin sayını və ya sırasını səhv etsəniz — uyğunlaşdırma xətası alacaqsınız.

Xəta №3: Əlavə məntiq tələb olunan yerdə method reference istifadə etmək.
Şərt, jurnal qeydiyyatı və ya istisna emalı tələb olunursa — metod istinadı deyil, lambda istifadə edin.

Xəta №4: Aşırı yüklənmiş metodlara istinad.
Əgər sinifdə eyni adlı bir neçə metod varsa, kompilyator hansını seçəcəyini anlaya bilməyə bilər. Bəzən funksional interfeysin tipini açıq göstərmək kömək edir.

Xəta №5: Qeyri-statik metoda obyekt olmadan istinad.
Məsələn, String::toUpperCase map-də düzgün işləyir, çünki birinci parametr — elə String obyektinin özüdür. Amma uyğun kontekstdən kənarda, harada ki statik metod gözlənilir, bu xəta ilə nəticələnəcək.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Cihaz identifikatorları çeviricisi 📟
Cihaz identifikatorları çeviricisi 📟
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Fərdi loqlaşdırma sistemi 📝
Fərdi loqlaşdırma sistemi 📝
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Anbar inventarının təşkili 🍎🍌🍐
Anbar inventarının təşkili 🍎🍌🍐
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Virtual ev heyvanları fabrikası 🐾
Virtual ev heyvanları fabrikası 🐾
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION