多字段分组
Map<String,Map<String, List<CampaignSendMessageListForFile>>> map = uploadSuccessList.stream().collect(Collectors.groupingBy( CampaignSendMessageListForFile::getChannel,Collectors.groupingBy(CampaignSendMessageListForFile::getContent) ));
.skip()和.limit()
List的强转
List<Date> dateList = (List<Date>)(List)strings;
List<Date> dates = strings.stream()
.map(x->(Date)x)
.collect(Collectors.toList());
//Arrays.asList()方法返回的List不能add对象
//receiverList.toArray(new String[receiverList.size()])
.filter 过滤
List<String> tableFieldList = priorityModelList.stream()
.filter(s -> s.getRuleTableName().toLowerCase().equals("person"))
.map(a -> a.getRuleTableField()).collect(Collectors.toList());
.distinct()去重
1.简单包装类型去重:
List<ImportMemberExcel> tid_Msid_LidList = excelUtilMember.userModelMapper.getToupointidMembershipidLoyaltyprogramidByLoginUserName(loginUserName);
List<Long> tidList = tid_Msid_LidList.stream().map(e -> e.getTouchPointID()).distinct().collect(Collectors.toList());
List<Long> msidList = tid_Msid_LidList.stream().map(e -> e.getMembershipID()).distinct().collect(Collectors.toList());
List<Long> lidList = tid_Msid_LidList.stream().map(e -> e.getLoyaltyProgramID()).distinct().collect(Collectors.toList());
2.根据对象内某字段去重--Map.putIfAbsent():
List列表运用Java8的stream流按某字段去重 - cdfive - 博客园
通过stream的
filter
方法来去重,不定义去重方法,在外面创建HashMap
代码:
Map<Object, Boolean> map = new HashMap<>(); List<Book> distinctNameBooks4 = books.stream().filter(e -> map.putIfAbsent(e.getName(), Boolean.TRUE) == null).collect(Collectors.toList()); System.out.println(distinctNameBooks4);
总结:
仍然是配合filter
方法实现去重,没有单独创建方法,临时定义一个HashMap
,保持了原列表的顺序,不足之处是有一定内存占用。
putIfAbsent() 方法会先判断指定的键(key)是否存在,不存在则将键/值对插入到 HashMap 中。 putIfAbsent() 方法的语法为:hashmap.putIfAbsent(K key, V value)
如果所指定的 key 已经在 HashMap 中存在,返回和这个 key 值对应的 value, 如果所指定的 key 不在 HashMap 中存在则将键/值对插入到 HashMap 中,并返回 null。
注意:如果指定 key已经和一个 null的值相关联存在于map中 ,则该方法也返回 null。
3. Map.computeIfAbsent()用法
该方法为java8 新增。
//Map接口中此方法源码:
public interface Map<K,V> {
//......
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
//第二个参数为null会抛出空指针异常
Objects.requireNonNull(mappingFunction);
V v;
//map中不存在这个key,或者存在这个key它的值为null
if ((v = get(key)) == null) {
V newValue;
//把1参key传入2参映射函数处理,返回值newValue的类型为map的value的类型V
//映射函数执行结果newValue!=null时,才把key-newValue放入map且return newValue,【此时map.computeIfAbsent(key,mappingFunction)相当于把key传入mappingFunction中执行相关逻辑返回newValue(给key准备的非null值),put(key, newValue);return newValue;两/三步】。
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
//map中存在这个key且其值不为null,v = get(key)返回原value(不会把第一个参数交给第二个参数),【此时map.computeIfAbsent(key,mappingFunction)相当于map.get(key)】。
//map中不存在这个key,或者存在这个key它的值为null ==> 把1参key交给2参映射函数处理,映射函数执行结果newValue==null ==> v = get(key)即return null,【此时map.computeIfAbsent(key,mappingFunction)也相当于map.get(key)】。
return v;
}
//......
}
//不管if判断是否为真,其对值的改变都是真实不虚的(不会回退!)
String a = "hello";
if((a = a.substring(0,2)) == null){
}
System.out.println(a);//he
对上面源码中自添加注释的总结:
map中存在这个key且其值不为null,v = get(key)返回原value(不为null)(不会把第一个参数交给第二个参数),【此时map.computeIfAbsent(key,mappingFunction)相当于map.get(key)】。
map中不存在这个key,或者存在这个key它的值为null ==> 把1参key传入2参映射函数处理,映射函数执行结果newValue==null ==> v = get(key)即return null(相当于return newValue),【此时map.computeIfAbsent(key,mappingFunction)也相当于map.get(key)】。map中不存在这个key,或者存在这个key它的值为null ==> 把1参key传入2参映射函数处理,映射函数执行结果newValue!=null,把key-newValue放入map且return newValue。
只要映射函数符合执行条件且执行完毕,computeIfAbsent方法返回值就是第二个参数--映射函数的执行结果,
1.此时computeIfAbsent方法返回值为null/映射函数的执行结果为null则说明computeIfAbsent方法未对map进行任何修改,
2.此时computeIfAbsent方法返回值不为null/映射函数的执行结果不为null则说明computeIfAbsent方法对map进行过put操作。
映射函数不符合执行条件,则computeIfAbsent方法返回值是map中此键的值且值不为null,且computeIfAbsent方法未对map进行任何修改。 如果映射函数符合执行条件但执行过程中抛出异常,将不添加任何键值对到map,也不会return任何值。
只知道computeIfAbsent方法返回值不为null,并不能直接推出computeIfAbsent方法返回值来自原值还是映射函数计算出来的新值。
有下面一则程序片段:
//映射函数是key -> new ArrayList<>()时,demoValue永不为null,不会出现空指针
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
//只知道computeIfAbsent方法返回值不为null,并不能直接推出computeIfAbsent方法返回值来自原值还是映射函数计算出来的新值(原值可能也是无元素的非null集合)。//不管demoValue来自原值【通过源码中get(key)得到--此时demoValue中或许已经有值
】,还是映射函数计算出来的新值【通过源码中put(key, newValue);return newValue;得到--此时demoValue中无元素,因为映射函数是key -> new ArrayList<>()】,但只要demoValue是对象类型,下面两行add操作都会修改map中"demoKey"键的值,因为demoValue和map中"demoKey"键的值是有同一内存地址的同一对象,请看下面示例3
demoValue .add(true);
demoValue .add(false);
示例1:
Map<String, List<Boolean>> map = new HashMap<>();
//接收的类型必须是map的值类型即List<Boolean>
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> {
/*map中不存在这个key或者存在这个key它的值为null,才会进入此方法!!
不进入此方法computeIfAbsent将直接返回原key的键值给demoValue*/
List<Boolean> newValueList = new ArrayList<>();
//方法体内可以拿到key
System.out.println(key);//"demoKey"
System.out.println("原key值:" + map.get(key));//必然打印:原key值:null
newValueList.add(false);
newValueList.add(true);
newValueList.add(true);
newValueList.add(false);
System.out.println("新key值:" + newValueList);
//return的类型必须是map的值类型即List<Boolean>,return的newValueList!=null时会在源码中间接被demoValue接收
//newValueList!=null时的map.put(key,newValueList)操作也是在底层源码执行的!
return newValueList;
//return的newValueList==null时,底层源码将不执行map.put(key,newValueList)操作,且return null给demoValue,所以可以理解为demoValue接收的是newValueList(因为newValueList也是null)
});
上面写法和下面写法逻辑一致!推荐下面写法
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
//映射函数是key -> new ArrayList<>(),则demoValue永不为null。
//映射函数符合执行条件的话,demoValue接收的是new ArrayList<>(),map放的是("demoKey",demoValue),则下面几行修改了map中此键的值
//映射函数不符合执行条件即在computeIfAbsent执行前map的key中已经有"demoKey"且键值不为null,不进行put操作仅返回map中此键的值,则下面几行也会修改到map中此键的值!
demoValue.add(false);
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
第二种写法要注意避免空指针(第一种写法也要避免空指针):
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> null);
demoValue.add(false);//此处会抛出空指针异常,demoValue接收的是null
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
下面这样写则是在computeIfAbsent方法内部抛出的空指针异常:
List<Boolean> demoValue = map.computeIfAbsent("demoKey", null);
示例2:
【"demoKey"键不存在】
public static void main(String[] args) {
Map<String,List<Boolean>> map = new HashMap();
/*List list = new ArrayList();
list.add(true);
map.put("demoKey", list);*/
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
System.out.println(demoValue.size());
demoValue.add(false);
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
System.out.println(map.toString());
}
//打印结果:
//0
//{demoKey=[false, true, false, true]}
//总结:走映射函数
【"demoKey"键存在但值为null】
public static void main(String[] args) {
Map<String,List<Boolean>> map = new HashMap();
map.put("demoKey", null);
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
System.out.println(demoValue.size());
demoValue.add(false);
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
System.out.println(map.toString());
}
//打印结果:
//0
//{demoKey=[false, true, false, true]}
//总结:走映射函数
【"demoKey"键存在且值不为null且有元素】
public static void main(String[] args) {
Map<String,List<Boolean>> map = new HashMap();
List list = new ArrayList();
list.add(true);
map.put("demoKey", list);
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
System.out.println(demoValue.size());
demoValue.add(false);
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
System.out.println(map.toString());
}
//打印结果:
//1
//{demoKey=[true, false, true, false, true]}
//总结:打印1说明computeIfAbsent返回原键值且不走映射函数,打印{demoKey=[true, false, true, false, true]}说明后面的add操作是对原键值list的add操作
【"demoKey"键存在且值不为null但无元素】
public static void main(String[] args) {
Map<String,List<Boolean>> map = new HashMap();
List list = new ArrayList();
map.put("demoKey", list);//list无元素
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
System.out.println(list==demoValue);
System.out.println(demoValue.size());
demoValue.add(false);
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
System.out.println(map.toString());
}
//打印结果:
//true
//0
//{demoKey=[false, true, false, true]}
//总结:为true,说明demoValue来自原键值不走映射函数,且demoValue和原键值是同一对象,后面的add是对原键值的操作
示例3:
源码中get(key)得到一个对象/键值赋给一个引用--变量名【List<Boolean> demoValue = get(key);】;
或者
put(key, newValue);return newValue;返回一个对象/键值赋给一个引用--变量名 【List<Boolean> demoValue = return newValue;】;
所以,对此变量demoValue进行的操作就是对key键的值进行的操作。
public static void main(String[] args) {
Map<String,List<Boolean>> map = new HashMap();
List<Boolean> demoValue1 = new ArrayList<>();
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
demoValue1.addAll(demoValue);
System.out.println("是否同一对象:"+ (demoValue == map.get("demoKey")));
System.out.println("是否同一对象1:"+ (demoValue1 == map.get("demoKey")));
System.out.println(demoValue.size());
demoValue.add(false);
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
System.out.println(map.toString());
}
//打印结果:
//是否同一对象:true
//是否同一对象1:false
//0
//{demoKey=[false, true, false, true]}
public static void main(String[] args) {
Map<String,List<Boolean>> map = new HashMap();
List list = new ArrayList();
list.add(true);
map.put("demoKey", list);
List<Boolean> demoValue1 = new ArrayList<>();
List<Boolean> demoValue = map.computeIfAbsent("demoKey", key -> new ArrayList<>());
demoValue1.addAll(demoValue);
System.out.println("是否同一对象:"+ ((demoValue == map.get("demoKey")) && (list == map.get("demoKey"))));
System.out.println("是否同一对象1:"+ (demoValue1 == map.get("demoKey")));
System.out.println(demoValue.size());
demoValue.add(false);
demoValue.add(true);
demoValue.add(false);
demoValue.add(true);
System.out.println(map.toString());
}
//打印结果:
//是否同一对象:true
//是否同一对象1:false
//1
//{demoKey=[true, false, true, false, true]}
.sorted()排序
Comparator.comparing(TSysRoleAndMenuDTO::getOrderIndex).reversed()是降序
菜单表查询结果的封装
//过滤 排序 设置
List<TSysRoleAndMenuDTO> collect = Lists.newArrayList();
if (!CollectionUtils.isEmpty(list)) {
// 过滤得一级菜单,
collect = list.stream().filter(e -> e.getLevels().equals(1))
.sorted(Comparator.comparing(TSysRoleAndMenuDTO::getOrderIndex)).collect(Collectors.toList());
// 遍历一级菜单,
for (TSysRoleAndMenuDTO tSysRoleAndMenuDTO : collect) {
if (!CollectionUtils.isEmpty(collect)) {
// 过滤得二级菜单--查询父级id和一级菜单id相等的集合,
List<TSysRoleAndMenuDTO> collect2 = list.stream().filter(e -> e.getParentId().equals(tSysRoleAndMenuDTO.getId()))
.sorted(Comparator.comparing(TSysRoleAndMenuDTO::getOrderIndex)).collect(Collectors.toList());
/*// 把二级菜单set到一级菜单实体中。
* 放上面也可以--【list如果后面变化,前面set进对象属性中的该list也会随之改变!】*/
tSysRoleAndMenuDTO.setMenuDTOList(collect2);
if (!CollectionUtils.isEmpty(collect2)) {
// 遍历二级菜单,
for (TSysRoleAndMenuDTO sysRoleAndMenuDTO2 : collect2) {
// 过滤得三级菜单,
List<TSysRoleAndMenuDTO> collect3 = list.stream().filter(e -> e.getParentId().equals(sysRoleAndMenuDTO2.getId()))
.sorted(Comparator.comparing(TSysRoleAndMenuDTO::getOrderIndex)).collect(Collectors.toList());
// 把三级菜单set到二级菜单实体中。
sysRoleAndMenuDTO2.setMenuDTOList(collect3);/*此时collect2也会随之更新*/
}
}
}
}
}
求和
double sum1pay_amount = tmpList.stream().mapToDouble(e -> e.getPay_amount() == null ? 0 : e.getPay_amount()).sum();//【注意相加的元素不能是null,否则空指针!】
自定义lambda表达式
1.定义一个接口,其中有且只能有一个方法
package com.kaytune.sizzled;
public interface Eatable {//提供一个接口,对于lamabda式其中有且只能有一个方法
String eat(String s, String b);
}
2.定义一个类,其中某一个公共的静态方法的参数是定义好的接口,相当于设计了一个lamabda表达式
package com.kaytune.sizzled;
public class LamabdaDemo {
public static String useEatable(Eatable e){
//【准备通用的接口方法入参】,使用lamabda表达式时只需输入形参即可
String bbb = "别BB";
String jbb = "就BB";
String res = e.eat(bbb, jbb);//【方法体由使用lamabda式的地方定义】
//【通用后置代码】
String bbb1 = "别AA";
String jbb1 = "就AA";
String h1 = bbb1 + jbb1;
return res + h1;
}
}
3.在某一个类中使用lamabda表达式
package com.kaytune.sizzled;
/**
* @beLongProjecet: theExampleProject
* @beLongPackage: com.kaytune.sizzled
* @author: sizzled
* @createTime: 2022/08/24 11:48
* @description: 使用定义好的lamabda表达式
* @version: v1.0
*/
public class UserLamabda {
public static void main(String[] args) {
//lamada表达式
String result = LamabdaDemo.useEatable(/*注意形参不是Eatable e*/ /*String*/ s, /*String*/ b) -> {//使用lamabda表达式只需输入形参(实际上是准备好的实参)
String jkjkjk = s + b;/*【这里放利用形参(实际上是准备好的实参),做的一些事情】*/
return jkjkjk;
//这里并不是return给result,而是LamabdaDemo.useEatable(Eatable e){}中String res = e.eat(bbb, jbb);的res
//result接收的是LamabdaDemo.useEatable(Eatable e){}的返回值
});
System.out.println(result);
//结果:别BB就BB别AA就AA
}
}
总计一下自定义lambda表达式的使用场景:共同的入参,不同的中间处理逻辑,共同的后处理逻辑。
Collectors.toMap
1.想获得一个id和name对应的Map<String, String> :
Map<String, String> map = list.stream().collect(Collectors.toMap(Student::getId,Student::getName));
2.注意:name可以为空字符串但不能为null,否则会报空指针,解决方案:
Map<String, String> map = list.stream().collect(Collectors.toMap(Student::getId, e->e.getName()==null?"":e.getName()));
3.假如存在id重复,两个vaue可以这样映射到同一个id:
Map<String, String> map = list.stream().collect(Collectors.toMap(Student::getId,Student::getName,(e1,e2)->e1+","+e2));
4.JSONArray类型返回Map
anyMatch()、allMatch()、noneMatch()
// anyMatch():匹配到任何一个元素和指定的元素相等,返回 true
// allMatch():匹配到全部元素和指定的元素相等,返回 true
// noneMatch():与 allMatch() 效果相反