The :: shortcut, static and object methods¶
โ Java 17 ยท Passing Methods Around by Name ยท 1/3
When a lambda only passes the baton¶
interface TitleAnnouncer {
void announce(String title);
}
TitleAnnouncer a = title -> System.out.println(title); // lambda
TitleAnnouncer b = System.out::println; // method reference
b.announce("Stranger Things");
The lambda receives title and hands it, untouched, to println. The method reference System.out::println says it directly: when announce() is called, call println with the same argument.
Like a lambda, it runs nothing when declared: println runs only when announce() is called.
One shortcut, four shapes¶
| # | Shape | Reference | Equivalent lambda |
|---|---|---|---|
| 1 | static method | Math::round |
x -> Math.round(x) |
| 2 | method on an object | title::startsWith |
s -> title.startsWith(s) |
| 3 | method on the parameter | String::isEmpty |
t -> t.isEmpty() |
| 4 | constructor | Episode::new |
n -> new Episode(n) |
A method reference behaves exactly like its lambda. It has no type of its own: like a lambda, it always fills a functional interface, whose parameters and return type tell Java which method to call.
Shape 1 โ A static method¶
interface PriceRounder {
long round(double price);
}
PriceRounder ref = Math::round; // same as p -> Math.round(p)
System.out.println(ref.round(15.49)); // 15
- Syntax:
ClassName::method, with no parentheses and no arguments. - The interface's parameter becomes the method's parameter.
Math.roundexists fordoubleandfloat; the interface takes adouble, so Java picks that one. No match, or two equally good matches, is a compile error.
Shape 2 โ A method on an object you have¶
interface TitleMatcher { boolean beginsWith(String prefix); }
interface TitleCheck { boolean check(); }
var title = "Stranger Things";
TitleMatcher ref = title::startsWith; // prefix -> title.startsWith(prefix)
System.out.println(ref.beginsWith("Str")); // true
TitleCheck empty = title::isEmpty; // () -> title.isEmpty()
System.out.println(empty.check()); // false
The left side is a real object, here the variable title. The method always runs on that object; the interface's parameters become its arguments, even zero of them.
When a lambda can't become a reference¶
TitleCheck c1 = title::startsWith("Str"); // โ no arguments after ::
TitleCheck c2 = title::startsWith; // โ check() has nothing to pass as a prefix
TitleCheck c3 = () -> title.startsWith("Str"); // โ
keep the lambda
A method reference is only a name: it can't carry fixed values or extra logic. It's a one-way street: every method reference can be rewritten as a lambda, but not every lambda as a method reference.
Shapes 3 and 4 are the trickier ones: the next page reads them step by step.