函数式接口是 Java 8 引入的一个重要概念,它在函数式编程和 Lambda 表达式中起着核心作用。函数式接口是指只有一个抽象方法的接口。Java 8 提供了一些内置的函数式接口,如 Predicate
、Function
、Consumer
和 Supplier
等,同时允许开发者自定义函数式接口。
基本概念
- 函数式接口:只有一个抽象方法的接口。
- Lambda 表达式:一种简洁的匿名函数,可以用来实现函数式接口。
- 方法引用:一种简洁的方式来引用已经存在的方法或构造器。
内置函数式接口
1. Predicate<T>
Predicate
是 Java 8 引入的一个函数式接口,位于 java.util.function
包中。它代表了一个布尔值的函数,通常用于条件判断。Predicate
接口包含一个抽象方法 test
,该方法接受一个输入参数并返回一个布尔值。
Predicate 接口的主要方法
-
test(T t)
:- 参数:
T
类型的输入参数。 - 返回值:
boolean
值,表示条件是否满足。 - 用途:用于测试给定的输入是否满足某个条件。
- 参数:
-
and(Predicate<? super T> other)
:- 参数:另一个
Predicate
对象。 - 返回值:一个新的
Predicate
对象,表示两个Predicate
的逻辑与(AND)。 - 用途:组合多个条件,只有所有条件都为真时才返回
true
。
- 参数:另一个
-
or(Predicate<? super T> other)
:- 参数:另一个
Predicate
对象。 - 返回值:一个新的
Predicate
对象,表示两个Predicate
的逻辑或(OR)。 - 用途:组合多个条件,只要有一个条件为真就返回
true
。
- 参数:另一个
-
negate()
:- 参数:无。
- 返回值:一个新的
Predicate
对象,表示当前Predicate
的逻辑非(NOT)。 - 用途:反转当前条件的结果。
示例
基本使用
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> isEven = x -> x % 2 == 0;
System.out.println(isEven.test(4)); // 输出: true
System.out.println(isEven.test(3)); // 输出: false
}
}
组合使用
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> isEven = x -> x % 2 == 0;
Predicate<Integer> isPositive = x -> x > 0;
// 组合条件
Predicate<Integer> isEvenAndPositive = isEven.and(isPositive);
Predicate<Integer> isEvenOrPositive = isEven.or(isPositive);
Predicate<Integer> isNotEven = isEven.negate();
System.out.println(isEvenAndPositive.test(4)); // 输出: true
System.out.println(isEvenAndPositive.test(-4)); // 输出: false
System.out.println(isEvenOrPositive.test(4)); // 输出: true
System.out.println(isEvenOrPositive.test(-3)); // 输出: true
System.out.println(isNotEven.test(4)); // 输出: false
System.out.println(isNotEven.test(3)); // 输出: true
}
}
在集合中的应用
Predicate
常用于集合操作,如过滤集合中的元素。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Predicate<Integer> isEven = x -> x % 2 == 0;
// 过滤出偶数
List<Integer> evenNumbers = numbers.stream()
.filter(isEven)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [2, 4, 6, 8, 10]
}
}
总结
Predicate
是一个非常有用的函数式接口,适用于需要进行条件判断的场景。它可以单独使用,也可以通过 and
、or
和 negate
方法组合成更复杂的条件。在集合操作中,Predicate
与流(Stream)API 结合使用,可以实现高效的过滤和条件判断。
2. Function<T, R>
Function
是 Java 8 引入的一个函数式接口,位于 java.util.function
包中。它代表了一个从一种类型的对象转换为另一种类型的对象的函数。Function
接口包含一个抽象方法 apply
,该方法接受一个输入参数并返回一个结果。
Function 接口的主要方法
-
apply(T t)
:- 参数:
T
类型的输入参数。 - 返回值:
R
类型的结果。 - 用途:用于将输入参数转换为结果。
- 参数:
-
andThen(Function<? super R,? extends V> after)
:- 参数:另一个
Function
对象。 - 返回值:一个新的
Function
对象,表示先应用当前Function
,再应用传入的Function
。 - 用途:组合多个
Function
,形成一个链式的转换。
- 参数:另一个
-
compose(Function<? super V,? extends T> before)
:- 参数:另一个
Function
对象。 - 返回值:一个新的
Function
对象,表示先应用传入的Function
,再应用当前Function
。 - 用途:组合多个
Function
,形成一个链式的转换,但顺序与andThen
相反。
- 参数:另一个
示例
基本使用
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> stringLength = s -> s.length();
String input = "Hello, World!";
int length = stringLength.apply(input);
System.out.println(length); // 输出: 13
}
}
组合使用
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> stringLength = s -> s.length();
Function<Integer, Integer> doubleValue = i -> i * 2;
// 组合函数
Function<String, Integer> doubleStringLength = stringLength.andThen(doubleValue);
String input = "Hello, World!";
int result = doubleStringLength.apply(input);
System.out.println(result); // 输出: 26
}
}
在集合中的应用
Function
常用于集合操作,如映射集合中的元素。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry");
Function<String, Integer> stringLength = s -> s.length();
// 映射每个字符串的长度
List<Integer> lengths = words.stream()
.map(stringLength)
.collect(Collectors.toList());
System.out.println(lengths); // 输出: [5, 6, 6]
}
}
总结
Function
是一个非常有用的函数式接口,适用于需要进行类型转换的场景。它可以单独使用,也可以通过 andThen
和 compose
方法组合成更复杂的转换。在集合操作中,Function
与流(Stream)API 结合使用,可以实现高效的映射和转换操作。
3. Consumer<T>
Consumer
是 Java 8 引入的一个函数式接口,位于 java.util.function
包中。它代表了一个接受单个输入参数并且没有返回值的操作。Consumer
接口通常用于表示对数据的消费或处理操作。
Consumer 接口的主要方法
-
accept(T t)
:- 参数:
T
类型的输入参数。 - 返回值:无。
- 用途:用于对输入参数进行处理或消费。
- 参数:
-
andThen(Consumer<? super T> after)
:- 参数:另一个
Consumer
对象。 - 返回值:一个新的
Consumer
对象,表示先执行当前Consumer
,再执行传入的Consumer
。 - 用途:组合多个
Consumer
,形成一个链式的处理操作。
- 参数:另一个
示例
基本使用
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> printUpperCase = s -> System.out.println(s.toUpperCase());
String input = "hello, world!";
printUpperCase.accept(input); // 输出: HELLO, WORLD!
}
}
组合使用
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> printUpperCase = s -> System.out.println(s.toUpperCase());
Consumer<String> printLowerCase = s -> System.out.println(s.toLowerCase());
// 组合消费者
Consumer<String> printBothCases = printUpperCase.andThen(printLowerCase);
String input = "Hello, World!";
printBothCases.accept(input); // 输出: HELLO, WORLD! 和 hello, world!
}
}
在集合中的应用
Consumer
常用于集合操作,如遍历集合中的元素并对其进行处理。
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry");
Consumer<String> printUpperCase = s -> System.out.println(s.toUpperCase());
// 遍历列表并打印每个单词的大写形式
words.forEach(printUpperCase);
// 输出:
// APPLE
// BANANA
// CHERRY
}
}
总结
Consumer
是一个非常有用的函数式接口,适用于需要对数据进行处理或消费的场景。它可以单独使用,也可以通过 andThen
方法组合成更复杂的处理操作。在集合操作中,Consumer
与流(Stream)API 结合使用,可以实现高效的遍历和处理操作。
常见应用场景
- 集合遍历:使用
forEach
方法遍历集合并处理每个元素。 - 日志记录:将日志记录操作封装为
Consumer
,便于在多个地方复用。 - 数据处理:对数据进行格式化、转换或其他处理操作。
通过 Consumer
,你可以编写更加简洁和模块化的代码,提高代码的可读性和可维护性。
4. Supplier<T>
Supplier
是 Java 8 引入的一个函数式接口,位于 java.util.function
包中。它代表了一个不接受任何参数但返回一个结果的函数。Supplier
接口通常用于表示一个提供某种类型的结果的工厂方法或生成器。
Supplier 接口的主要方法
get()
:- 参数:无。
- 返回值:
T
类型的结果。 - 用途:用于生成并返回一个结果。
示例
基本使用
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
Supplier<String> messageSupplier = () -> "Hello, World!";
String message = messageSupplier.get();
System.out.println(message); // 输出: Hello, World!
}
}
生成随机数
import java.util.Random;
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);
int randomNumber = randomSupplier.get();
System.out.println(randomNumber); // 输出: 一个 0 到 99 之间的随机整数
}
}
在集合中的应用
Supplier
可以用于生成集合的初始值或默认值。
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
Supplier<List<Integer>> listSupplier = ArrayList::new;
List<Integer> myList = listSupplier.get();
myList.add(1);
myList.add(2);
myList.add(3);
System.out.println(myList); // 输出: [1, 2, 3]
}
}
在 Optional 中的应用
Supplier
也常用于 Optional
类中的 orElseGet
方法,用于提供一个默认值生成器。
import java.util.Optional;
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
Optional<String> optional = Optional.empty();
Supplier<String> defaultSupplier = () -> "Default Value";
String result = optional.orElseGet(defaultSupplier);
System.out.println(result); // 输出: Default Value
}
}
总结
Supplier
是一个非常有用的函数式接口,适用于需要生成某种类型的结果的场景。它可以单独使用,也可以与其他功能接口和类结合使用,例如在集合初始化、生成随机数、提供默认值等方面。通过 Supplier
,你可以编写更加简洁和模块化的代码,提高代码的可读性和可维护性。
常见应用场景
- 生成默认值:在
Optional
中提供默认值生成器。 - 集合初始化:生成集合的初始值或默认值。
- 随机数生成:生成随机数或随机对象。
- 配置文件加载:从配置文件中读取并返回配置值。
通过 Supplier
,你可以轻松地创建和管理生成结果的逻辑,使代码更加灵活和高效。