Skip to content

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); } }
Lambdat -> 类名.静态方法(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&lt;T&gt;() { @Override public void accept(T t) { 对象.实例方法(t); } }
Lambdat -> 对象.实例方法(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); } }
Lambdat -> 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); } }
Lambdat -> 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.方法(); } }
Lambdat -> 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]; } }
Lambdalen -> new 类型[len]
方法引用类型[]::new

八、方法引用汇总表

类型匿名内部类Lambda方法引用
静态方法new Function<T,R>(){apply(T t){return 类.方法(t);}}t -> 类.方法(t)类::方法
其他类成员方法new Consumer&lt;T&gt;(){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不是Integer

5. this/super 的作用域

java
public class Outer {
    public void run() {
        Runnable r = this::doSomething;  // ✅ 正确
    }
    
    private void doSomething() { }
}

6. 注意事项汇总

序号注意事项说明
1引用处必须是函数式接口方法引用不能单独存在,必须赋值给函数式接口
2形参和返回值一致被引用方法的参数个数、类型、返回值需与抽象方法匹配
3方法必须已存在只能引用已有的方法,不能引用不存在的
4功能满足需求被引用方法的功能逻辑需符合使用场景
5this/super 有作用域限制只在对应类内部才能使用

相关标签

#Java #方法引用 #Lambda #Stream #函数式编程 #匿名内部类

Knowledge4J — Java 知识库