大家好!今天我们来聊聊 Java 中一个非常有用的特性:方法引用。它可以让我们写出更简洁、更易读的代码。
1. 为什么需要方法引用?
在介绍方法引用之前,让我们先看看 Java 中以前如何实现类似的功能,以及它们存在的不足。
1.1 匿名内部类
匿名内部类可以让我们在需要时定义一个类的实例,而无需为它命名。它经常被用来实现接口或扩展抽象类。
interface MyInterface {
void operate(int a, int b);
}
public class Main {
public static void main(String[] args) {
MyInterface myInterface = new MyInterface() {
@Override
public void operate(int a, int b) {
System.out.println(a + b);
}
};
myInterface.operate(2, 3); // 输出 5
}
}
在这个例子中,我们定义了一个接口 MyInterface,它有一个 operate 方法。在 main 方法中,我们创建了一个匿名内部类,它实现了 MyInterface 接口,并重写了 operate 方法。
缺点:
-
代码冗长,可读性差。
-
需要定义一个额外的类,增加了代码的复杂度。
1.2 Lambda 表达式
Lambda 表达式是一种更简洁的语法,它可以用来表示匿名函数。
interface MyInterface {
void operate(int a, int b);
}
public class Main {
public static void main(String[] args) {
MyInterface myInterface = (a, b) -> System.out.println(a + b);
myInterface.operate(2, 3); // 输出 5
}
}
在这个例子中,我们使用 lambda 表达式 (a, b) -> System.out.println(a + b) 来实现 MyInterface 接口的 operate 方法。
缺点:
-
当 lambda 表达式只包含一个方法调用时,代码仍然显得有些冗长。
1.3 方法引用
为了解决匿名内部类和 lambda 表达式存在的缺点,Java 引入了方法引用。它可以让我们用更简洁的方式来表示 lambda 表达式,让代码更易读。
2. 什么是方法引用?
方法引用,顾名思义,就是将方法作为参数传递给另一个方法。它本质上是一种语法糖,可以让我们用更简洁的方式来表示 lambda 表达式。
好处:
-
代码更简洁:方法引用可以避免冗长的 lambda 表达式,让代码更易读。
-
更易理解:方法引用更直观地表达了代码的意图,更容易理解。
使用场景:
-
当 lambda 表达式只包含一个方法调用时,可以使用方法引用。
-
当需要传递一个方法作为参数给另一个方法时,可以使用方法引用。
使用方法引用条件:
-
方法的参数列表必须与被引用的方法的参数列表相同。
-
方法的返回类型必须与被引用的方法的返回类型相同。
表示符号:
方法引用使用双冒号 (::) 符号来表示。
3. 引用静态方法
概念说明:
我们可以使用方法引用来引用一个类的静态方法。
引用方法:
类名::静态方法名
引用格式:
interface MyInterface {
int operate(int a, int b);
}
public class Main {
public static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
MyInterface myInterface = Main::add; // 使用方法引用引用静态方法
int result = myInterface.operate(2, 3);
System.out.println(result); // 输出 5
}
}
案例演示:
在这个例子中,我们定义了一个接口 MyInterface,它有一个 operate 方法。然后我们定义了一个类 Main,它包含一个静态方法 add。在 main 方法中,我们使用方法引用 Main::add 来引用 add 方法,并将它赋值给 myInterface 变量。最后,我们调用 myInterface.operate(2, 3),它会调用 add 方法,并将结果打印出来。
4. 引用成员方法
概念说明:
我们可以使用方法引用来引用一个对象的成员方法。(局限性:不能引用所有类中的成员方法)
引用方法:
1.其它类:其它类对象::方法名
2.本类:this::方法名(非静态) && 若是静态 => new 类名()::方法名
3.父类:super::方法名
引用格式:
interface MyInterface {
String operate(String str);
}
public class Main {
public String toUpperCase(String str) {
return str.toUpperCase();
}
public static void main(String[] args) {
Main main = new Main();
MyInterface myInterface = main::toUpperCase; // 使用方法引用引用成员方法
String result = myInterface.operate("hello");
System.out.println(result); // 输出 HELLO
}
}
案例演示:
在这个例子中,我们定义了一个接口 MyInterface,它有一个 operate 方法。然后我们定义了一个类 Main,它包含一个成员方法 toUpperCase。在 main 方法中,我们创建一个 Main 对象,并使用方法引用 main::toUpperCase 来引用 toUpperCase 方法,并将它赋值给 myInterface 变量。最后,我们调用 myInterface.operate("hello"),它会调用 toUpperCase 方法,并将结果打印出来。
5. 引用构造方法
概念说明:
我们可以使用方法引用来引用一个类的构造方法。
引用方法:
类名::new
引用格式:
interface MyInterface {
Person create(String name);
}
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
MyInterface myInterface = Person::new; // 使用方法引用引用构造方法
Person person = myInterface.create("John");
System.out.println(person.name); // 输出 John
}
}
案例演示:
在这个例子中,我们定义了一个接口 MyInterface,它有一个 create 方法。然后我们定义了一个类 Person,它有一个构造方法。在 main 方法中,我们使用方法引用 Person::new 来引用 Person 的构造方法,并将它赋值给 myInterface 变量。最后,我们调用 myInterface.create("John"),它会调用 Person 的构造方法,创建一个 Person 对象,并将结果打印出来。
6. 引用数组的构造方法
概念说明:
我们可以使用方法引用来引用一个数组的构造方法。
引用方法:
类型[]::new
引用格式:
interface MyInterface {
int[] create(int length);
}
public class Main {
public static void main(String[] args) {
MyInterface myInterface = int[]::new; // 使用方法引用引用数组构造方法
int[] array = myInterface.create(5);
System.out.println(array.length); // 输出 5
}
}
案例演示:
在这个例子中,我们定义了一个接口 MyInterface,它有一个 create 方法。在 main 方法中,我们使用方法引用 int[]::new 来引用 int 数组的构造方法,并将它赋值给 myInterface 变量。最后,我们调用 myInterface.create(5),它会创建一个长度为 5 的 int 数组,并将结果打印出来。
7. 方法引用小demo
这里提供两个关于方法引用的小demo,分别展示了引用静态方法和引用成员方法的应用场景。
Demo 1:引用静态方法
这个demo展示了如何使用方法引用来简化代码,避免冗长的lambda表达式。
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class MethodReferenceDemo1 {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用lambda表达式
names.forEach(name -> System.out.println(name.toUpperCase()));
System.out.println("--------------------");
// 使用方法引用
names.forEach(String::toUpperCase);
}
}
在这个例子中,我们使用 forEach 方法来遍历 names 列表中的每个元素。
-
第一种方法使用 lambda 表达式 name -> System.out.println(name.toUpperCase()) 来将每个名字转换为大写并打印出来。
-
第二种方法使用方法引用 String::toUpperCase 来引用 String 类的 toUpperCase 方法,实现同样的功能,代码更加简洁。
Demo 2:引用成员方法
这个demo展示了如何使用方法引用来引用对象的方法,并将其作为参数传递给另一个方法。
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class MethodReferenceDemo2 {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用lambda表达式
Function<String, Integer> lengthFunction = name -> name.length();
names.forEach(name -> System.out.println(lengthFunction.apply(name)));
System.out.println("--------------------");
// 使用方法引用
names.forEach(name -> System.out.println(name.length()));
}
}
在这个例子中,我们使用 forEach 方法来遍历 names 列表中的每个元素,并打印每个名字的长度。
-
第一种方法使用 lambda 表达式 name -> name.length() 来获取每个名字的长度。
-
第二种方法使用方法引用 name::length 来直接引用 String 类的 length 方法,实现同样的功能,代码更加简洁。
结语:希望能够帮助各位看官理解 Java 中的方法引用,并能够在你的代码中灵活地使用它。感谢各位看官的观看,下期见,谢谢~