Java 中的方法引用
方法引用可以有不同的形式,取决于方法的来源和使用场景。主要有四种形式:
-
静态方法引用:
ClassName::staticMethod
示例:
Math::max; // 等价于 (a, b) -> Math.max(a, b)
-
实例方法引用(特定对象的方法):
instance::instanceMethod
示例:
System.out::println; // 等价于 x -> System.out.println(x)
-
实例方法引用(任意对象的方法):
ClassName::instanceMethod
示例:
String::toLowerCase; // 等价于 x -> x.toLowerCase()
-
构造方法引用:
ClassName::new
示例:
ArrayList::new; // 等价于 () -> new ArrayList<>()
- 方法引用有四种主要形式:静态方法引用、实例方法引用(特定对象或任意对象)、以及构造方法引用。它们是简化 Lambda 表达式的方式。
import java.util.function.Supplier;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static void main(String[] args) {
// 构造函数引用
Supplier<Person> personSupplier = Person::new;
// 实例方法引用(任意对象)
Supplier<String> nameSupplier = personSupplier.get()::getName;
// 使用实例方法引用
System.out.println(nameSupplier.get()); // 打印 name
}
}
Supplier
是 Java 8 引入的一个函数式接口,位于 java.util.function
包中。它的主要作用是提供一个结果,不接收任何输入参数。Supplier
常用于需要延迟计算或惰性求值的场景,也就是在需要时提供一个值,而不立即计算或创建它。
Supplier
的定义
Supplier
是一个泛型接口,定义如下:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
T
:代表返回值的类型。get()
:是唯一需要实现的方法,调用它会返回类型T
的值。
使用场景
Supplier
通常用于生成或提供一个值、对象,或者用于懒加载。当我们想要推迟某些计算直到调用方真正需要它时,Supplier
就非常有用。
示例 1:基本使用 Supplier
下面的例子展示了如何使用 Supplier
来提供一个字符串:
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
// 使用 Supplier 提供一个字符串
Supplier<String> stringSupplier = () -> "Hello, World!";
// 调用 get() 获取结果
System.out.println(stringSupplier.get()); // 输出 "Hello, World!"
}
}
在这个例子中,Supplier<String>
是一个返回字符串的 Supplier
,调用 get()
方法时返回 "Hello, World!"
。
示例 2:使用 Supplier
延迟计算
Supplier
还可以用于延迟计算,例如只有在需要的时候才计算某个值:
import java.util.function.Supplier;
public class LazyEvaluationExample {
public static void main(String[] args) {
Supplier<Double> randomSupplier = () -> Math.random();
// 延迟生成随机数
System.out.println("First call: " + randomSupplier.get());
System.out.println("Second call: " + randomSupplier.get());
}
}
每次调用 randomSupplier.get()
都会生成一个新的随机数。这就是 Supplier
的延迟计算的优势,只有在真正需要时才会执行。
示例 3:使用 Supplier
创建对象
Supplier
还可以用于创建对象,尤其是在构造函数引用中非常常见。
import java.util.function.Supplier;
public class Person {
private String name;
public Person() {
this.name = "John Doe";
}
public String getName() {
return name;
}
public static void main(String[] args) {
// 使用 Supplier 提供一个 Person 实例
Supplier<Person> personSupplier = Person::new;
// 延迟创建 Person 对象
Person person = personSupplier.get();
System.out.println("Person's name: " + person.getName()); // 输出 "John Doe"
}
}
在这个例子中,Person::new
是构造方法引用,返回一个新的 Person
实例。Supplier
提供了一种惰性加载对象的方式,只有在 get()
被调用时才创建 Person
对象。
Supplier<T>
是一个不接受任何参数,但会返回类型T
的值的函数式接口。- 它用于延迟计算、惰性求值或者对象创建。
- 通过调用
get()
方法,可以获取由Supplier
提供的值或对象。
Supplier
常用于需要提供值的场景,特别是在不确定何时需要这个值时,它是延迟计算的有效工具。
如果你需要一个能够接受参数并返回结果的函数式接口,那么应该使用 Java 8 中的另一个函数式接口,而不是 Supplier
。Supplier
只适用于不需要参数的场景。如果需要传递参数并返回结果,可以使用以下接口:
1. Function<T, R>
:接收一个参数并返回一个结果
- 定义:
Function<T, R>
接收一个类型为T
的参数,并返回一个类型为R
的结果。
示例:使用 Function
接收参数并返回结果
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
// 定义一个 Function:接收一个字符串并返回它的长度
Function<String, Integer> lengthFunction = str -> str.length();
// 调用 apply() 方法传递参数并获取结果
System.out.println(lengthFunction.apply("Hello")); // 输出 5
}
}
T
:输入参数的类型。R
:返回值的类型。apply(T t)
:方法用于接收输入参数并返回结果。
2. BiFunction<T, U, R>
:接收两个参数并返回一个结果
- 定义:
BiFunction<T, U, R>
接收两个参数,T
和U
,并返回一个类型为R
的结果。
示例:使用 BiFunction
接收两个参数并返回结果
import java.util.function.BiFunction;
public class BiFunctionExample {
public static void main(String[] args) {
// 定义一个 BiFunction:接收两个整数并返回它们的乘积
BiFunction<Integer, Integer, Integer> multiplyFunction = (a, b) -> a * b;
// 调用 apply() 方法传递两个参数并获取结果
System.out.println(multiplyFunction.apply(5, 3)); // 输出 15
}
}
T
:第一个输入参数的类型。U
:第二个输入参数的类型。R
:返回值的类型。apply(T t, U u)
:方法用于接收两个输入参数并返回结果。
3. Consumer<T>
:接收一个参数但不返回结果
- 定义:
Consumer<T>
接收一个类型为T
的参数,但不返回任何结果(类似于void
方法)。
示例:使用 Consumer
接收参数但不返回结果
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
// 定义一个 Consumer:接收一个字符串并打印出来
Consumer<String> printConsumer = str -> System.out.println(str);
// 调用 accept() 方法传递参数
printConsumer.accept("Hello, World!"); // 输出 "Hello, World!"
}
}
T
:输入参数的类型。accept(T t)
:方法用于接收输入参数,不返回结果。
4. BiConsumer<T, U>
:接收两个参数但不返回结果
- 定义:
BiConsumer<T, U>
接收两个类型的参数,但不返回结果。
示例:使用 BiConsumer
接收两个参数但不返回结果
import java.util.function.BiConsumer;
public class BiConsumerExample {
public static void main(String[] args) {
// 定义一个 BiConsumer:接收两个参数并打印
BiConsumer<String, Integer> printConsumer = (name, age) ->
System.out.println(name + " is " + age + " years old");
// 调用 accept() 方法传递两个参数
printConsumer.accept("Alice", 25); // 输出 "Alice is 25 years old"
}
}
总结:
Supplier<T>
:不接收任何参数,返回类型T
的结果。Function<T, R>
:接收一个参数,返回类型R
的结果。BiFunction<T, U, R>
:接收两个参数,返回类型R
的结果。Consumer<T>
:接收一个参数,不返回结果。BiConsumer<T, U>
:接收两个参数,不返回结果。
根据需要选择合适的函数式接口来处理带参的场景。