实际项目Java1.8流处理, Optional常见用法

流处理

相信大家肯定遇到过列表需要按某个字符进行排序, 这时我们用流处理就可以很优雅的实现该功能了

java 复制代码
convert.setItems(convert.getItems().stream()
    .sorted(Comparator.comparing(
        item -> StringUtils.defaultIfBlank(item.getWarehouseName(), ""),
        Collator.getInstance(Locale.CHINESE)
    ))
    .collect(Collectors.toList()));

解释

  1. StringUtils.defaultIfBlank

    • StringUtils.defaultIfBlank(item.getWarehouseName(), "") 会返回 item.getWarehouseName() 如果它不是空或 null,否则返回空字符串 ""
  2. Comparator.comparing

    • Comparator.comparing 方法用于创建一个比较器,这里使用 Collator.getInstance(Locale.CHINESE) 来确保中文字符的正确排序。
  3. collect(Collectors.toList())

    • 将排序后的流收集为一个新的列表,并设置回 convert 对象的 items 属性。

或者在列表中对手机号进行加密等操作

java 复制代码
                // 手机号加密
                List<GetPackageListRes.GetPackageListInnerPackage> items = convert.getItems().stream()
                        .peek(item -> item.setSenderMobile(StringUtils.isBlank(item.getSenderMobile()) ? "" : AppAesUtils.aesEncrypt(item.getSenderMobile())))
                        .collect(Collectors.toList());

在Java 8的Stream API中,peekmap 是两个常用的中间操作方法,它们的功能和用途有所不同。下面是它们的区别和用法示例:

peek 方法

用途
  • peek 主要用于调试目的,它允许你在流的处理过程中打印或检查每个元素,而不改变元素本身。
  • peek 不会对流中的元素进行任何转换或修改,它只是提供了一个钩子,让你可以在流的处理过程中插入一些操作(通常是日志记录或断言)。
方法签名
java 复制代码
Stream<T> peek(Consumer<? super T> action)
示例
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> result = numbers.stream()
                             .peek(System.out::println)  // 打印每个元素
                             .filter(n -> n % 2 == 0)
                             .collect(Collectors.toList());

System.out.println(result);  // 输出: [2, 4]

在这个示例中,peek 用于打印流中的每个元素,但不会改变它们。最终的结果是 [2, 4]

map 方法

用途
  • map 用于将流中的每个元素转换为另一个形式。它接受一个函数作为参数,并将该函数应用于流中的每个元素,生成一个新的流。
  • map 是一种转换操作,它可以改变流中元素的类型或值。
方法签名
java 复制代码
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
示例
java 复制代码
List<String> words = Arrays.asList("apple", "banana", "cherry");

List<Integer> lengths = words.stream()
                             .map(String::length)  // 将每个字符串转换为其长度
                             .collect(Collectors.toList());

System.out.println(lengths);  // 输出: [5, 6, 6]

在这个示例中,map 将每个字符串转换为其长度,生成一个新的流,最终的结果是 [5, 6, 6]

总结

  • peek

    • 用于调试,不改变流中的元素。
    • 主要用于在流的处理过程中插入一些操作,如打印日志。
    • 返回类型与输入类型相同。
  • map

    • 用于转换,可以改变流中的元素。
    • 接受一个函数作为参数,将该函数应用于流中的每个元素。
    • 返回类型可以与输入类型不同。

示例对比

假设我们有一个列表,包含一些 GetSelfPickupAddressesListRes 对象,我们希望在处理过程中打印每个对象,并根据 selfPickupType 修改 receiverAddr

使用 peekmap
java 复制代码
List<GetSelfPickupAddressesListRes> listRes = ...; // 初始化列表

List<GetSelfPickupAddressesListRes> processedListRes = listRes.stream()
                                                             .peek(res -> System.out.println("Processing: " + res))
                                                             .map(res -> {
                                                                 if (GetSelfPickupAddressesListRes.SELF_PICKUP_TYPE_CABINET.equals(res.getSelfPickupType())) {
                                                                     res.setReceiverAddr(res.getReceiverAddr() + "(自提柜)");
                                                                 } else if (GetSelfPickupAddressesListRes.SELF_PICKUP_TYPE_POINT.equals(res.getSelfPickupType())) {
                                                                     res.setReceiverAddr(res.getReceiverAddr() + "(自提点)");
                                                                 }
                                                                 return res;
                                                             })
                                                             .collect(Collectors.toList());

// 打印处理后的结果
processedListRes.forEach(System.out::println);

在这个示例中:

  • peek 用于在处理每个对象时打印一条消息。
  • map 用于根据 selfPickupType 修改 receiverAddr

通过这种方式,你可以同时使用 peek 进行调试,并使用 map 进行转换。

Optional常见用法

在日常项目开发中, 我们少不了对应信息进行脱敏加密, 如果对应信息从服务调用而来, 这时我们就需要对信息进行判空处理。

在Java 8中,Optional 类提供了一种处理可能为 null 的值的优雅方式。filtermap 方法是 Optional 类中非常有用的两个方法,它们分别用于过滤和转换值。下面是对这两个方法的详细解释和示例。

filter 方法

用途
  • filter 方法用于根据给定的谓词(Predicate)来决定是否保留 Optional 中的值。
  • 如果谓词返回 true,则 Optional 中的值保持不变;如果谓词返回 false,则 Optional 变为 Optional.empty()
方法签名
java 复制代码
Optional<T> filter(Predicate<? super T> predicate)
示例
java 复制代码
Optional<String> optionalValue = Optional.of("1234567890");
Optional<String> filteredValue = optionalValue.filter(s -> s.length() > 5);

System.out.println(filteredValue.orElse("Default Value"));  // 输出: 1234567890

在这个示例中,filter 方法检查字符串的长度是否大于5。因为 "1234567890" 的长度是10,所以 filteredValue 仍然是 Optional.of("1234567890")

map 方法

用途
  • map 方法用于将 Optional 中的值转换为另一种类型。
  • 它接受一个函数(Function),并将该函数应用于 Optional 中的值,生成一个新的 Optional
方法签名
java 复制代码
<U> Optional<U> map(Function<? super T, ? extends U> mapper)
示例
java 复制代码
Optional<String> optionalValue = Optional.of("1234567890");
Optional<Integer> mappedValue = optionalValue.map(s -> s.length());

System.out.println(mappedValue.orElse(0));  // 输出: 10

在这个示例中,map 方法将字符串转换为其长度,生成一个新的 Optional<Integer>

综合示例

结合 filtermap 方法,我们可以更优雅地处理可能为 null 或空字符串的情况,并进行转换。

java 复制代码
dto.setReceiverFixtel(
    Optional.ofNullable(res.getReceiverFixtel())
            .filter(StringUtils::isNotBlank)
            .map(CommonUtil::overlayPhone)
            .orElse("")
);
解释
  1. Optional.ofNullable(res.getReceiverFixtel())

    • 创建一个 Optional 对象,如果 res.getReceiverFixtel() 返回 null,则 OptionalOptional.empty()
  2. .filter(StringUtils::isNotBlank)

    • 使用 filter 方法检查 Optional 中的值是否不是空字符串。如果值是空字符串或 null,则 Optional 变为 Optional.empty()
  3. .map(CommonUtil::overlayPhone)

    • 使用 map 方法将 Optional 中的值转换为电话号码的遮罩形式。CommonUtil::overlayPhone 是一个静态方法,假设它接受一个字符串并返回一个遮罩后的字符串。
  4. .orElse("")

    • 如果 OptionalOptional.empty(),则返回默认值 ""。否则,返回转换后的值。
再举个例子,对值进行判空后类型转换:
java 复制代码
        Optional<String> length = Optional.ofNullable(waybillBaseDto.getLength()).map(String::valueOf);
        Optional<String> width = Optional.ofNullable(waybillBaseDto.getWidth()).map(String::valueOf);
        Optional<String> height = Optional.ofNullable(waybillBaseDto.getHeight()).map(String::valueOf);
相关推荐
无心水29 分钟前
【分布式利器:腾讯TSF】10、TSF故障排查与架构评审实战:Java架构师从救火到防火的生产哲学
java·人工智能·分布式·架构·限流·分布式利器·腾讯tsf
Boilermaker19928 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
Cherry的跨界思维8 小时前
28、AI测试环境搭建与全栈工具实战:从本地到云平台的完整指南
java·人工智能·vue3·ai测试·ai全栈·测试全栈·ai测试全栈
MM_MS8 小时前
Halcon变量控制类型、数据类型转换、字符串格式化、元组操作
开发语言·人工智能·深度学习·算法·目标检测·计算机视觉·视觉检测
꧁Q༒ོγ꧂8 小时前
LaTeX 语法入门指南
开发语言·latex
njsgcs9 小时前
ue python二次开发启动教程+ 导入fbx到指定文件夹
开发语言·python·unreal engine·ue
alonewolf_999 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
一嘴一个橘子9 小时前
spring-aop 的 基础使用(啥是增强类、切点、切面)- 2
java
sheji34169 小时前
【开题答辩全过程】以 中医药文化科普系统为例,包含答辩的问题和答案
java
古城小栈9 小时前
Rust 迭代器产出的引用层数——分水岭
开发语言·rust