Method References — Class::method
Method Reference — lambda-র আরও সংক্ষিপ্ত ও পরিষ্কার রূপ
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.
x -> x.toString()। এই ক্ষেত্রের জন্য Java দিয়েছে method reference — Class::method। কাজ সমান, কিন্তু পরিষ্কার।
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:
Class::staticMethod, (২) unbound instance — Class::instanceMethod (যেখানে প্রথম argument-ই receiver), (৩) bound instance — instance::instanceMethod (একটি নির্দিষ্ট object-এ), (৪) constructor — Class::new।
3. Each Form in Action
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.
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
| Form | Syntax | Example | বাংলায় |
|---|---|---|---|
| Static | Class::staticMethod | Integer::parseInt | static method। |
| Unbound instance | Class::instanceMethod | String::length | প্রথম argument-ই receiver। |
| Bound instance | obj::instanceMethod | list::add | নির্দিষ্ট object-এ। |
| Constructor | Class::new | ArrayList::new | নতুন instance তৈরি। |
6. Practice Problems
-
Rewrite
s -> s.toUpperCase()as a method reference and use it on a list.s -> s.toUpperCase()-কে method reference-এ রূপান্তর করুন।✨ Show Answer
Main.javaimport 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); } } -
Parse
{"1", "2", "3"}to integers usingInteger::parseInt.{"1","2","3"}-কেInteger::parseIntদিয়ে integer-এ convert করুন।✨ Show Answer
Main.javaimport 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); } } -
Collect a stream into a new
ArrayListusingArrayList::new.ArrayList::newদিয়ে stream-কে নতুনArrayList-এ collect করুন।✨ Show Answer
Main.javaimport 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); } } -
Explain the difference between
String::length(unbound) and"Hello"::length(bound).String::length(unbound) ও"Hello"::length(bound)-এর পার্থক্য কী?✨ Show Answer
Answer:
String::lengthtakes aStringargument — the receiver — and returns its length; its type isFunction<String, Integer>."Hello"::lengthhas the receiver already bound to the literal"Hello"; it takes no arguments and returns 5 — aSupplier<Integer>. Unbound needs a receiver later, bound already has one.String::lengthএকটিString-কে receiver হিসেবে নেয় — signatureFunction<String, Integer>।"Hello"::length-তে receiver আগেই "Hello"-তে bound — argument ছাড়াই 5 দেয়, signatureSupplier<Integer>। Unbound-এ receiver পরে দিতে হয়, bound-এ আগেই দেওয়া। -
Use a bound instance method reference to append all strings from a list to a
StringBuilder.Bound instance method reference দিয়ে একটি list-এর সব stringStringBuilder-এ append করুন।✨ Show Answer
Main.javaimport 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.