Stream流使用随笔

        记录下实习中项目中常用的一些方法

定时任务的使用 -- 

1、首先,在项目启动类上添加 @EnableScheduling 注解,开启对定时任务的支持。@EnableScheduling 注解的作用是发现注解 @Scheduled 的任务并在后台执行该任务。

2、编写定时任务类和方法,定时任务类通过 Spring IOC 加载,使用 @Component 注解。
3、定时方法使用 @Scheduled注解。

@Scheduled(cron="0 0 2 1 * ? * ") 通过 cron 表达式定义规则。

cron 表达式是一个字符串,该字符串由 6 个空格分为 7 个域,每一个域代表一个时间含义。 通常定义 “年” 的部分可以省略,实际常用的 Cron 表达式由前 6 部分组成。格式如下:

* :表示所有值,可解读为 “每”。 如果在 “日” 这个域中设置 *,表示每一天都会触发。

? :表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如,要在每月的 8 号触发一个操作,但不关心是周几,我们可以这么设置 0 0 0 8 * ?。

CollectionUtils工具类

CollectionUtils在真实项目中,是一个非常好用的工具类,使用非常频繁。它可以使代码更加简洁和安全。

.isEmpty

.isEqualCollection 比较两个集合中的元素是否相同,不会考虑它们的顺序。

.addAll(myList, 1, 2, 3)

.subtract(list1, list2) - 返回从集合 a 中减去集合 b 中元素后的结果。

.isEqualCollection(list1, list2) - 检查两个集合是否包含相同的元素,无论顺序如何。

.union 并集

.intersection 交集

StringUtils工具类

.isEmpty(str) - 检查字符串是否为空或为 null。

.isNotBlank(str) - 检查字符串是否不为空、不为 null,且不只包含空白字符。

StringUtils.equalsIgnoreCaseAndEmpty(a,b) 可以避免空指针问题,例如a = null

*stream流

Stream 是 Java 中用于处理集合数据的流式处理 API,它提供了一种更简洁、高效的方式来操作集合元素。

过滤数据

使用 filter 方法可以从集合中过滤出满足某个条件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

List<Integer> evenNumbers = numbers.stream()

                                     .filter(n -> n % 2 == 0) //过滤(筛选)

                                     .collect(Collectors.toList());

// evenNumbers 包含 [2, 4, 6]

映射数据

使用 map 方法可以对集合中的元素进行映射转换。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

List<Integer> nameLengths = names.stream()

                                 .map(String::length)

                                 .collect(Collectors.toList());

// nameLengths 包含 [5, 3, 7]

提取部分数据

使用 limit 方法可以限制 Stream 处理的元素数量。

List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");

List<String> firstTwoFruits = fruits.stream()

                                    .limit(2) // 按排序顺序限制

                                    .collect(Collectors.toList());

// firstTwoFruits 包含 ["apple", "banana"]

跳过部分数据

使用 skip 方法可以跳过前面的一些元素。

List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");

List<String> skippedFruits = fruits.stream()

                                   .skip(2) // 按排序顺序跳过

                                   .collect(Collectors.toList());

// skippedFruits 包含 ["cherry", "date"]

聚合操作:

使用聚合操作如 reduce 可以对集合进行汇总、计算。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

int sum = numbers.stream()

                 .reduce(0, (a, b) -> a + b);

// sum 等于 15

分组和分区:

使用 groupingBy 和 partitioningBy 方法可以对数据进行分组或分区。

List<Person> people = ... // 一组 Person 对象

// 键值为country, List<Person>为country相同的人员列表

Map<String, List<Person>> peopleByCountry

= people.stream()

.collect(Collectors.groupingBy(Person::getCountry));

// 键值为布尔值,以年龄18为分界线(分为两个区)

Map<Boolean, List<Person>> adultsAndMinors

= people.stream()

            .collect(Collectors.partitioningBy(p -> p.getAge() >= 18));

例子:

分组方法1

List<Map<String, Object>> distinctList = convertedList.stream()

            .collect(Collectors.toMap(

                map -> map.get("serviceNo"),

                Function.identity(),

                (existing, replacement) -> existing

            ))

            .values()

            .stream()

            .collect(Collectors.toList());

    collect(Collectors.toMap(...))用于将Stream中的元素映射为一个新的Map,其中的键是每个Map对象中的"serviceNo"字段的值,而值是原始的Map对象(即Function.identity()表示不做任何转换),并且如果有重复的键,则保留旧值(即(existing, replacement) -> existing表示保留旧值)。

.values()将上一步得到的Map中的所有值(Map的value集合)提取出来,返回一个Collection。

.stream()再将这个Collection转换成一个Stream,以便后续操作。

分组方法2

List<Map<String, Object>> distinctList = convertedList.stream()

    .collect(Collectors.groupingBy(map -> map.get("serviceNo")))

    .values()

    .stream()

    .flatMap(List::stream)

.collect(Collectors.toList());

在这个示例中,我们首先使用Collectors.groupingBy根据"serviceNo"字段的值将原始列表中的Map对象分组到一个Map中,然后通过values()方法获取分组后的Collection,再通过flatMap将多个分组合并为一个流,最后使用Collectors.toList()将所有的Map对象收集到一个列表中。

这样就可以得到按"serviceNo"字段分组的不同组的Map对象列表,而且不会包含重复的"serviceNo"值。

例子:

Map<Long,List<Long>> purchaseIdToGoodsIds = physicalTestingGoodsPurchases.stream()

            .collect(Collectors.groupingBy(PhysicalTestingGoodsPurchase::getPurchaseId,

                Collectors.mapping(PhysicalTestingGoodsPurchase::getGoodsId, Collectors.toList())));

列表 physicalTestingGoodsPurcha,这个列表的元素类型是PhysicalTestingGoodsPurchase。根据某个属性(purchaseId)对这个列表进行分组,并收集每个分组中元素的另一个属性(goodsId)到一个列表中。

代码执行的过程如下:

physicalTestingGoodsPurchases.stream():将 physicalTestingGoodsPurchases 列表转化为 Stream。

Collectors.groupingBy(...): 这是一个 Collector,用于按照指定的属性对 Stream 中的元素进行分组。在此例中,使用 PhysicalTestingGoodsPurchase::getPurchaseId 作为键(key),表示根据 purchaseId 进行分组。

Collectors.mapping(...): 这是内部 Collector,用于对每个分组进行进一步的处理。在此,表示对每个分组中的元素,获取它们的 goodsId 属性。

Collectors.toList(): 表示您想将每个分组中的元素(已经是 goodsId 属性的形式了)收集到一个列表中。

最终,得到一个 Map<Long, List<Long>>,其中键是 purchaseId,值是与该 purchaseId 相关的 goodsId 列表。

例如,如果有以下 physicalTestingGoodsPurchases 列表:

[

    {purchaseId: 1, goodsId: 10},

    {purchaseId: 1, goodsId: 11},

    {purchaseId: 2, goodsId: 20}

]

经过上述代码处理后,您将得到以下的映射:

{

    1: [10, 11],

    2: [20]

}

例子:

        BigDecimal totalInvoiceAmount = distinctList.stream()

            .distinct()

            .map(map -> (BigDecimal) map.get("billAmount"))

            .filter(Objects::nonNull)

            .reduce(BigDecimal.ZERO, BigDecimal::add);

.distinct()方法用于去除Stream中的重复元素,确保每个元素都是唯一的。

例子:

BigDecimal invoiceAmount

= omsOrderGoodsRepository.findAllByDeletedFalseAndOrderId(orderIds.get(i))

        .stream()

        .map(OmsOrderGoods::getReturnAmount) //获取return_amount

        .filter(Objects::nonNull) // 过滤掉为null的元素

        .reduce(orderAmounts.get(i),BigDecimal::subtract);//逐个减去

SQL

去重

使用DISTINCT关键字: DISTINCT关键字用于从查询结果中去除重复的行。

SELECT DISTINCT column1, column2 FROM your_table;

使用GROUP BY子句: GROUP BY子句通常用于分组聚合操作,但它也可以用于去重数据。您可以将要去重的列放在GROUP BY子句中,并且在SELECT中只选择那些列,这将自动去除重复的行。

SELECT column1, column2 FROM your_table GROUP BY column1, column2;

模糊查询

<if test="returnsNo != null and returnsNo != ''">

    AND oor.returns_no LIKE CONCAT('%', #{returnsNo}, '%')

</if>

日期范围查询

<if test="startDate != null and endDate != null">

    AND DATE(oor.created_date) BETWEEN #{startDate} AND #{endDate}

</if>

分组后,组内字符拼接

GROUP_CONCAT(g.`name` ORDER BY g.`name` ASC SEPARATOR ', ')

    GROUP_CONCAT:这是一个聚合函数,通常与 GROUP BY 子句一起使用。它用于将分组内的多个值合并成一个字符串。

    g.name:这是要合并的字段,通常是一个文本字段(字符串)。在这个例子中,它是 g 表中的 name 字段。

    ORDER BY g.name ASC:这部分表示在合并这些值之前,按照 name 字段的升序(ASC 表示升序)对它们进行排序。

SEPARATOR ', ':这是用于分隔合并后的值的字符串。在这个例子中,合并后的值之间将使用逗号和空格作为分隔符。

CASE 表达式

CASE

    WHEN EXISTS (

        SELECT 1

        FROM physics_chemistry_test_goods pctg

        WHERE pcs.id = pctg.physics_chemistry_test_id

        AND (pctg.status = 0 OR pctg.status IS NULL)

        ) THEN 0

        ELSE 1

        END AS status

CASE:这是一个 SQL 关键字,表示开始一个条件表达式,用于根据条件返回不同的值。

WHEN EXISTS (...) THEN 0:这是 CASE 表达式的第一个分支。它检查一个子查询是否返回了结果。如果子查询返回了至少一行记录,那么条件成立,这里的返回值是 0。

EXISTS (...):这是一个条件谓词,用于检查子查询是否返回了结果。

    SELECT 1

FROM  physics_chemistry_test_goods pctg

WHERE pcs.id = pctg.physics_chemistry_test_id

AND (pctg.status = 0 OR pctg.status IS NULL):

这是一个子查询,它从名为 physics_chemistry_test_goods 的表 pctg 中选择 1。该子查询与外部查询的表 pcs 进行了关联,通过 pcs.id = pctg.physics_chemistry_test_id 进行连接。子查询中的条件 (pctg.status = 0 OR pctg.status IS NULL) 用于筛选符合条件的记录。

    THEN 0:如果子查询返回结果,那么 CASE 表达式将返回 0。

    ELSE 1:如果子查询不返回结果,那么将会执行 ELSE 部分,这里的返回值是 1。

    END:END 标志着 CASE 表达式的结束。

    AS status:这是一个别名,它将 CASE 表达式的结果列命名为 status。

综合起来,这段代码的作用是根据条件判断子查询是否返回了符合条件的记录,如果有则返回 0,否则返回 1,最后将结果列命名为 status。

备用值

IFNULL(gs.customer_price, fpg.customer_price) AS customerPrice

    IFNULL:这是一个 SQL 函数,用于判断第一个参数是否为 NULL,如果是 NULL,则返回第二个参数的值。如果第一个参数不是 NULL,则返回第一个参数的值。

    gs.customer_price:这是第一个参数,它表示要检查是否为 NULL 的字段,通常是一个数值或者可以为 NULL 的字段。

    fpg.customer_price:这是第二个参数,如果第一个参数 gs.customer_price 是 NULL,则将返回这个字段的值。

    AS customerPrice:这是一个别名,它将 IFNULL 函数的结果列命名为 customerPrice,这样在查询结果中就可以使用 customerPrice 来引用这个值。

综合起来,这段代码的作用是检查 gs.customer_price 是否为 NULL,如果是 NULL,则返回 fpg.customer_price 的值,否则返回 gs.customer_price 的值,并将结果列命名为 customerPrice。这在处理具有备用值的情况下非常有用,以确保结果不包含 NULL 值。

待更新

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值