# 一.JDK8 的增强
# 1.Lambda 表达式
- Lambda 表达式是一个匿名方法,将行为像数据一样进行传递。
- Lambda 表达式的常见结构:
BinaryOperator<Integer>add=(×,y)→×+y
。 - 函数接口指仅具有单个抽象方法的接口,用来表示 Lambda 表达式的类型。
# 2.jdk8 增强与新特性
Java 8 引入了许多新的语言特性和 API 改进,以下是其中一些主要的特性:
- Lambda 表达式: Lambda 表达式是一种更简洁的语法,用于表示一个匿名函数。它使得在集合操作、事件处理等场景下代码更具可读性和简洁性。
- 函数式接口: Java 8 引入了函数式接口的概念,这是只包含一个抽象方法的接口。Lambda 表达式可以与函数式接口一起使用。
- 方法引用: 方法引用允许你直接引用现有的方法或构造函数,从而使代码更加简洁。
- 默认方法和静态方法: 接口现在可以包含默认方法和静态方法的实现。这使得在接口中添加新的方法时,不会破坏已有的实现。
- Stream API: Stream API 提供了一种更便捷的方式来处理集合数据。它支持函数式编程风格,可以用于过滤、映射、归约等操作。
- 新的日期和时间 API: Java 8 引入了
java.time
包,提供了全新的日期和时间 API,解决了旧的Date
和Calendar
类存在的问题。 - Optional 类:
Optional
是一个容器类,用于表示一个值可能存在,也可能不存在的情况,从而减少空指针异常的发生。 - Nashorn 引擎: Nashorn 是一个新的轻量级、高性能的 JavaScript 引擎,用于在 Java 程序中执行 JavaScript 代码。
- 新的重复注解和类型注解: 如前所述,Java 8 引入了对多重注解的支持,以及更丰富的类型注解。
- PermGen 空间被移除: Java 8 中,永久代(PermGen)被元空间(Metaspace)所取代,用于存放类的元数据。
# 3.Stream 的组成与特点
Stream
(流)是一个来自数据源的元素队列并支持聚合操作:
- 元素是特定类型的对象,形成一个队列。
Java
中的Stream
并不会向集合那样存储和管理元素,而是按需计算 - 数据源流的来源可以是集合
Collection
、数组Array
、I/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);
}
}
2
3
4
5
6
7
8
9
10
11
12
javap -c -p Java8_01_Source_Main 查看class文件
> 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
}
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);
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);
}
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());
}
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());
2
3
# 二.筛选
# 1.filter 过滤
//筛选符合条件的数据
List<DdlNode> collect = dagConf.getNodes().stream().filter(t -> NodeTypeEnum.OUT.name().equalsIgnoreCase(t.getType()))
.collect(Collectors.toList());
2
3
//或者条件
storeDay += dayStoreSkuSizeInvSalDTOList.stream().filter(p1 -> p1.getFlag() == 1 || p1.getFlag() == 3).count();
2
//并且条件
storeDay += dayStoreSkuSizeInvSalDTOList.stream().filter(p1 -> p1.getFlag() == 1 && p1.getFlag() == 3).count();
2
# 2.筛选是否存在
final boolean exist = value.stream()
.filter(x -> x.getFlag().equals(FlagEnum.RED.getCode())).collect(Collectors.toList()).size() > 0;
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();
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();
}
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());
}
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());
}
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());
}
}
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());
}
}
}
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());
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);
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())
2
3
4
5
6
7
8
9
10
# 2.双排序
timeAxisList.sort(Comparator.comparing(TimeAxisDTO::getFinancialYear).thenComparing(TimeAxisDTO::getFinancialWeek));
多字段排序:
list.sort(Comparator.comparing(UserInformation::getId).thenComparing(UserInformation::getAge));
多字段排序,指定正序还是倒序:
/**
* 按照推荐、置顶、发布时间来排序
* @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);
}
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());
2
3
4
# 4.反转排序
salListsTopN.sort(Comparator.comparing(SalList::getSalQty).reversed());
# 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());
2
3
4
# 6.list 嵌套排序
List<List<String>>排序
/**
* 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));
}
}
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());
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));
}
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));
}
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());
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());
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);
}
}
}
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));
# 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;
2
3
4
5
# 四.分组
# 1.单字段分组
Map<String, List<TaskRecordDO>> collect1 = list.stream().collect(Collectors.groupingBy(TaskRecordDO::getOutNodeKey));
@Test
public void test13() {
//所有价格等级的店铺列表
Map<Integer, List<Property>> priceMap = properties.stream()
.collect(Collectors.groupingBy(Property::getPriceLevel));
System.out.println(JSON.toJSONString(priceMap));
}
2
3
4
5
6
7
# 2.多字段分组
//多字段
Map<String, List<DayStoreSkuSizeInvSalDTO>> financialYearWeekInfo = sizeIndex.stream().collect(Collectors.groupingBy(p -> p.getFinancialYear() + ":" + p.getFinancialWeek()));
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));
}
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)));
遍历:
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) -> {
});
}
});
}
2
3
4
5
6
7
8
9
# 五.互转
# 1.抽取对象属性
List<Integer> ids = taskRecordDOList.stream().map(TaskRecordDO::getId).collect(Collectors.toList());
# 2.obj2obj
List<DayStoreSkuSizeInvSalDTO> dtos = sizeInvSalList.stream()
.map(item -> {
DayStoreSkuSizeInvSalDTO dayStoreSkuSizeInvSalDTO = new DayStoreSkuSizeInvSalDTO();
BeanUtil.copyProperties(item, dayStoreSkuSizeInvSalDTO);
return dayStoreSkuSizeInvSalDTO;
}).collect(Collectors.toList());
2
3
4
5
6
# 3.属性转 set
转set:
final Set<String> sizeCodes = sizeInvSalList.stream().map(DayStoreSkuSizeInvSalDO::getSizeCode).collect(Collectors.toSet());
筛选转set:
final List<String> genderName = pageQuery.getGenderName();
if (CollectionUtils.isNotEmpty(genderName)) {
tags = tags.stream().filter(t -> genderName.contains(t.getGenderName()))
.collect(Collectors.toList());
}
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());
2
# 5.toMap 重复 key
Map<Date, TimeAxisDTO> collect6 = timeAxisDTOListB.stream().collect(Collectors.
toMap(TimeAxisDTO::getPeriodSdate, timeAxisDTO -> timeAxisDTO, (key1, key2) -> key1));
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);
}
}
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());
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);
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);
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);
2
3
4
5
6
7
8
# 六.计算
# 1.汇总数据
homeSkuTotal.setTotal7SalQty(tags.stream().mapToInt(item -> Objects.nonNull(item.getTotal7SalQty()) ? item.getTotal7SalQty() : 0).sum());
if (CollectionUtils.isNotEmpty(homeSkuTotalOrr)) {
homeSkuTotalOrr.stream().mapToInt(AdsDayOrrDO::getOrderNotArriveQty).sum();
}
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());
}
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);
2
3
4
5
6
# 4.判断集合为空
CollectionUtils.isNotEmpty({a,b}): true
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
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));
}
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;
}
}
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);
}
}
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
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 9.数据去重
//方式一
List<Long> distinctIdList = idList.stream().distinct().collect(Collectors.toList());
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());
2
3
4
# 七.reducing
# 1.什么是 reducing?
在 Java 8 中,Collectors.reducing
是Collectors
类提供的一个强大的工具,用于进行归约操作。它用于将流中的元素按照某种规则进行累积,最终生成一个汇总结果。
Collectors.reducing(identity, op)
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));
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);
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));
2
3
4
5
6
7
8
在这个例子中,Integer::max
是一个方法引用,表示执行整数的最大值操作。
# 5.实战应用?
有一个集合 storeReports,希望求不同分组策略下汇总值
- 先根据不同的策略进行分组
- 在 groupingBy 的内部进行 reducing 操作
- new DTO()是初始值
- 后面的函数是规约的具体逻辑
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()
)
)
));
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;
}
2
3
4
5
6
02-GIT学习 →