# 一.JDK8 的增强

# 1.Lambda 表达式

  • Lambda 表达式是一个匿名方法,将行为像数据一样进行传递。
  • Lambda 表达式的常见结构:BinaryOperator<Integer>add=(×,y)→×+y
  • 函数接口指仅具有单个抽象方法的接口,用来表示 Lambda 表达式的类型。

# 2.jdk8 增强与新特性

Java 8 引入了许多新的语言特性和 API 改进,以下是其中一些主要的特性:

  1. Lambda 表达式: Lambda 表达式是一种更简洁的语法,用于表示一个匿名函数。它使得在集合操作、事件处理等场景下代码更具可读性和简洁性。
  2. 函数式接口: Java 8 引入了函数式接口的概念,这是只包含一个抽象方法的接口。Lambda 表达式可以与函数式接口一起使用。
  3. 方法引用: 方法引用允许你直接引用现有的方法或构造函数,从而使代码更加简洁。
  4. 默认方法和静态方法: 接口现在可以包含默认方法和静态方法的实现。这使得在接口中添加新的方法时,不会破坏已有的实现。
  5. Stream API: Stream API 提供了一种更便捷的方式来处理集合数据。它支持函数式编程风格,可以用于过滤、映射、归约等操作。
  6. 新的日期和时间 API: Java 8 引入了 java.time 包,提供了全新的日期和时间 API,解决了旧的 DateCalendar 类存在的问题。
  7. Optional 类: Optional 是一个容器类,用于表示一个值可能存在,也可能不存在的情况,从而减少空指针异常的发生。
  8. Nashorn 引擎: Nashorn 是一个新的轻量级、高性能的 JavaScript 引擎,用于在 Java 程序中执行 JavaScript 代码。
  9. 新的重复注解和类型注解: 如前所述,Java 8 引入了对多重注解的支持,以及更丰富的类型注解。
  10. PermGen 空间被移除: Java 8 中,永久代(PermGen)被元空间(Metaspace)所取代,用于存放类的元数据。

# 3.Stream 的组成与特点

Stream(流)是一个来自数据源的元素队列并支持聚合操作:

  • 元素是特定类型的对象,形成一个队列。Java中的Stream不会向集合那样存储和管理元素,而是按需计算
  • 数据源流的来源可以是集合Collection、数组ArrayI/O channel, 产生器generator
  • 聚合操作类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted

和以前的Collection操作不同, Stream 操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。这样做可以对操作进行优化, 比如延迟执行(laziness evaluation)和短路( short-circuiting)
  • 内部迭代:以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。Stream提供了内部迭代的方式, 通过访问者模式 (Visitor)实现。

和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。

# 4.Stream 底层原理

示例代码:

public class Java8_01_Source_Main {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Red");
        list.add("Green");
        list.add("Blue");
        long lengthyColors = list.stream().filter(c -> c.length() > 3).count();
        System.out.println(lengthyColors);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
javap -c -p Java8_01_Source_Main  查看class文件
1
> javap -c -p  Java8_01_Source_Main
警告: 二进制文件Java8_01_Source_Main包含com.xiaofei.antjava8.源码.Java8_01_Source_Main
Compiled from "Java8_01_Source_Main.java"
public class com.xiaofei.antjava8.源码.Java8_01_Source_Main {
  public com.xiaofei.antjava8.源码.Java8_01_Source_Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #4                  // String Red
      11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      16: pop
      17: aload_1
      18: ldc           #6                  // String Green
      20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      25: pop
      26: aload_1
      27: ldc           #7                  // String Blue
      29: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      34: pop
      35: aload_1
      36: invokeinterface #8,  1            // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
      41: invokedynamic #9,  0              // InvokeDynamic #0:test:()Ljava/util/function/Predicate;
      46: invokeinterface #10,  2           // InterfaceMethod java/util/stream/Stream.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
      51: invokeinterface #11,  1           // InterfaceMethod java/util/stream/Stream.count:()J
      56: lstore_2
      57: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
      60: lload_2
      61: invokevirtual #13                 // Method java/io/PrintStream.println:(J)V
      64: return

  private static boolean lambda$main$0(java.lang.String);  // c -> c.length() > 3
    Code:
       0: aload_0
       1: invokevirtual #14                 // Method java/lang/String.length:()I
       4: iconst_3
       5: if_icmple     12
       8: iconst_1
       9: goto          13
      12: iconst_0
      13: ireturn
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

分析结论:

通过字节码可以看到 invokedynamic 指令以某种方式负责创建 Predicate 实例。

此方法以 字符串 作为输入,然后执行以下步骤:

  • 计算输入长度(invokevirtual on length)
  • 将长度与常量 3 进行比较(if_icmple 和 iconst_3)
  • 如果长度小于或等于 3,则返回 false

Java 7 中之前,JVM 只是有四个方法调用类型:

  • invokevirtual 调用正常类方法,
  • invokestatic 调用静态方法,
  • invokeinterface 调用接口的方法,
  • invokespecial 调用构造函数或私有方法。

对于 lambda 表达式,Java 不是在编译时创建匿名内部类,而是在运行时通过调用动态创建它们

# 5.回调函数

#回调函数的写法  有套路的
#消息确认成功回调函数
ConfirmCallback ackCallback (deliveryTag,multiple)->{
}:
#消息确认失败回调函数
ConfirmCallback nackCallback (deliveryTag,multiple)->(
#准备消息的监听器监听哪些消息成功了哪些消息失败了
#异步通知
channel..addConfirmListener(ackCallback,nackCallback);
1
2
3
4
5
6
7
8
9

# 6.flatMap

public static void main(String[] args) {
        List<Integer> lista = new ArrayList<>();
        lista.add(1);
        lista.add(3);

        List<Integer> listb = new ArrayList<>();
        listb.add(2);
        listb.add(4);
        List<List<Integer>> listc = new ArrayList<>();
        listc.add(lista);
        listc.add(listb);
        System.out.println(listc);
        List<Integer> listd = listc.stream().flatMap(ele -> ele.stream()).collect(Collectors.toList());
        System.out.println(listd);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Map<String,List<Object>>使用java8转为 List<Object>

public static void main(String[] args) {
        Map<String, List<Integer>> map = new HashMap<>();
        map.put("1", Arrays.asList(1, 2, 3));
        map.put("2", Arrays.asList(4, 5, 6));
        map.put("3", Arrays.asList(7, 8, 9));
        // 假设已经将数据存储到map中
        List<Integer> list = map.values().stream()
                .flatMap(List::stream)
                .collect(Collectors.toList());
        // 将所有List<Object>对象中的元素合并成一个Stream,并将所有元素收集到一个新的List<Object>中
        log.info(list.toString());
    }
1
2
3
4
5
6
7
8
9
10
11
12
final List<StoreSkuInvSalDTO> collect = groupName_2_salDatas.values().stream()
                .flatMap(x -> x.getProducts().stream())
                .collect(Collectors.toList());
1
2
3

# 二.筛选

# 1.filter 过滤

//筛选符合条件的数据
List<DdlNode> collect = dagConf.getNodes().stream().filter(t -> NodeTypeEnum.OUT.name().equalsIgnoreCase(t.getType()))
    .collect(Collectors.toList());
1
2
3
//或者条件
storeDay += dayStoreSkuSizeInvSalDTOList.stream().filter(p1 -> p1.getFlag() == 1 || p1.getFlag() == 3).count();
1
2
//并且条件
storeDay += dayStoreSkuSizeInvSalDTOList.stream().filter(p1 -> p1.getFlag() == 1 && p1.getFlag() == 3).count();
1
2

# 2.筛选是否存在

  final boolean exist = value.stream()
                    .filter(x -> x.getFlag().equals(FlagEnum.RED.getCode())).collect(Collectors.toList()).size() > 0;
1
2

# 3.最小最大

//最小值
final Integer minWeek = timeAxisDTOS.stream().min(Comparator.comparing(x -> x.getFinancialWeek())).get().getFinancialWeek();

//最大值
final Integer maxWeek = timeAxisDTOS.stream().max(Comparator.comparing(x -> x.getFinancialWeek())).get().getFinancialWeek();
1
2
3
4
5

# 4.找到第一个存在的

final Optional<AdsDimFinancialYearWeekInfoDO> first = dimList.stream().filter(t -> t.getFinancialYear().equals(finalYear)&& t.getFinancialYearWeek().equals(finalWeek)).findFirst();
if (first.isPresent()) {
final AdsDimFinancialYearWeekInfoDO yearWeekInfo = first.get();
}
1
2
3
4

# 5.多条件筛选

final Set<String> headerFilterList = pageQuery.getHeaderFilterList();
        if (CollectionUtils.isNotEmpty(headerFilterList)) {
            tags = tags.stream().filter(t -> headerFilterList.contains("salQty") ? t.getSalQty() > 0 : true)
                    .filter(t -> headerFilterList.contains("replenishQty") ? t.getReplenishQty() > 0 : true)
                    .filter(t -> headerFilterList.contains("orderNotArriveQty") ? t.getOrderNotArriveQty() > 0 : true)
                    .filter(t -> headerFilterList.contains("replenishNotArriveQty") ? t.getReplenishNotArriveQty() > 0 : true)
                    .collect(Collectors.toList());
        }
1
2
3
4
5
6
7
8

# 6.模糊筛选

final String productCode = pageQuery.getProductCode();
        if (StringUtils.isNotEmpty(productCode)) {
            tags = tags.stream().filter(t -> t.getProductCode() != null && t.getProductCode().indexOf(productCode) > -1).collect(Collectors.toList());
        }
1
2
3
4

# 7.或者筛选

final Set<String> invQtyList = pageQuery.getInvQtyList();
        if (CollectionUtils.isNotEmpty(invQtyList)) {
            if (!invQtyList.contains("A") && !invQtyList.contains("B") && invQtyList.contains("C") && invQtyList.contains("D")) {
                tags = tags.stream().filter(t -> t.getInvQty() >= 50)
                        .collect(Collectors.toList());
            } else {
                tags = tags.stream().filter(t ->
                        (invQtyList.contains("A") && t.getInvQty() <= 0) ||
                                (invQtyList.contains("B") && t.getInvQty() > 0 && t.getInvQty() < 50) ||
                                (invQtyList.contains("C") && t.getInvQty() > 50 && t.getInvQty() < 300) ||
                                (invQtyList.contains("D") && t.getInvQty() >= 300)

                ).collect(Collectors.toList());
            }
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 8.反射筛选

 final Set<String> headerFilterList = pageQuery.getHeaderFilterList();
        if (CollectionUtils.isNotEmpty(headerFilterList) && !headerFilterList.contains(CommonConstant.ALL)) {
            for (String item : headerFilterList) {
                if (StringUtils.equals("replenishQty", item) || StringUtils.equals("orderNotArriveQty", item) || StringUtils.equals("replenishNotArriveQty", item)) {
                    tags = tags.stream().filter(t -> Objects.nonNull(Reflect.on(t).field(item).get()) && (Integer) Reflect.on(t).field(item).get() != 0).collect(Collectors.toList());
                } else {
                    tags = tags.stream().filter(t -> Objects.nonNull(Reflect.on(t).field(item).get()) && (Integer) Reflect.on(t).field(item).get() > 0).collect(Collectors.toList());
                }
            }
        }
1
2
3
4
5
6
7
8
9
10

# 9.条件成立才过滤

products = products.stream()
                        .filter(x -> StringUtils.equals(x.getCategoryName1(), categoryName1))
                        .filter(x -> StringUtils.isEmpty(genderName) || StringUtils.equals(x.getGenderName(), genderName))
                        .filter(x -> StringUtils.equals(x.getIsnewFlag(), "0"))
                        .collect(Collectors.toList());
1
2
3
4
5

# 10.Match

  • anyMatch: 匹配到任何一个元素和指定的元素相等,返回 true
  • allMatch():匹配到全部元素和指定的元素相等,返回 true
  • noneMatch():与 allMatch() 效果相反
List<String> strList = ListUtil.toList("a", "b", "c", "d");
        boolean a = Optional.ofNullable(strList).orElseGet(ListUtil::toList)
                .stream()
                .anyMatch(obj -> obj.equals("a"));
        System.out.println("anyMatch()测试多元素结果:" + a);
1
2
3
4
5

# 三.排序

# 1.单排序

properties.sort(Comparator.comparing(x -> x.distance));
list.sort(Comparator.comparing(UserInformation::getName));

//正序
list=list.stream().sorted().collect(Collectors.toList());
list.stream().sorted(Comparator.comparing(Student::getAge))

//逆序
list.stream().sorted(Comparator.reverseOrder())
list.stream().sorted(Comparator.comparing(Student::getAge).reversed())
1
2
3
4
5
6
7
8
9
10

# 2.双排序

timeAxisList.sort(Comparator.comparing(TimeAxisDTO::getFinancialYear).thenComparing(TimeAxisDTO::getFinancialWeek));
1

多字段排序:

list.sort(Comparator.comparing(UserInformation::getId).thenComparing(UserInformation::getAge));
1

多字段排序,指定正序还是倒序:

/**
     * 按照推荐、置顶、发布时间来排序
     * @param list
     */
private static void sort(List<Article> list){
    List<Article> sortList = list.stream()            .sorted(Comparator.comparing(Article::getRecommend,Comparator.reverseOrder())
                    .thenComparing(Article::getTop,Comparator.reverseOrder())
                    .thenComparing(Article::getReleaseTime,Comparator.reverseOrder()))
            .collect(Collectors.toList());
    sortList.stream().forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11

# 3.自定义排序

List<String> sortListA = Arrays.asList("2023", "2022", "2021", "2020", "2019", "2018", "2017");
List<String> sortListB = Arrays.asList("春", "夏", "秋", "冬");
value = value.stream().sorted(Comparator.comparing(TotalListRegionSeasonDTO::getRegionNo, Comparator.comparing(sortListA::indexOf))
                        .thenComparing(TotalListRegionSeasonDTO::getSeasonName, Comparator.comparing(sortListB::indexOf))).collect(Collectors.toList());
1
2
3
4

# 4.反转排序

salListsTopN.sort(Comparator.comparing(SalList::getSalQty).reversed());
1

# 5.中文拼音排序

List<String> sortList = Arrays.asList("春", "夏", "秋", "冬");
Collator collator = Collator.getInstance(Locale.CHINA);
styleCategoryDim = styleCategoryDim.stream().sorted(Comparator.comparing(StyleCategoryDataDTO::getSeasonName, Comparator.comparing(sortList::indexOf))
.thenComparing(StyleCategoryDataDTO::getStyleCategoryName, collator)).collect(Collectors.toList());
1
2
3
4

# 6.list 嵌套排序

List<List<String>>排序
1
/**
 * List<List<String>> 排序算法
 *
 * @author : qinyingjie
 * @version : 2.2.0
 * @date : 2022/12/12 11:22
 */
public class Java8_09_stream_sort {

    private static List<List<String>> METHOD_LIST_WITH_ORDER = new LinkedList<>();

    /**
     * 按第n位降序排列
     *
     * @param compareIndex
     */
    private static void doSortDesc(int compareIndex) {
        for (int i = 0; i < METHOD_LIST_WITH_ORDER.size() - 1; i++) {
            int preIndex = i;
            int currentIndex = i + 1;
            Long currentItem = Long.valueOf(METHOD_LIST_WITH_ORDER.get(currentIndex).get(compareIndex));
            List<String> currentObject = METHOD_LIST_WITH_ORDER.get(currentIndex);

            //当前节点的值大于前一节点,交换,且是循环比较
            while (preIndex >= 0 && currentItem > Long.valueOf(METHOD_LIST_WITH_ORDER.get(preIndex).get(compareIndex))) {
                METHOD_LIST_WITH_ORDER.set(preIndex + 1, METHOD_LIST_WITH_ORDER.get(preIndex));
                preIndex--;
            }
            //设置preIndex + 1的值
            METHOD_LIST_WITH_ORDER.set(preIndex + 1, currentObject);
        }
    }

    public static void main(String[] args) {
        METHOD_LIST_WITH_ORDER.add(Arrays.asList("1", "3", "4", "5"));
        METHOD_LIST_WITH_ORDER.add(Arrays.asList("1", "3", "4", "4"));
        METHOD_LIST_WITH_ORDER.add(Arrays.asList("1", "3", "4", "7"));
        METHOD_LIST_WITH_ORDER.add(Arrays.asList("1", "3", "4", "1"));
        METHOD_LIST_WITH_ORDER.add(Arrays.asList("2", "3", "4", "9"));
        doSortDesc(3);
        for (List<String> list : METHOD_LIST_WITH_ORDER) {
            for (String s : list) {
                System.out.print(s + ",");
            }
            System.out.println();
        }
        System.out.println(JSON.toJSONString(METHOD_LIST_WITH_ORDER));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 7.多字段升降不定

 final String sortName = pageQuery.getSortname();
        final String sortOrd = pageQuery.getSortord();
        tags = tags.stream().sorted(
                ("sal_qty".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getSalQty, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                        "total7_sal_qty".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getTotal7SalQty, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                "total14_sal_qty".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getTotal14SalQty, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                        "total28_sal_qty".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getTotal28SalQty, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                "total_sal_qty".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getTotalSalQty, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                        "total_size_store_day".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getTotalSizeStoreDay, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                                "counter_date".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getCounterDate, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                                        "inv_store_count".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getInvStoreCount, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                                                "total_sal_qty_store_rate".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getTotalSalQtyStoreRate, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                                                        "total30_sal_qty_store_rate".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getTotal30SalQtyStoreRate, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                                                                "replenish_not_arrive_qty".equals(sortName) ? Comparator.comparing(ProductAllexinfoV1DTO::getReplenishNotArriveQty, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()) :
                                                                                                        Comparator.comparing(ProductAllexinfoV1DTO::getSalQty, StringUtils.equals(sortOrd, "desc") ? Comparator.reverseOrder() : Comparator.naturalOrder()))
        ).collect(Collectors.toList());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 8.反射排序

public static void main(String[] args) {
        final String sortName = "counterDate";
//        final String sortOrd = "desc";
        final String sortOrd = "asc";

        List<ProductAllexinfoV1DTO> tags = new ArrayList<>();
        ProductAllexinfoV1DTO do1 = new ProductAllexinfoV1DTO();
        do1.setSalQty(26);
        do1.setCounterDate("2023-01-01");
        tags.add(do1);

        ProductAllexinfoV1DTO do2 = new ProductAllexinfoV1DTO();
        do2.setSalQty(233);
        do2.setCounterDate(null);
        tags.add(do2);

        ProductAllexinfoV1DTO do3 = new ProductAllexinfoV1DTO();
        do3.setSalQty(56);
        do3.setCounterDate("2023-03-01");
        tags.add(do3);

        tags.sort((o1, o2) -> {
            final Object object1 = Reflect.on(o1).field(sortName).get();
            final Object object2 = Reflect.on(o2).field(sortName).get();
           if (Objects.isNull(object1) && Objects.isNull(object2)) return 0;
            if (Objects.isNull(object1)) return 1;
            if (Objects.isNull(object2)) return -1;
            if (object1 instanceof String) {
                return StringUtils.equals(sortOrd, "desc") ? Comparator.<String>reverseOrder().compare((String) object1, (String) object2) :
                        Comparator.<String>naturalOrder().compare((String) object1, (String) object2);
            } else if (object1 instanceof Integer) {
                return StringUtils.equals(sortOrd, "desc") ? Comparator.<Integer>reverseOrder().compare((Integer) object1, (Integer) object2) :
                        Comparator.<Integer>naturalOrder().compare((Integer) object1, (Integer) object2);
            } else if (object1 instanceof BigDecimal) {
                return StringUtils.equals(sortOrd, "desc") ? Comparator.<BigDecimal>reverseOrder().compare((BigDecimal) object1, (BigDecimal) object2) :
                        Comparator.<BigDecimal>naturalOrder().compare((BigDecimal) object1, (BigDecimal) object2);
            }
            return 0;
        });
        System.out.println(JSONArray.toJSONString(tags));
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

测试filter:

 public static void main(String[] args) {
        final String sortName = "counterDate";
//        final String sortOrd = "desc";
        final String sortOrd = "asc";

        List<ProductAllexinfoV1DTO> tags = new ArrayList<>();
        ProductAllexinfoV1DTO do1 = new ProductAllexinfoV1DTO();
        do1.setSalQty(26);
        do1.setCounterDate("2023-01-01");
        do1.setReplenishQty(111);
        tags.add(do1);

        ProductAllexinfoV1DTO do2 = new ProductAllexinfoV1DTO();
        do2.setSalQty(233);
        do2.setCounterDate(null);
        do2.setReplenishQty(0);
        tags.add(do2);

        ProductAllexinfoV1DTO do3 = new ProductAllexinfoV1DTO();
        do3.setSalQty(56);
        do3.setCounterDate("2023-03-01");
        do3.setReplenishQty(131);
        tags.add(do3);

        final Set<String> headerFilterList = new HashSet<>();
        headerFilterList.add("replenishQty");
        if (CollectionUtils.isNotEmpty(headerFilterList) && !headerFilterList.contains(CommonConstant.ALL)) {
            for (String item : headerFilterList) {
                if (StringUtils.equals("replenishQty", item) || StringUtils.equals("orderNotArriveQty", item) || StringUtils.equals("replenishNotArriveQty", item)) {
                    tags.stream().filter(t -> Objects.nonNull(Reflect.on(t).field(item).get()) && (Integer) Reflect.on(t).field(item).get() != 0).collect(Collectors.toList());
                } else {
                    tags.stream().filter(t -> Objects.nonNull(Reflect.on(t).field(item).get()) && (Integer) Reflect.on(t).field(item).get() > 0).collect(Collectors.toList());
                }
            }
        }
        System.out.println(JSONArray.toJSONString(tags));
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 9.不用 stream 排序

// 正序
list.sort(Comparator.comparing(Integer::intValue));
// 倒序
list.sort(Comparator.comparing(Integer::intValue).reversed());
// 正序
list.sort(Comparator.comparing(Student::getAge));
// 倒序
list.sort(Comparator.comparing(Student::getAge).reversed());
1
2
3
4
5
6
7
8

# 10.含空值排序

list=list.stream().sorted(Comparator.comparing(l -> l.getCreateTime(), Comparator.nullsFirst(Date::compareTo))).collect(Collectors.toList());

List<Map<String, Object>> collect = maps.stream() .sorted(Comparator.comparing((Map<String, Object> o) -> (Double) o.get("score"),
Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing((Map<String, Object> o) -> ((double) o.get("dealerDistance")),
Comparator.nullsLast(Comparator.naturalOrder())))
.collect(Collectors.toList());
1
2
3
4
5
6
7

# 11.nullsLast

以 nullsLast()为例,项目逻辑中 dealerDistance 为 null 时排最后

Comparator.nullsLast(Comparator.reverseOrder())把 null 排序最后面,然后是 Comparator.reverseOrder(),null 值不参与逆序,null 还是在最后 Comparator.nullsLast(Double ::compareTo).reversed() 先是把 null 排最后面,再整体 reversed(),包括为 null 的,所以 null 在最前面 注:reverseOrder()是逆转排序即逆序,而 reversed()是逆转仔细理解,这两个在意思上还是有区别

# 12.根据 map 的 key 排序

要根据resultsMap的键值对中的键(String类型)进行降序排列,可以使用Comparator接口来实现自定义比较器,并将其传递给TreeMap类的构造函数。以下是一种实现方法:

public class Main {
    public static void main(String[] args) {
        // 创建一个示例的 Map
        Map<String, List<StoreSalCalendarDTO>> resultsMap = new HashMap<>();
        // 添加一些键值对
        resultsMap.put("Key1", new ArrayList<>());
        resultsMap.put("Key3", new ArrayList<>());
        resultsMap.put("Key2", new ArrayList<>());
        // 使用自定义比较器对键进行降序排列
        Map<String, List<StoreSalCalendarDTO>> sortedMap = new TreeMap<>(new KeyComparator());
        sortedMap.putAll(resultsMap);
        // 打印排好序的 Map
        for (Map.Entry<String, List<StoreSalCalendarDTO>> entry : sortedMap.entrySet()) {
            System.out.println(entry.getKey());
        }
    }

    static class KeyComparator implements Comparator<String> {
        @Override
        public int compare(String key1, String key2) {
            // 降序排列
            return key2.compareTo(key1);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

在上述示例中,我们首先创建了一个示例的resultsMap,其中包含一些键值对。然后,我们定义了一个名为KeyComparator的内部类,实现了Comparator<String>接口,用于比较键的值。在compare方法中,我们通过使用key2.compareTo(key1)实现了降序排列。最后,我们创建了一个新的TreeMap实例,并传递了KeyComparator对象作为参数。通过putAll方法将原始的resultsMap中的键值对放入新的sortedMap中,以得到降序排列的结果。

在打印循环中,我们遍历排好序的sortedMap的键,并将它们输出到控制台。

# 13.set 排序

storeSkuSizeInvTotalSalDTO.setSizeCodeList(new TreeSet<>(sizeCodes));
1

# 14.比较器特性

特殊错误:比较方法违反其一般合同

在 JDK7 版本以上,Comparator 要满足自反性,传递性,对称性,不然 Arrays.sort,Collections.sort 会报 IllegalArgumentException 异常。

  • 自反性:当 两个相同的元素相比时,compare 必须返回 0,也就是 compare(o1, o1) = 0;
  • 反对称性:如果 compare(o1,o2) = 1,则 compare(o2, o1)必须返回符号相反的值也就是 -1;
  • 传递性:如果 a>b, b>c, 则 a 必然大于 c。也就是 compare(a,b)>0, compare(b,c)>0, 则 compare(a,c)>0
final Object object1 = Reflect.on(o1).field(sortName).get();
final Object object2 = Reflect.on(o2).field(sortName).get();
if (Objects.isNull(object1) && Objects.isNull(object2)) return 0;
if (Objects.isNull(object1)) return 1;
if (Objects.isNull(object2)) return -1;
1
2
3
4
5

# 四.分组

# 1.单字段分组

Map<String, List<TaskRecordDO>> collect1 = list.stream().collect(Collectors.groupingBy(TaskRecordDO::getOutNodeKey));
1
@Test
public void test13() {
    //所有价格等级的店铺列表
    Map<Integer, List<Property>> priceMap = properties.stream()
        .collect(Collectors.groupingBy(Property::getPriceLevel));
    System.out.println(JSON.toJSONString(priceMap));
}
1
2
3
4
5
6
7

# 2.多字段分组

//多字段
Map<String, List<DayStoreSkuSizeInvSalDTO>> financialYearWeekInfo = sizeIndex.stream().collect(Collectors.groupingBy(p -> p.getFinancialYear() + ":" + p.getFinancialWeek()));
1
2

# 3.每个店铺的价格等级

每个店铺的价格等级:

@Test
public void test12() {
    //获取每个店铺的价格等级
    Map<String, Integer> map = properties.stream()
        .collect(Collectors.toMap(Property::getName, Property::getPriceLevel));
    System.out.println(JSON.toJSONString(map));
}
1
2
3
4
5
6
7

# 4.多字段分组

分组:

Map<Integer, Map<Integer, List<StoreSalCalendarDTO>>> groupByYearMonth =               results.stream().collect(Collectors.groupingBy(StoreSalCalendarDTO::getFinancialYear,                       Collectors.groupingBy(StoreSalCalendarDTO::getFinancialYearMonth)));
1

遍历:

Map<Integer, Map<Integer, List<StoreSalCalendarDTO>>> groupByYearMonth = new HashMap<>();
        if (Objects.nonNull(groupByYearMonth)) {
            groupByYearMonth.forEach((year, yearValue) -> {
                if (Objects.nonNull(yearValue)) {
                    yearValue.forEach((month, monthValue) -> {
                    });
                }
            });
        }
1
2
3
4
5
6
7
8
9

# 五.互转

# 1.抽取对象属性

List<Integer> ids = taskRecordDOList.stream().map(TaskRecordDO::getId).collect(Collectors.toList());
1

# 2.obj2obj

List<DayStoreSkuSizeInvSalDTO> dtos = sizeInvSalList.stream()
                .map(item -> {
                    DayStoreSkuSizeInvSalDTO dayStoreSkuSizeInvSalDTO = new DayStoreSkuSizeInvSalDTO();
                    BeanUtil.copyProperties(item, dayStoreSkuSizeInvSalDTO);
                    return dayStoreSkuSizeInvSalDTO;
                }).collect(Collectors.toList());
1
2
3
4
5
6

# 3.属性转 set

转set:

final Set<String> sizeCodes = sizeInvSalList.stream().map(DayStoreSkuSizeInvSalDO::getSizeCode).collect(Collectors.toSet());
1

筛选转set:

final List<String> genderName = pageQuery.getGenderName();
        if (CollectionUtils.isNotEmpty(genderName)) {
            tags = tags.stream().filter(t -> genderName.contains(t.getGenderName()))
                    .collect(Collectors.toList());
        }
1
2
3
4
5

# 4.list2list

Map<Object, List<Student>> mapGroup = list.stream().collect(Collectors.groupingBy(v ->             v.getName() + v.getAge()));
List<List<Student>> categorys = new ArrayList<>(mapGroup.values());
1
2

# 5.toMap 重复 key

Map<Date, TimeAxisDTO> collect6 = timeAxisDTOListB.stream().collect(Collectors.
  toMap(TimeAxisDTO::getPeriodSdate, timeAxisDTO -> timeAxisDTO, (key1, key2) -> key1));
1
2

# 6.array2List

/**
 * 数组转list  Arrays.asList不能add
 *
 * @author : kwan
 * @version : 1.0.0
 * @date : 2022/8/10 00:21
 */
public class Basic_collection_10_Array2List_01 {

  public static void main(String[] args) {
    String[] strArray = new String[2];
    List list = Arrays.asList(strArray);
    //对转换后的list插入一条数据
    list.add("1");
    System.out.println(list);
  }
}
/**
 * 数组转list
 *
 * @author : kwan
 * @version : 1.0.0
 * @date : 2022/8/10 00:21
 */
public class Basic_collection_10_Array2List_02 {
    public static void main(String[] args) {
        String[] strArray = new String[2];
        ArrayList<String> list = new ArrayList<String>(Arrays.asList(strArray));
        list.add("1");
        System.out.println(list);
    }
}
/**
 * 数组转list
 *
 * @author : kwan
 * @version : 1.0.0
 * @date : 2022/8/10 00:21
 */
public class Basic_collection_10_Array2List_03 {

    public static void main(String[] args) {
        String[] strArray = new String[2];
        ArrayList< String> arrayList = new ArrayList<String>(strArray.length);
        Collections.addAll(arrayList, strArray);
        arrayList.add("1");
        System.out.println(arrayList);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 7.map2list

需要将 map 打平转为 list

  final List<StoreSkuInvSalDTO> sal = groupName_2_salDatas.values().stream()
                .flatMap(x -> x.getProducts().stream())
                .collect(Collectors.toList());
1
2
3

# 8.List&String&Set 互转

//list转string
String str= String.join("','", list);

//list转set
Set<String> set = new HashSet<>(skuList);

//set转list
List<String> list = new ArrayList<>(set);
1
2
3
4
5
6
7
8

# 9.arrays2str

默写关键点

  • mapToObj
  • collect
  • Collectors
int[] res = {1, 2, 3, 4, 5};
final String collect = Arrays.stream(res).mapToObj(String::valueOf).collect(Collectors.joining(""));
        System.out.println(collect);
1
2
3
//StringBuilder低效写法
int[] res = {1, 2, 3, 4, 5};
StringBuilder sb = new StringBuilder();
for (int i : res) {
    sb.append(i);
}
String result1 = sb.toString().trim();
System.out.println(result1);
1
2
3
4
5
6
7
8

# 六.计算

# 1.汇总数据

homeSkuTotal.setTotal7SalQty(tags.stream().mapToInt(item -> Objects.nonNull(item.getTotal7SalQty()) ? item.getTotal7SalQty() : 0).sum());
1
 if (CollectionUtils.isNotEmpty(homeSkuTotalOrr)) {
      homeSkuTotalOrr.stream().mapToInt(AdsDayOrrDO::getOrderNotArriveQty).sum();
}
1
2
3

# 2.分组求和

分组求最大值再求和

 if (CollectionUtils.isNotEmpty(homeSkuTotalOrr)) {
            final Collection<Optional<AdsDayOrrDO>> values = homeSkuTotalOrr.stream().collect(Collectors.groupingBy(AdsDayOrrDO::getProductKey, Collectors.maxBy(Comparator.comparing(AdsDayOrrDO::getPeriodSdate)))).values();
            homeSkuTotalDTO.setOrderNotArriveQty(values.stream().mapToInt(item -> item.get().getOrderNotArriveQty()).sum());
            homeSkuTotalDTO.setReplenishNotArriveQty(values.stream().mapToInt(item -> item.get().getReplenishNotArriveQty()).sum());
        }
1
2
3
4
5

# 3.内存分页

pageBean.setTotalElements(tags.size());
            pageBean.setTotalPages(tags.size() / pageQuery.getSize() + (tags.size() % pageQuery.getSize() == 0 ? 0 : 1));
            pageBean.setSize(pageQuery.getSize());
            pageBean.setNumber(pageQuery.getPage());
            pageBean.setContent(tags.stream().skip((pageQuery.getPage() - 1) * pageQuery.getSize()).limit(pageQuery.getSize()).collect(Collectors.toList()));
            pageBean.setNumberOfElements(CollectionUtils.isNotEmpty(pageBean.getContent()) ? pageBean.getContent().size() : 0L);
1
2
3
4
5
6

# 4.判断集合为空

CollectionUtils.isNotEmpty({a,b}): true
1
<dependency>
  <groupId>commons-collections</groupId>
  <artifactId>commons-collections</artifactId>
  <version>3.2.2</version>
</dependency>
1
2
3
4
5

# 5.并行处理

@Test
public void test15() {
    // 调用 parallelStream 方法即能并行处理
    List<String> names = properties.parallelStream()
        .filter(p -> p.priceLevel < 4)
        .sorted(Comparator.comparingInt(Property::getDistance))
        .map(Property::getName)
        .limit(2)
        .collect(Collectors.toList());
    System.out.println(JSON.toJSONString(names));
}

1
2
3
4
5
6
7
8
9
10
11
12

# 6.获取字符中数据

//博客浏览量未达成
final int x = message.indexOf("需要");
String str = message.substring(x + 2, x + 7);
for (int i = str.length() - 1; i >= 0; i--) {
    char lastChar = str.charAt(i);
    if (Character.isDigit(lastChar)) {
        // 字符不是数字,舍去最后一位字符
        str = str.substring(0, i + 1);
        break;
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 7.判断相同的元素

public class Java8_06_Stream_Same {
  public static void main(String[] args) {
    // 老师集合
    List<Teacher> teachers = Arrays.asList(
      new Teacher(1L, "张三"),
      new Teacher(2L, "李四"),
      new Teacher(3L, "王五"),
      new Teacher(4L, "赵六"));

    // 学生集合
    List<Student> students = Arrays.asList(
      new Student(5L, "张三"),
      new Student(6L, "李四"),
      new Student(7L, "小红"),
      new Student(8L, "小明"));

    // 求同时出现在老师集合和学生集合中的人数,name相同即视为同一个人
    int size = (int) teachers.stream()
      .map(t -> students.stream().filter(s -> Objects.nonNull(t.getName()) && Objects.nonNull(s.getName()) && Objects.equals(t.getName(), s.getName())).findAny().orElse(null))
      .filter(Objects::nonNull).count();

    // 求同时出现在老师集合和学生集合中人的name集合,name相同即视为同一个人
    List<String> names = teachers.stream()
      .map(t -> students.stream().filter(s -> Objects.nonNull(t.getName()) && Objects.nonNull(s.getName()) && Objects.equals(t.getName(), s.getName())).findAny().orElse(null))
      .filter(Objects::nonNull)
      .map(Student::getName)
      .collect(Collectors.toList());

    System.out.println("相同的人数:" + size);
    System.out.println("相同的人姓名集合:" + names);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 8.list 是否重复

public class Java8_13_stream_count {
  public static void main(String[] args) {
    List<Integer> list = new ArrayList() {
      {
        add(1);
        add(2);
        add(1);
      }
    };
    long count = list.stream().distinct().count();
    boolean isRepeat = count < list.size();
    System.out.println(count);//输出2
    System.out.println(isRepeat);//输出true
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 9.数据去重

//方式一
List<Long> distinctIdList = idList.stream().distinct().collect(Collectors.toList());
1
2
//方式二
final List<ProductAllexinfoV1DTO> invSqlSkus = tags.stream().filter(t -> t.getInvQty() > 0 || t.getSalQty() > 0).collect(Collectors.toList());
        homeSkuTotal.setProductTotal(CollectionUtils.isEmpty(invSqlSkus) ? 0 :
                invSqlSkus.stream().map(ProductAllexinfoV1DTO::getProductKey).collect(Collectors.toSet()).size());
1
2
3
4

# 七.reducing

# 1.什么是 reducing?

在 Java 8 中,Collectors.reducingCollectors类提供的一个强大的工具,用于进行归约操作。它用于将流中的元素按照某种规则进行累积,最终生成一个汇总结果。

Collectors.reducing(identity, op)
1
  • identity:归约操作的初始值,也是流中没有元素时的默认值。
  • op:一个二元操作符,用于将两个元素结合起来,执行归约操作。

# 2.使用示例?

下面是一个具体的例子,假设有一个包含整数的列表,我们希望对这些整数求和:

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

// 使用Collectors.reducing进行求和
Optional<Integer> sum = numbers.stream()
    .collect(Collectors.reducing((x, y) -> x + y));

// 打印结果
System.out.println("Sum: " + sum.orElse(0));
1
2
3
4
5
6
7
8

这个例子中,Collectors.reducing 接受一个 Lambda 表达式 (x, y) -> x + y 作为参数,表示对两个元素执行求和操作。sum 是一个Optional<Integer>,它包含了最终的求和结果。如果流为空,orElse(0) 将返回默认值 0。

# 3.使用优化

这个例子也可以通过方法引用来简化:

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

// 使用方法引用进行求和
int sum = numbers.stream()
    .collect(Collectors.reducing(0, Integer::sum));

// 打印结果
System.out.println("Sum: " + sum);
1
2
3
4
5
6
7
8

在这里,Integer::sum 是一个方法引用,表示执行整数求和操作。

# 4.复杂规约

Collectors.reducing 还可以用于更复杂的归约操作,例如查找最大值或最小值。下面是一个查找最大值的例子:

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

// 使用Collectors.reducing查找最大值
Optional<Integer> max = numbers.stream()
    .collect(Collectors.reducing(Integer::max));

// 打印结果
System.out.println("Max: " + max.orElse(0));
1
2
3
4
5
6
7
8

在这个例子中,Integer::max 是一个方法引用,表示执行整数的最大值操作。

# 5.实战应用?

有一个集合 storeReports,希望求不同分组策略下汇总值

  1. 先根据不同的策略进行分组
  2. 在 groupingBy 的内部进行 reducing 操作
  3. new DTO()是初始值
  4. 后面的函数是规约的具体逻辑

reducing实战:

Map<String, DTO> resultMap  = storeReports.stream()
                    .collect(Collectors.groupingBy(storeReportDTO -> isTotal ? storeReportDTO.groupKeyTotal() : storeReportDTO.groupKey(),
                            Collectors.reducing(new DTO(),
                                    (s1, s2) -> new DTO(
                                            s2.getName1(),
                                            s2.getKey(),
                                            s2.getYearName(),
                                            s2.getSeasonName(),
                                            Optional.ofNullable(s1.getSalQty()).orElse(0L) + Optional.ofNullable(s2.getSalQty()).orElse(0L),
                                            BigDecimal.ZERO,
                                            BigDecimal.ZERO,
                                            BigDecimal.ZERO,
                                            s2.getWeekOrMonth(),
                                            s2.getYear()
                                    )
                            )
                    ));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

分组

public String groupKey() {
    return year + ":_:" + weekOrMonth + ":_:" + key + ":_:" + yearName + ":_:" + seasonName;
}
public String groupKeyTotal() {
    return year + ":_:" + weekOrMonth + ":_:" + key;
}
1
2
3
4
5
6
上次更新: 10/29/2024, 10:27:50 AM