前言
Lambda表达式是 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数,也即是可以将函数作为参数传递到方法中。使用 Lambda 表达式可以使我们的代码变的更加简洁紧凑也更便于我们理解。
该文章仅仅只是记录一下本人在工作中用到的一些示例,不会介绍Lambda的一些底层原理, 如函数式接口、方法引用等。如果大家需要了解这些知识,还请各位自行查阅相关资料。 最近看到了一篇介绍Stream流的文章,很不错,推荐给大家:吃透JAVA的Stream流操作,多年实践总结
准备工作
为了便于后续示例的编写,需要首先定义一个实体类:
package com.learn.lambda;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class LambdaDemo {
private String item;
private Integer statNum;
private String itemValue;
/**
* 扩展字段 写入任意信息
*/
private Object extendInfo;
public LambdaDemo(String item, Integer statNum) {
this.item = item;
this.statNum = statNum;
}
}
初始化样例数据:
private static List<LambdaDemo> demoList = new ArrayList<>();
static {
LambdaDemo demo1 = new LambdaDemo("001",100);
LambdaDemo demo2 = new LambdaDemo("002",200);
LambdaDemo demo3 = new LambdaDemo("003",300);
LambdaDemo demo4 = new LambdaDemo("004",400);
LambdaDemo demo5 = new LambdaDemo("005",500);
LambdaDemo demo6 = new LambdaDemo("006",600);
LambdaDemo demo7 = new LambdaDemo("007",700);
LambdaDemo demo8 = new LambdaDemo("008",800);
LambdaDemo demo9 = new LambdaDemo("009",900);
LambdaDemo demo10 = new LambdaDemo("010",1000);
demoList.add(demo1);
demoList.add(demo2);
demoList.add(demo3);
demoList.add(demo4);
demoList.add(demo5);
demoList.add(demo6);
demoList.add(demo7);
demoList.add(demo8);
demoList.add(demo9);
demoList.add(demo10);
}
到此准备工作基本已经完成。
示例
List集合转为Map集合
转换成map是如果没有重复key的情况是可以使用下边的方式
/**
* list转为Map
*/
public static void listToMap(){
Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, LambdaDemo::getStatNum));
collect.forEach((key,value)-> System.out.println(key+":"+value));
//如果value 为空的话 可以进行下判断
Map<String, Integer> map = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, p -> p.getStatNum() == null ? 0 : p.getStatNum()));
System.out.println(map);
}
如果转换成map后有重复key值的话将会出现报错,将 样例数据 设置为有key值重复的情况。
LambdaDemo demo1 = new LambdaDemo("001",100);
LambdaDemo demo2 = new LambdaDemo("001",200);
再次执行上边的代码将会出现如下错误:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 100
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
解决该问题其实也很简单,如下是将重复key的value值相加,如果是String类型的话可以使用逗号隔开进行拼接。具体根据自己的实际业务需求进行相应的处理。
/**
* list转为Map 解决重复key值的问题
* 将值相加
*/
public static void listToMapSolveDuplicateKey(){
Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, LambdaDemo::getStatNum,(oleValue,newValue)->oleValue+newValue));
collect.forEach((key,value)-> System.out.println(key+":"+value));
}
运行输出结果为:
001:300 //001的值为300,说明已经将重复key值的value相加
003:300
004:400
005:500
006:600
007:700
008:800
009:900
010:1000
还可以进行覆盖操作:
/**
* list转为Map 解决重复key值的问题
* 将值覆盖
*/
public static void listToMapSolveDuplicateKey2(){
Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, LambdaDemo::getStatNum,(oleValue,newValue)->newValue));
collect.forEach((key,value)-> System.out.println(key+":"+value));
}
关键点就在于使用哪一个值,oleValue为第一个key对应的值,newValue为第二个相同key对应的值。
(oleValue,newValue)->newValue)
(oleValue,newValue)->oleValue)
List集合获取Map<String,List< LambdaDemo >>
使用groupingBy 进行分组
Map<String, List< LambdaDemo >> collect = demoList.stream().collect(Collectors.groupingBy(LambdaDemo::getItem));
此时map的value值存放的是对象的集合,如果想取出对象中的某一个属性作为集合返回,可以使用如下形式:
Map<String, List<String>> collect = demoList.stream()
.collect(Collectors.groupingBy(LambdaDemo::getItem,Collectors.mapping(LambdaDemo::itemValue,Collectors.toList())));
将实体类作为value值
Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, lambdaDemo->lambdaDemo));
或者如下形式
Map<String, Integer> collect = demoList.stream().collect(Collectors.toMap(LambdaDemo::getItem, Function.identity()));
计算对象中的某值之和
/**
* list 计算对象中的某值之和
*/
public static void listSum(){
int sum = demoList.stream().mapToInt(LambdaDemo::getStatNum).sum();
System.out.println(sum);
}
除了mapToInt方法外,还有mapToDouble、mapToLong等方法。可以按需使用。
list转换为字符串
逗号也可以根据需求换成其他相关的符号
/**
* 将list转换为使用逗号隔开的字符串
*/
public static void listToString(){
String value = demoList.stream().map(lambdaDemo -> String.valueOf(lambdaDemo.getItem())).collect(Collectors.joining(","));
System.out.println(value);
}
list转换为list
样例数据中的list中存放的是对象,我们可以将对对象中的item抽取出来转换成一个新的list
/**
* list转换为list
*/
public static void listToList(){
List<String> stringList = demoList.stream().map(LambdaDemo::getItem).collect(Collectors.toList());
stringList.forEach(System.out::println);
}
删除数据
使用Lambda删除数据也是非常方便的:
/**
* 删除数据
*/
public static void removeData(){
demoList.removeIf(lambdaDemo->lambdaDemo.getItem().equals("001"));
demoList.forEach(lambdaDemo -> System.out.println(lambdaDemo.getItem()));
}
排序
将样例数据中的statNum的数据打乱,可以使用如下方式进行排序:
/**
* 排序
*/
public static void sortData() {
//正序
demoList.sort(Comparator.comparing(LambdaDemo::getStatNum));
demoList.forEach(lambdaDemo -> System.out.println(lambdaDemo.getStatNum()));
System.out.println("----------");
//倒序
demoList.sort(Comparator.comparing(LambdaDemo::getStatNum).reversed());
demoList.forEach(lambdaDemo -> System.out.println(lambdaDemo.getStatNum()));
}
多字段排序
// 方式一 集合方式
Collections.sort(userList, Comparator.comparing(UserVO::getName)
.thenComparingInt(UserVO::getAge));
// 方式二 Stream方式
List<UserVO> collect = userList.stream()
.sorted(Comparator.comparing(UserVO::getName).thenComparingInt(UserVO::getAge))
.collect(Collectors.toList());
多字段Null 值排序
// 方式一 集合方式
Collections.sort(userList, Comparator.nullsFirst(Comparator.comparing(UserVO::getAge)).reversed());
// 方式二 Stream方式 nullsFirst() 有空的元素放在最前面,nullsLast(String::compareTo) 有空的字段放在最后面
List<UserVO> collect = userList.stream().sorted(Comparator.nullsFirst(Comparator.comparing(UserVO::getAge,Comparator.nullsLast(String::compareTo)))).collect(Collectors.toList());
JSONArray排序
JSONArray array = mtd.getJSONArray("XXXX");
array.sort(Comparator.comparing(obj -> ((JSONObject) obj).getString("XX")));
过滤
过滤也是比较常用的,比如我们过滤出statNum等于500的记录
/**
* 过滤
*/
public static void filter(){
Stream<LambdaDemo> lambdaDemoStream = demoList.stream().filter(lambdaDemo -> lambdaDemo.getStatNum() == 500);
lambdaDemoStream.forEach(lambdaDemo -> {
System.out.println(lambdaDemo.getStatNum());
});
}
去重
去重方式有很多,以下仅供参考!
List<LambdaDemo> distinctList = demoList.stream().collect(
Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(LambdaDemo::getItem))),
ArrayList::new));
distinctList.forEach(System.out::println);
以上只是本人在当前工作中使用到的部分示例,意在做下简单记录以备忘记时及时查询。我会不定时更新,欢迎大家评论区补充!
逗号拼接字符串
public static <T> String parseListToStr3(List<T> list){
String result = list.stream().map(String::valueOf).collect(Collectors.joining(","));
return result;
}
自定义分页
List<String> receivers = new ArrayList<>();
for (int i = 1; i <= 100; i++) {
receivers.add(String.valueOf(i));
}
int pageSize = 20;
int totalPage = receivers.size() % pageSize == 0 ? receivers.size() / pageSize : receivers.size() / pageSize + 1;
for (int pageNo = 1; pageNo <= totalPage; pageNo++) {
List<String> subUserList = receivers.stream().skip((long) (pageNo - 1) * pageSize).limit(pageSize).
collect(Collectors.toList());
System.out.println(subUserList);
}