函数式接口是 Java 8 引入的一种接口,用于支持函数式编程。函数式接口通常包含一个抽象方法,可以被 Lambda 表达式或方法引用所实现。在本文中,我们将深入探讨函数式接口的概念、用途以及如何创建和使用函数式接口。
什么是函数式接口
函数式接口是只包含一个抽象方法的接口。但是默认方法和静态方法在此接口中可以定义多个。Java 中的函数式接口可以被用作 Lambda 表达式的目标类型。通过函数式接口,可以实现更简洁、更具可读性的代码,从而支持函数式编程的思想。
常见函数式接口
Java 中有一些内置的函数式接口,用于不同的用途:
Runnable
: 用于描述可以在单独线程中执行的任务。Callable
: 类似于 Runnable
,但可以返回执行结果或抛出异常。Comparator
: 用于比较两个对象的顺序。Function
: 接受一个参数并产生一个结果。Predicate
: 接受一个参数并返回一个布尔值,用于判断条件是否满足。Supplier
: 不接受参数,但返回一个值。自定义函数式接口
自定义函数式接口是需要在接口上添加 @FunctionalInterface
注解
定义 CustomFunctionalInterface
接口函数
@java.lang.FunctionalInterface
public interface CustomFunctionalInterface {
void execute();
}
在上述代码中,定义了一个名为 CustomFunctionalInterface
的函数式接口,其中包含一个抽象方法 execute
,这是一个无参无返回值的方法。通过使用 @FunctionalInterface
注解,明确告诉编译器这是一个函数式接口,确保它只包含一个抽象方法。
基于 CustomFunctionalInterface
使用
public class CustomFunctionInterfaceTest {
public void test(CustomFunctionalInterface functionalInterface) {
functionalInterface.execute();
}
@Test
public void execute() {
test(() -> System.out.println("Hello World Custom!"));
}
}
在测试类 CustomFunctionInterfaceTest
中,定义了一个名为 test
的方法,接受一个 CustomFunctionalInterface
参数,并在方法体中调用了 execute
方法。这个方法允许将任意实现了 CustomFunctionalInterface
的 Lambda 表达式传递进来,并执行其 execute
方法。
在测试方法 execute
中,通过调用 test
方法,传递了一个 Lambda 表达式 () -> System.out.println("Hello World Custom!")
。这个 Lambda 表达式实现了 CustomFunctionalInterface
的抽象方法 execute
,即打印了一条 "Hello World Custom!" 的消息。
常见函数式接口基本使用
Predicate
当涉及到对集合或数据进行筛选时,Java 中的函数式接口 Predicate
可以发挥重要作用。Predicate
是一个通用的函数式接口,用于定义一个接受参数并返回布尔值的操作,用于判断条件是否满足。
Predicate
函数式接口
@FunctionalInterface
public interface Predicate {
boolean test(T t);
}
基于 Predicate
进行筛选
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class PredicateExample {
public static List filterStrings(List list, Predicate predicate) {
List filteredList = new ArrayList();
for (String str : list) {
if (predicate.test(str)) {
filteredList.add(str);
}
}
return filteredList;
}
public static void main(String[] args) {
List stringList = List.of("apple", "banana", "cherry", "date", "elderberry");
Predicate lengthPredicate = str -> str.length() > 5;
List longStrings = filterStrings(stringList, lengthPredicate);
System.out.println("Long strings: " + longStrings);
}
}
在这个示例中,我们定义了一个 filterStrings
方法,它接受一个字符串列表和一个 Predicate
参数,并返回符合条件的字符串列表。在 main
方法中,我们创建了一个长度判断的 Predicate
,然后使用它来筛选出长度大于 5 的字符串。
Consumer
函数式接口 Consumer
在 Java 中用于表示接受一个参数并且没有返回值的操作。它可以用于执行一些对输入数据的处理,例如打印、修改等。
Consumer
函数式接口
@FunctionalInterface
public interface Consumer {
void accept(T t);
}
基于 Consumer
进行筛选
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerExample {
public static void processIntegers(List list, Consumer consumer) {
for (Integer num : list) {
consumer.accept(num);
}
}
public static void main(String[] args) {
List integerList = List.of(1, 2, 3, 4, 5);
Consumer squareAndPrint = num -> {
int square = num * num;
System.out.println("Square of " + num + " is: " + square);
};
processIntegers(integerList, squareAndPrint);
}
}
在这个示例中,我们定义了一个 filterStrings
方法,它接受一个字符串列表和一个 Predicate
参数,并返回符合条件的字符串列表。在 main
方法中,我们创建了一个长度判断的 Predicate
,然后使用它来筛选出长度大于 5 的字符串。
在这个示例中,我们定义了一个 processIntegers
方法,它接受一个整数列表和一个 Consumer
参数,并在方法内遍历列表,对每个元素执行 accept
方法。在 main
方法中,我们创建了一个 Consumer
实现 squareAndPrint
,它会计算每个元素的平方并打印出来。
Function
函数式接口 Function
在 Java 中用于表示一个接受一个参数并产生一个结果的操作。它可以用于执行各种转换、映射和处理操作。
Function
函数式接口
Function
接口定义了一个名为 apply
的抽象方法,接受一个参数并返回一个结果。这个接口用于表示一个对输入数据的转换操作。
@FunctionalInterface
public interface Function {
R apply(T t);
}
在上述定义中,T
表示输入类型,R
表示输出类型。
基于 Function
进行数据转换
转换为大写
import java.util.function.Function;
public class FunctionExample {
public static String convertToUpperCase(String input, Function function) {
return function.apply(input);
}
public static void main(String[] args) {
String original = "hello world";
String upperCase = convertToUpperCase(original, str -> str.toUpperCase());
System.out.println(upperCase);
}
}
在这个示例中,我们定义了一个 convertToUpperCase
方法,它接受一个字符串和一个 Function
参数,用于将输入字符串转换为大写。在 main
方法中,我们通过传递一个 Function
实现来执行转换操作。
字符串长度映射
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FunctionExample {
public static List mapStringLengths(List list, Function function) {
return list.stream()
.map(function)
.collect(Collectors.toList());
}
public static void main(String[] args) {
List strings = List.of("apple", "banana", "cherry", "date");
List lengths = mapStringLengths(strings, str -> str.length());
System.out.println(lengths);
}
}
在这个示例中,我们定义了一个 mapStringLengths
方法,它接受一个字符串列表和一个 Function
参数,用于将输入字符串映射为它们的长度。通过使用 map
操作,我们在列表中的每个字符串上执行了长度映射。
Supplier
函数式接口 Supplier
在 Java 中用于表示一个不接受参数但产生一个结果的操作。它通常用于延迟计算,只在需要时才执行操作并生成结果。
Supplier
函数式接口
Supplier
接口定义了一个名为 get
的抽象方法,用于获取一个结果。这个接口用于表示一个无参操作,只产生结果。
javaCopy code
@FunctionalInterface
public interface Supplier {
T get();
}
在上述定义中,T
表示结果的类型
基于 Supplier
进行延迟计算
随机数生成
import java.util.Random;
import java.util.function.Supplier;
public class SupplierExample {
public static int generateRandomNumber(Supplier supplier) {
return supplier.get();
}
public static void main(String[] args) {
Supplier randomSupplier = () -> new Random().nextInt(100);
int randomNumber = generateRandomNumber(randomSupplier);
System.out.println("Random number: " + randomNumber);
}
}
在这个示例中,我们定义了一个 generateRandomNumber
方法,它接受一个 Supplier
参数,并通过调用 get
方法获取随机数。在 main
方法中,我们创建了一个随机数生成的 Supplier
,然后将它传递给 generateRandomNumber
方法来获取随机数。
延迟初始化
import java.util.function.Supplier;
public class SupplierExample {
private String expensiveResource = null;
public String getExpensiveResource(Supplier supplier) {
if (expensiveResource == null) {
expensiveResource = supplier.get();
}
return expensiveResource;
}
public static void main(String[] args) {
Supplier resourceSupplier = () -> {
System.out.println("Initializing expensive resource...");
return "Expensive Resource";
};
SupplierExample example = new SupplierExample();
System.out.println(example.getExpensiveResource(resourceSupplier));
System.out.println(example.getExpensiveResource(resourceSupplier));
}
}
在这个示例中,我们定义了一个 getExpensiveResource
方法,它接受一个 Supplier
参数,并使用延迟初始化的方式获取昂贵的资源。在 main
方法中,我们创建了一个资源初始化的 Supplier
,然后多次调用 getExpensiveResource
方法,观察只有在需要时才会初始化资源。