Method References — Class::method

Method Reference — lambda-র আরও সংক্ষিপ্ত ও পরিষ্কার রূপ

Read: ~25 min Intermediate 5 practice problems Live code runner

1. Why Method References?

Often a lambda does nothing but pass its arguments straight to an existing method: x -> x.toString(). Java has a compact syntax for that case — a method reference — written Class::method. The result is the same functional interface, but cleaner.

অনেক lambda কেবল argument-গুলো একটি বিদ্যমান method-এ pass করে — যেমন x -> x.toString()। এই ক্ষেত্রের জন্য Java দিয়েছে method reference — Class::method। কাজ সমান, কিন্তু পরিষ্কার।
Main.java
import java.util.*;

class Main {
    public static void main(String[] args) {
        List<String> xs = List.of("Arif", "Rina", "Hasan");

        // Lambda form
        xs.forEach(x -> System.out.println(x));

        // Method reference form — identical behavior
        xs.forEach(System.out::println);
    }
}

2. The Four Forms

There are exactly four forms of method reference:

Four Forms of Method Reference Integer::parseInt 1. Static method Class::staticMethod String::length 2. Unbound instance method Class::instanceMethod list::add 3. Bound instance method instance::instanceMethod ArrayList::new 4. Constructor reference Class::new Figure 28.1 — চার ধরনের method reference।
চারটি রূপ: (১) static — Class::staticMethod, (২) unbound instance — Class::instanceMethod (যেখানে প্রথম argument-ই receiver), (৩) bound instance — instance::instanceMethod (একটি নির্দিষ্ট object-এ), (৪) constructor — Class::new।

3. Each Form in Action

নিচে প্রতিটি form-এর lambda ও method-reference পাশাপাশি দেখানো হলো।
Main.java
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

class Main {
    public static void main(String[] args) {

        // (1) Static method reference
        Function<String, Integer> parse1 = s -> Integer.parseInt(s);
        Function<String, Integer> parse2 = Integer::parseInt;
        System.out.println(parse1.apply("42") + " == " + parse2.apply("42"));

        // (2) Unbound instance method reference
        Function<String, Integer> len1 = s -> s.length();
        Function<String, Integer> len2 = String::length;
        System.out.println(len1.apply("Bangladesh") + " == " + len2.apply("Bangladesh"));

        // (3) Bound instance method reference
        List<Integer> bucket = new ArrayList<>();
        Consumer<Integer> add1 = n -> bucket.add(n);
        Consumer<Integer> add2 = bucket::add;
        add1.accept(1); add2.accept(2); add2.accept(3);
        System.out.println("bucket = " + bucket);

        // (4) Constructor reference
        Supplier<List<String>> make1 = () -> new ArrayList<>();
        Supplier<List<String>> make2 = ArrayList::new;
        System.out.println(make1.get().getClass() + " == " + make2.get().getClass());
    }
}

4. When Lambda Is Better Than Method Reference

Prefer a lambda when the method reference would require a mental hop to figure out what happens. A method reference is cleaner only when the name itself reads like the operation being performed.

Method reference-টি না পড়ে বোঝা যাচ্ছে না — এমন হলে lambda বেশি পরিষ্কার। শুধু method-এর নামটিই যখন operation-টা পড়ে বুঝিয়ে দেয়, তখনই method reference বেছে নিন।
Main.java
import java.util.*;
import java.util.stream.*;

class Main {
    public static void main(String[] args) {
        List<String> xs = List.of("hi", "hello", "yo");

        // Clean method reference
        xs.stream().map(String::toUpperCase).forEach(System.out::println);

        // A lambda is better here — intent is clearer
        long vowelStart = xs.stream()
                            .filter(s -> "aeiouAEIOU".indexOf(s.charAt(0)) >= 0)
                            .count();
        System.out.println("vowel-start count = " + vowelStart);
    }
}

5. Vocabulary

FormSyntaxExampleবাংলায়
StaticClass::staticMethodInteger::parseIntstatic method।
Unbound instanceClass::instanceMethodString::lengthপ্রথম argument-ই receiver।
Bound instanceobj::instanceMethodlist::addনির্দিষ্ট object-এ।
ConstructorClass::newArrayList::newনতুন instance তৈরি।

6. Practice Problems

  1. Rewrite s -> s.toUpperCase() as a method reference and use it on a list.
    s -> s.toUpperCase()-কে method reference-এ রূপান্তর করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    import java.util.stream.*;
    class Main {
        public static void main(String[] args) {
            List<String> xs = List.of("dhaka", "sylhet", "khulna");
            xs.stream().map(String::toUpperCase).forEach(System.out::println);
        }
    }
  2. Parse {"1", "2", "3"} to integers using Integer::parseInt.
    {"1","2","3"}-কে Integer::parseInt দিয়ে integer-এ convert করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    import java.util.stream.*;
    class Main {
        public static void main(String[] args) {
            List<Integer> nums = List.of("1", "2", "3").stream()
                .map(Integer::parseInt).toList();
            System.out.println(nums);
        }
    }
  3. Collect a stream into a new ArrayList using ArrayList::new.
    ArrayList::new দিয়ে stream-কে নতুন ArrayList-এ collect করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    import java.util.stream.*;
    class Main {
        public static void main(String[] args) {
            ArrayList<Integer> out = Stream.of(1, 2, 3, 4)
                .collect(Collectors.toCollection(ArrayList::new));
            System.out.println(out);
        }
    }
  4. Explain the difference between String::length (unbound) and "Hello"::length (bound).
    String::length (unbound) ও "Hello"::length (bound)-এর পার্থক্য কী?
    ✨ Show Answer

    Answer: String::length takes a String argument — the receiver — and returns its length; its type is Function<String, Integer>. "Hello"::length has the receiver already bound to the literal "Hello"; it takes no arguments and returns 5 — a Supplier<Integer>. Unbound needs a receiver later, bound already has one.

    String::length একটি String-কে receiver হিসেবে নেয় — signature Function<String, Integer>। "Hello"::length-তে receiver আগেই "Hello"-তে bound — argument ছাড়াই 5 দেয়, signature Supplier<Integer>। Unbound-এ receiver পরে দিতে হয়, bound-এ আগেই দেওয়া।

  5. Use a bound instance method reference to append all strings from a list to a StringBuilder.
    Bound instance method reference দিয়ে একটি list-এর সব string StringBuilder-এ append করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            List<String> parts = List.of("Hello", ", ", "ABCL", " TECH!");
            StringBuilder sb = new StringBuilder();
            parts.forEach(sb::append);
            System.out.println(sb);
        }
    }

Summary — Module 28

Method references are shorthand for lambdas that just delegate to an existing method. The four forms are static (Integer::parseInt), unbound instance (String::length), bound instance (list::add), and constructor (ArrayList::new). Use them when the method name itself tells the reader what the operation does — otherwise a lambda is clearer.

Method reference হলো lambda-র সংক্ষিপ্ত রূপ — যখন শুধু একটি বিদ্যমান method কল হচ্ছে। চার form: static, unbound-instance, bound-instance, constructor। যখন method name-ই operation বোঝায়, তখন method reference সবচেয়ে ভালো; নয়তো lambda-ই পরিষ্কার।

Next Module → Stream API — map, filter, reduce, collect।