给我讲讲java中stream流的Function,Consumer,Predicate,Supplier,Optional,我不太理解它们的具体用法,最好能深入浅出,通俗易懂
一、核心功能接口
Java 的函数式接口(如 Function、Consumer 等)
是为 Lambda 表达式和 Stream 流设计的工具,它们像“零件”一样组合起来处理数据。
1. Function<T, R>:加工数据的工厂🏭
功能:接收一个输入值(T),处理后返回结果(R)。
场景:适合 转换数据,比如将字符串转成数字,或对象转DTO。
代码示例:
Function<String, Integer> strToLength = s -> s.length();
System.out.println(strToLength.apply("Hello"));
List<String> names = Arrays.asList("Alice", "Bob");
List<Integer> lengths = names.stream()
.map(strToLength)
.collect(Collectors.toList());
2. Consumer<T>:只吃不吐的大胃王🍔
功能:接收一个输入值(T),但 不返回任何结果。
场景:适合 消费数据,比如打印日志、修改对象状态。
代码示例:
Consumer<String> printer = s -> System.out.println("Value: " + s);
printer.accept("Test");
List<String> names = Arrays.asList("Alice", "Bob");
names.stream()
.forEach(printer);
3. Predicate<T>:判断题考官✅❌
功能:接收一个输入值(T),返回 boolean 值。
场景:适合 条件筛选,比如过滤集合中的元素。
代码示例:
Predicate<String> startsWithA = s -> s.startsWith("A");
System.out.println(startsWithA.test("Alice"));
List<String> names = Arrays.asList("Alice", "Bob", "Anna");
List<String> aNames = names.stream()
.filter(startsWithA)
.collect(Collectors.toList());
4. Supplier<T>:无中生有的魔法师✨
功能:不需要输入参数,直接返回一个值(T)。
场景:适合 延迟生成数据,比如生成随机数、获取配置。
代码示例:
Supplier<LocalDateTime> timeSupplier = () -> LocalDateTime.now();
System.out.println(timeSupplier.get());
Stream.generate(() -> Math.random() * 100)
.limit(5)
.forEach(System.out::println);
5. Optional<T>:防Null的保险箱🔒
功能:包装一个可能为 null 的值,强制开发者处理空值。
场景:避免 NullPointerException,明确处理可能为空的情况。
代码示例:
String name = null;
Optional<String> optName = Optional.ofNullable(name);
optName.ifPresent(s -> System.out.println(s));
String safeName = optName.orElse("Unknown");
System.out.println(safeName);
Optional<String> upperName = optName.map(String::toUpperCase);
System.out.println(upperName.orElse("N/A"));
二、对比总结
接口 输入 输出 典型用途 类比
Function<T,R> T R 数据转换(如 map 操作) 工厂加工原材料 → 成品
Consumer<T> T void 消费数据(如 forEach 操作) 吃货吃掉食物
Predicate<T> T boolean 条件判断(如 filter 操作) 判断题对错
Supplier<T> 无 T 生成数据(如 generate 操作) 魔法师凭空变物
Optional<T> - - 安全处理 null 保险箱防丢
三、组合使用案例
假设有一个需求:从用户列表中找出年龄大于18岁的用户,提取他们的名字并转为大写,最后打印。
代码实现:
java
Copy Code
List<User> users = Arrays.asList(
new User("Alice", 20),
new User("Bob", 17),
new User("Charlie", 22)
);
users.stream()
.filter(user -> user.getAge() > 18)
.map(user -> user.getName().toUpperCase())
.forEach(System.out::println);
四、关键注意事项
避免滥用 Optional:
不要用 Optional 替代所有 null,主要针对返回值可能为空的场景。
避免直接调用 Optional.get()(可能抛异常),优先用 orElse() 或 ifPresent()。
函数式接口与 Lambda 简化:
尽量用 Lambda 表达式或方法引用简化代码(如 s -> s.length() → String::length)。
注意并行流中的线程安全:
Supplier、Consumer 等接口的实现需确保线程安全。
通过理解这些接口的角色和作用,可以更灵活地编写函数式风格的 Java 代码,让 Stream 流操作更加简洁高效!