Java 方法引用(Method Reference)详解
概述
方法引用是 Lambda 表达式的简化写法,当 Lambda 表达式只是调用已有方法时,用 :: 替代。
匿名内部类 → Lambda → 方法引用
new Function<T, R>() {
@Override
public R apply(T t) {
return t.toString();
}
}
↓
t -> t.toString()
↓
Object::toString一、引用静态方法
语法:ClassName::staticMethodName
Lambda → 方法引用
java
// Lambda
Function<String, Integer> lambda = s -> Integer.parseInt(s);
// 匿名内部类
Function<String, Integer> anonymous = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
};
// 方法引用
Function<String, Integer> ref = Integer::parseInt;
lambda.apply("123"); // 123
anonymous.apply("123"); // 123
ref.apply("123"); // 123常用示例
java
List<String> nums = List.of("1", "2", "3");
// 字符串转整数
nums.stream()
.map(Integer::parseInt)
.collect(Collectors.toList());
// 等价写法
nums.stream()
.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
})
.collect(Collectors.toList());
// Math类静态方法
nums.stream()
.map(Math::abs) // 方法引用
.map(new Function<Double, Double>() { // 匿名内部类
@Override
public Double apply(Double d) {
return Math.sqrt(d);
}
})
.map(Math::sqrt); // 方法引用静态方法引用要点
| 写法 | 格式 |
|---|---|
| 匿名内部类 | new Function<T, R>() { @Override public R apply(T t) { return 类名.静态方法(t); } } |
| Lambda | t -> 类名.静态方法(t) |
| 方法引用 | 类名::静态方法 |
二、引用其他类成员方法(对象::实例方法)
语法:otherObject::instanceMethodName
Lambda → 方法引用
java
// Lambda
Consumer<String> lambda = s -> System.out.println(s);
// 匿名内部类
Consumer<String> anonymous = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
// 方法引用
Consumer<String> ref = System.out::println;
lambda.accept("Hello"); // 输出: Hello
anonymous.accept("Hello"); // 输出: Hello
ref.accept("Hello"); // 输出: Hello常用示例
java
List<String> names = List.of("Tom", "Alice");
// 打印
names.forEach(System.out::println);
// 等价写法
names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
// StringBuilder追加
StringBuilder sb = new StringBuilder();
Function<String, StringBuilder> lambda = s -> sb.append(s);
Function<String, StringBuilder> anonymous = new Function<String, StringBuilder>() {
@Override
public StringBuilder apply(String s) {
return sb.append(s);
}
};
Function<String, StringBuilder> ref = sb::append;
lambda.apply("Hello"); // sb = "Hello"
anonymous.apply(" World"); // sb = "Hello World"
ref.apply("!"); // sb = "Hello World!"其他类成员方法要点
| 写法 | 格式 |
|---|---|
| 匿名内部类 | new Consumer<T>() { @Override public void accept(T t) { 对象.实例方法(t); } } |
| Lambda | t -> 对象.实例方法(t) |
| 方法引用 | 对象::实例方法 |
三、引用本类成员方法(this::实例方法)
语法:this::instanceMethodName
Lambda → 方法引用
java
public class MyClass {
private String prefix = "Result: ";
public void demo() {
List<String> list = List.of("A", "B", "C");
// 方法引用
list.forEach(this::printWithPrefix);
// 等价写法
list.forEach(new Consumer<String>() {
@Override
public void accept(String item) {
MyClass.this.printWithPrefix(item);
}
});
// 等价写法
list.forEach(item -> this.printWithPrefix(item));
}
private void printWithPrefix(String item) {
System.out.println(prefix + item);
}
}完整示例
java
public class Calculator {
private int baseValue = 10;
public List<Integer> process(List<Integer> numbers) {
return numbers.stream()
.map(this::addBase) // 方法引用
.filter(this::isAboveBase) // 方法引用
.collect(Collectors.toList());
}
// 等价写法
public List<Integer> process2(List<Integer> numbers) {
return numbers.stream()
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer n) {
return Calculator.this.addBase(n);
}
})
.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer n) {
return Calculator.this.isAboveBase(n);
}
})
.collect(Collectors.toList());
}
private int addBase(int n) {
return n + baseValue;
}
private boolean isAboveBase(int n) {
return n > baseValue;
}
}本类成员方法要点
| 写法 | 格式 |
|---|---|
| 匿名内部类 | new Function<T, R>() { @Override public R apply(T t) { return this.方法(t); } } |
| Lambda | t -> this.方法(t) |
| 方法引用 | this::方法 |
四、引用父类成员方法(super::实例方法)
语法:super::instanceMethodName
Lambda → 方法引用
java
public class Parent {
public String greet(String name) {
return "Hello, " + name;
}
}
public class Child extends Parent {
@Override
public String greet(String name) {
// 方法引用
Function<String, String> ref = super::greet;
// 等价写法
Function<String, String> anonymous = new Function<String, String>() {
@Override
public String apply(String name) {
return Child.super.greet(name);
}
};
// 等价写法
Function<String, String> lambda = name -> Child.super.greet(name);
return ref.apply(name) + " (from child)";
}
}完整示例
java
class Animal {
public void speak() {
System.out.println("Animal speaks");
}
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("Dog barks");
}
public void callSuperSpeak() {
// 方法引用
Runnable r = super::speak;
// 等价写法
Runnable anonymous = new Runnable() {
@Override
public void run() {
Dog.super.speak();
}
};
// 等价写法
Runnable lambda = () -> Dog.super.speak();
r.run(); // 输出: Animal speaks
}
}父类成员方法要点
| 写法 | 格式 |
|---|---|
| 匿名内部类 | new Runnable() { @Override public void run() { super.方法(); } } |
| Lambda | () -> super.方法() |
| 方法引用 | super::方法 |
五、引用构造方法(类名::new)
语法:ClassName::new
Lambda → 方法引用
java
// Lambda
Function<String, User> lambda = name -> new User(name);
// 匿名内部类
Function<String, User> anonymous = new Function<String, User>() {
@Override
public User apply(String name) {
return new User(name);
}
};
// 方法引用
Function<String, User> ref = User::new;
lambda.apply("Alice"); // new User("Alice")
anonymous.apply("Alice"); // new User("Alice")
ref.apply("Alice"); // new User("Alice")常用示例
java
// ArrayList构造
Supplier<ArrayList<String>> lambda = () -> new ArrayList<String>();
Supplier<ArrayList<String>> anonymous = new Supplier<ArrayList<String>>() {
@Override
public ArrayList<String> get() {
return new ArrayList<String>();
}
};
Supplier<ArrayList<String>> ref = ArrayList::new;
// String(char[])构造
Function<char[], String> lambda2 = chars -> new String(chars);
Function<char[], String> anonymous2 = new Function<char[], String>() {
@Override
public String apply(char[] chars) {
return new String(chars);
}
};
Function<char[], String> ref2 = String::new;
// 两个参数的构造
BiFunction<String, Integer, User> lambda3 = (name, age) -> new User(name, age);
BiFunction<String, Integer, User> anonymous3 = new BiFunction<String, Integer, User>() {
@Override
public User apply(String name, Integer age) {
return new User(name, age);
}
};
BiFunction<String, Integer, User> ref3 = User::new;构造方法引用实战
java
class UserDTO {
private String name;
private String email;
// getters, setters
}
class UserEntity {
private String name;
private String email;
public UserEntity(UserDTO dto) {
this.name = dto.getName();
this.email = dto.getEmail();
}
}
// 使用方法引用转换
List<UserEntity> entities = dtos.stream()
.map(UserEntity::new)
.collect(Collectors.toList());
// 等价写法
List<UserEntity> entities2 = dtos.stream()
.map(new Function<UserDTO, UserEntity>() {
@Override
public UserEntity apply(UserDTO dto) {
return new UserEntity(dto);
}
})
.collect(Collectors.toList());构造方法引用要点
| 写法 | 格式 |
|---|---|
| 匿名内部类 | new Function<T, R>() { @Override public R apply(T t) { return new 类名(t); } } |
| Lambda | t -> new 类名(t) |
| 方法引用 | 类名::new |
六、类名引用成员方法(类型::实例方法)【重点】
语法:ClassName::instanceMethodName
这是最常用的方法引用形式。第一个参数自动成为方法调用者。
规则详解
抽象方法形参对应关系:
┌────────────────────────────────────────────────────────────┐
│ 抽象方法参数: (T t, U u) │
│ │ │ │
│ ↓ ↓ │
│ 成员方法参数: 充当调用者 ← u作为成员方法的参数 │
└────────────────────────────────────────────────────────────┘方法引用的四条规则:
| 序号 | 规则 | 说明 |
|---|---|---|
| 1 | 需要函数式接口 | 方法引用必须赋值给函数式接口 |
| 2 | 方法必须已存在 | 被引用的方法必须在类中已定义 |
| 3 | 形参和返回值一致 | 被引用方法的参数(从第2个开始)与抽象方法一致,返回值一致 |
| 4 | 功能满足需求 | 逻辑符合使用场景 |
抽象方法形参详解:
| 参数位置 | 作用 | 说明 |
|---|---|---|
| 第一个参数 | 充当调用者 | 决定了可以引用哪个类中的方法 |
| 第二个到最后 | 传给被引用方法 | 跟被引用方法的形参保持一致 |
在 Stream 流中:第一个参数一般表示流里面的每一个数据。
无参成员方法(最重要)
java
// String::toUpperCase 分析
// 抽象方法: R apply(T t) → Function<String, String>
// 成员方法: String toUpperCase() → 无参方法
// Lambda
Function<String, String> lambda = s -> s.toUpperCase();
// 匿名内部类
Function<String, String> anonymous = new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
};
// 方法引用
Function<String, String> ref = String::toUpperCase;
lambda.apply("abc"); // "ABC"
anonymous.apply("abc"); // "ABC"
ref.apply("abc"); // "ABC"有参成员方法
java
// String::concat 分析
// 抽象方法: R apply(T t, U u) → BiFunction<String, String, String>
// 成员方法: String concat(String another)
// Lambda
BiFunction<String, String, String> lambda = (s1, s2) -> s1.concat(s2);
// 匿名内部类
BiFunction<String, String, String> anonymous = new BiFunction<String, String, String>() {
@Override
public String apply(String s1, String s2) {
return s1.concat(s2);
}
};
// 方法引用
BiFunction<String, String, String> ref = String::concat;
lambda.apply("Hello", " World"); // "Hello World"
anonymous.apply("Hello", " World"); // "Hello World"
ref.apply("Hello", " World"); // "Hello World"java
// String::startsWith 分析
// 抽象方法: R apply(T t, U u) → BiFunction<String, String, Boolean>
// 成员方法: boolean startsWith(String prefix)
// Lambda
BiFunction<String, String, Boolean> lambda = (s, prefix) -> s.startsWith(prefix);
// 匿名内部类
BiFunction<String, String, Boolean> anonymous = new BiFunction<String, String, Boolean>() {
@Override
public Boolean apply(String s, String prefix) {
return s.startsWith(prefix);
}
};
// 方法引用
BiFunction<String, String, Boolean> ref = String::startsWith;
lambda.apply("hello", "he"); // true
anonymous.apply("hello", "he"); // true
ref.apply("hello", "he"); // true自定义类 getter 引用
java
class Person {
private String name;
private int age;
public String getName() { return name; }
public int getAge() { return age; }
}
// Person::getName 分析
// 抽象方法: R apply(T t) → Function<Person, String>
// 成员方法: String getName() → 无参方法
// Lambda
Function<Person, String> lambda = p -> p.getName();
// 匿名内部类
Function<Person, String> anonymous = new Function<Person, String>() {
@Override
public String apply(Person p) {
return p.getName();
}
};
// 方法引用
Function<Person, String> ref = Person::getName;
// Person::getAge 分析
// 抽象方法: R apply(T t) → Function<Person, Integer>
// 成员方法: int getAge() → 无参方法
// Lambda
Function<Person, Integer> lambda2 = p -> p.getAge();
// 匿名内部类
Function<Person, Integer> anonymous2 = new Function<Person, Integer>() {
@Override
public Integer apply(Person p) {
return p.getAge();
}
};
// 方法引用
Function<Person, Integer> ref2 = Person::getAge;Stream 中的完整对比
java
List<String> names = List.of("Tom", "Alice", "Bob");
// 方法引用
List<String> result1 = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
// Lambda
List<String> result2 = names.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toList());
// 匿名内部类
List<String> result3 = names.stream()
.map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
})
.collect(Collectors.toList());类名引用成员方法要点
| 写法 | 格式 |
|---|---|
| 匿名内部类 | new Function<T, R>() { @Override public R apply(T t) { return t.方法(); } } |
| Lambda | t -> t.方法() |
| 方法引用 | 类名::方法 |
七、引用数组的构造方法(类型[]::new)
语法:Type[]::new
Lambda → 方法引用
java
// Lambda
IntFunction<int[]> lambda = length -> new int[length];
// 匿名内部类
IntFunction<int[]> anonymous = new IntFunction<int[]>() {
@Override
public int[] apply(int length) {
return new int[length];
}
};
// 方法引用
IntFunction<int[]> ref = int[]::new;
lambda.apply(5); // int[5]
anonymous.apply(5); // int[5]
ref.apply(5); // int[5]常用示例
java
// String[] 数组
IntFunction<String[]> lambda = len -> new String[len];
IntFunction<String[]> anonymous = new IntFunction<String[]>() {
@Override
public String[] apply(int length) {
return new String[length];
}
};
IntFunction<String[]> ref = String[]::new;
// toArray实战
List<String> names = List.of("Alice", "Bob", "Charlie");
// 方法引用
String[] arr1 = names.stream().toArray(String[]::new);
// Lambda
String[] arr2 = names.stream().toArray(len -> new String[len]);
// 匿名内部类
String[] arr3 = names.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int length) {
return new String[length];
}
});数组构造方法要点
| 写法 | 格式 |
|---|---|
| 匿名内部类 | new IntFunction<T[]>() { @Override public T[] apply(int len) { return new 类型[len]; } } |
| Lambda | len -> new 类型[len] |
| 方法引用 | 类型[]::new |
八、方法引用汇总表
| 类型 | 匿名内部类 | Lambda | 方法引用 |
|---|---|---|---|
| 静态方法 | new Function<T,R>(){apply(T t){return 类.方法(t);}} | t -> 类.方法(t) | 类::方法 |
| 其他类成员方法 | new Consumer<T>(){accept(T t){对象.方法(t);}} | t -> 对象.方法(t) | 对象::方法 |
| 本类成员方法 | new Function<T,R>(){apply(T t){return this.方法(t);}} | t -> this.方法(t) | this::方法 |
| 父类成员方法 | new Runnable(){run(){super.方法();}} | () -> super.方法() | super::方法 |
| 构造方法 | new Function<T,R>(){apply(T t){return new 类(t);}} | t -> new 类(t) | 类::new |
| 类名成员方法 | new Function<T,R>(){apply(T t){return t.方法();}} | t -> t.方法() | 类::方法 |
| 数组构造方法 | new IntFunction<T[]>(){apply(int i){return new 类型[i];}} | i -> new 类型[i] | 类型[]::new |
九、方法引用使用场景
Stream 中的完整对比
java
List<Person> people = List.of(
new Person("Alice", 25),
new Person("Bob", 30)
);
// ┌─────────────────────────────────────────────────────────────────────┐
// │ map - 提取字段 │
// └─────────────────────────────────────────────────────────────────────┘
// 方法引用
List<String> names1 = people.stream().map(Person::getName).collect(toList());
// Lambda
List<String> names2 = people.stream().map(p -> p.getName()).collect(toList());
// 匿名内部类
List<String> names3 = people.stream()
.map(new Function<Person, String>() {
@Override
public String apply(Person p) {
return p.getName();
}
})
.collect(toList());
// ┌─────────────────────────────────────────────────────────────────────┐
// │ forEach - 打印 │
// └─────────────────────────────────────────────────────────────────────┘
// 方法引用
people.forEach(System.out::println);
// Lambda
people.forEach(p -> System.out.println(p));
// 匿名内部类
people.forEach(new Consumer<Person>() {
@Override
public void accept(Person p) {
System.out.println(p);
}
});十、注意事项
1. 引用处必须是函数式接口
java
// ❌ 错误:方法引用不能单独使用
String::toUpperCase; // 编译错误!
// ✅ 正确:必须赋值给函数式接口
Function<String, String> func = String::toUpperCase;2. 被引用的方法形参和返回值需与抽象方法一致
java
@FunctionalInterface
interface Calculator {
int calculate(int a, int b); // 抽象方法:2个参数,返回int
}
// ✅ 正确
Calculator add = Integer::sum; // int sum(int a, int b)
Calculator subtract = Math::subtractExact; // int subtractExact(int a, int b)
// ❌ 错误:参数个数不匹配
// Calculator calc = Math::abs; // abs只有1个参数3. 被引用的方法必须已经存在
java
class Person {
public String getName() { return name; } // 方法必须存在
}
// ✅ 正确
Function<Person, String> getter = Person::getName;
// ❌ 错误:方法不存在
// Consumer<Person> c = Person::someMethod;4. 被引用的方法功能需满足当前需求
java
// 场景:需要计算字符串长度
Function<String, Integer> length = String::length; // ✅ 符合
// ❌ 错误:功能不符合
// Function<String, Integer> bad = String::toUpperCase; // 返回String不是Integer5. this/super 的作用域
java
public class Outer {
public void run() {
Runnable r = this::doSomething; // ✅ 正确
}
private void doSomething() { }
}6. 注意事项汇总
| 序号 | 注意事项 | 说明 |
|---|---|---|
| 1 | 引用处必须是函数式接口 | 方法引用不能单独存在,必须赋值给函数式接口 |
| 2 | 形参和返回值一致 | 被引用方法的参数个数、类型、返回值需与抽象方法匹配 |
| 3 | 方法必须已存在 | 只能引用已有的方法,不能引用不存在的 |
| 4 | 功能满足需求 | 被引用方法的功能逻辑需符合使用场景 |
| 5 | this/super 有作用域限制 | 只在对应类内部才能使用 |
相关标签
#Java #方法引用 #Lambda #Stream #函数式编程 #匿名内部类