本文目录导读:

Java 方法引用案例详解
方法引用是 Lambda 表达式的简化写法,用 符号表示,下面通过实际案例来展示各种类型的方法引用。
方法引用的四种类型
| 类型 | 语法 | 对应 Lambda |
|---|---|---|
| 静态方法引用 | ClassName::staticMethod |
(args) -> ClassName.staticMethod(args) |
| 实例方法引用(特定对象) | instance::instanceMethod |
(args) -> instance.instanceMethod(args) |
| 实例方法引用(类类型) | ClassName::instanceMethod |
(obj, args) -> obj.instanceMethod(args) |
| 构造器引用 | ClassName::new |
(args) -> new ClassName(args) |
实战案例
案例1:静态方法引用
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
public class StaticMethodRef {
public static void main(String[] args) {
// 场景1:对列表进行排序
List<String> names = Arrays.asList("Tom", "Alice", "Bob", "Charlie");
// Lambda 写法
names.sort((s1, s2) -> String.compareToIgnoreCase(s1, s2));
// 方法引用写法(静态方法引用)
names.sort(String::compareToIgnoreCase);
System.out.println("排序结果: " + names); // [Alice, Bob, Charlie, Tom]
// 场景2:使用 Function 接口
Function<Integer, String> intToString = String::valueOf;
System.out.println(intToString.apply(123).length()); // 3
// 场景3:使用 Predicate 判断空字符串
Predicate<String> isEmpty = String::isEmpty;
System.out.println(isEmpty.test("")); // true
System.out.println(isEmpty.test("Hello")); // false
}
}
案例2:实例方法引用(特定对象)
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
public class InstanceMethodRef {
public static void main(String[] args) {
// 创建一个 StringBuilder 对象
StringBuilder sb = new StringBuilder("Hello ");
// 场景1:Consumer 接口 - 对特定对象的方法引用
Consumer<String> appendToSb = sb::append;
appendToSb.accept("World!");
System.out.println(sb.toString()); // Hello World!
// 场景2:Function 接口
List<String> names = List.of("Apple", "Banana", "Cherry");
// Lambda 写法
Function<String, Integer> lenLambda = (s) -> s.length();
// 方法引用写法(更简洁,使用特定对象的方法)
Function<String, Integer> lenRef = String::length; // 这是类类型实例方法引用
System.out.println(names.stream()
.map(String::length) // 类类型实例方法引用
.toList()); // [5, 6, 6]
// 场景3:特定对象的方法引用
List<String> toUpper = new ArrayList<>(List.of("hello", "world"));
System.out.println(toUpper.stream()
.map(String::toUpperCase)
.toList()); // [HELLO, WORLD]
}
}
案例3:实例方法引用(类类型 - 需要参数)
import java.util.Arrays;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Function;
public class ClassInstanceMethodRef {
public static void main(String[] args) {
// 场景1:比较两个字符串(忽略大小写)
List<String> words = Arrays.asList("Apple", "banana", "Cherry", "apple");
// 使用 BiPredicate 接口(接收两个参数)
BiPredicate<String, String> equalsIgnoreCase = String::equalsIgnoreCase;
System.out.println("Apple 与 apple 相等?: " +
equalsIgnoreCase.test("Apple", "apple")); // true
// 场景2:查找列表中是否存在特定元素
boolean hasApple = words.stream()
.anyMatch("apple"::equalsIgnoreCase); // 特定对象实例方法引用
System.out.println("列表包含 apple: " + hasApple); // true
// 场景3:复杂对象的方法引用
List<Person> persons = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35)
);
// 将 Person 对象映射为姓名
Function<Person, String> getName = Person::getName;
System.out.println("人员姓名: " + persons.stream()
.map(getName)
.toList()); // [Alice, Bob, Charlie]
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
案例4:构造器引用
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
public class ConstructorRef {
public static void main(String[] args) {
// 场景1:无参构造器引用
Supplier<List<String>> listFactory = ArrayList::new;
List<String> list = listFactory.get();
list.add("Hello");
System.out.println("创建的空列表: " + list); // [Hello]
// 场景2:有参构造器引用
Function<String, StringBuilder> sbFactory = StringBuilder::new;
StringBuilder sb = sbFactory.apply("Hello World");
System.out.println("构造器创建: " + sb.toString()); // Hello World
// 场景3:数组构造器引用
Function<Integer, String[]> stringArray = String[]::new;
String[] arr = stringArray.apply(5);
System.out.println("创建数组长度: " + arr.length); // 5
// 场景4:结合 Stream 使用
List<String> names = List.of("Alice", "Bob", "Charlie");
List<Student> students = names.stream()
.map(Student::new) // 构造器引用
.toList();
students.forEach(System.out::println);
}
}
class Student {
private String name;
public Student(String name) {
this.name = name;
System.out.println("为学生创建了: " + name);
}
@Override
public String toString() {
return "Student{" + "name='" + name + '\'' + '}';
}
}
案例5:综合实战 - 员工数据处理
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ComprehensiveDemo {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("张伟", 28, 18000, "技术部"),
new Employee("李娜", 35, 22000, "产品部"),
new Employee("王强", 42, 30000, "管理部"),
new Employee("赵敏", 24, 15000, "技术部"),
new Employee("钱进", 38, 25000, "市场部")
);
System.out.println("=== 原始数据 ===");
employees.forEach(System.out::println);
// 场景1:排序(方法引用)
System.out.println("\n=== 按年龄排序 ===");
employees.stream()
.sorted(Comparator.comparingInt(Employee::getAge))
.forEach(System.out::println);
// 场景2:工资过滤 + 统计
System.out.println("\n=== 工资超过20000的员工 ===");
double avgSalary = employees.stream()
.filter(e -> e.getSalary() > 20000)
.mapToInt(Employee::getSalary)
.average()
.orElse(0);
System.out.println("平均工资: " + avgSalary);
// 场景3:按部门分组
System.out.println("\n=== 按部门分组 ===");
Map<String, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
byDept.forEach((dept, empList) -> {
System.out.println(dept + ": " + empList.size() + "人");
});
// 场景4:获取所有姓名
System.out.println("\n=== 员工姓名 ===");
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
// 场景5:自定义比较器
System.out.println("\n=== 按工资降序 ===");
employees.stream()
.sorted(Comparator.comparingInt(Employee::getSalary).reversed())
.map(Employee::getName)
.forEach(e -> System.out.println("员工: " + e));
}
}
class Employee {
private String name;
private int age;
private int salary;
private String department;
public Employee(String name, int age, int salary, String department) {
this.name = name;
this.age = age;
this.salary = salary;
this.department = department;
}
// Getters
public String getName() { return name; }
public int getAge() { return age; }
public int getSalary() { return salary; }
public String getDepartment() { return department; }
@Override
public String toString() {
return String.format("%s(%d岁,工资%d,%s)", name, age, salary, department);
}
}
方法引用 vs Lambda 对照表
// 1. 静态方法引用
Function<Integer, String> f1 = String::valueOf; // 方法引用
Function<Integer, String> f2 = i -> String.valueOf(i); // Lambda
// 2. 实例方法引用(直接调用)
List<String> list = List.of("a", "b");
list.forEach(System.out::println); // 方法引用
list.forEach(s -> System.out.println(s)); // Lambda
// 3. 对象引用(比较)
Comparator<String> c1 = String::compareToIgnoreCase; // 方法引用
Comparator<String> c2 = (a, b) -> a.compareToIgnoreCase(b); // Lambda
// 4. 构造器引用
Supplier<List<String>> s1 = ArrayList::new; // 方法引用
Supplier<List<String>> s2 = () -> new ArrayList<>(); // Lambda
使用建议
✅ 适合使用方法引用:
- 已有现成的方法直接匹配函数式接口
- 代码更加简洁、易读
- 标准库中如
Stream操作
❌ 不适合使用方法引用:
- 方法调用需要额外参数(非直接匹配)
- Lambda 中代码量超过一行
- 需要进行逻辑判断或计算
// 反例:方法引用反而更复杂
Function<String, String> f = s -> {
String upper = s.toUpperCase();
return upper + "-suffix";
}; // 这种情况必须用 Lambda
方法引用的核心价值在于简化代码,让代码更具可读性,选择标准:
- 方法恰好匹配接口参数 → 使用静态引用
- 需要对对象进行操作 → 使用实例引用
- 需要创建新对象 → 使用构造器引用
- 逻辑复杂或需要额外处理 → 继续使用 Lambda
掌握方法引用的关键是要理解函数式接口的参数传递规则,当方法签名与接口方法签名匹配时,就可以使用 简化代码。