Stream流

124 阅读3分钟

网上有很多关于stream流的文章和案例分析,我只记录自己在实际开发中用过的,慢慢更新记录。 ps:用的jdk17,用toList()代替collect(Collectors.toList())

1.以逗号分割的字符串转list

// 以逗号分割的字符串转list  
String userId = "25421,84521,78495,23584";  
List<String> userIdList = Arrays.stream(userId.split(",")).collect(Collectors.toList());  
userIdList.stream().forEach(System.out::println);  
// jdk17 可以直接用toList()代替  
System.out.println("------------------------");  
userIdList = Arrays.stream(userId.split(",")).toList();  
userIdList.stream().forEach(System.out::println);  
  
// 正在使用以上字符串是没有问题的,但如果是客户自己输入,可能会出现以下情况  
userId = "25421,84521,78495,23584,";  
// 这种情况,如果我们不做任何业务逻辑其实也不影响什么,如果这个字符串是客户手机号,一般情况会使用正则校验手机号  
// 这时,我会考虑到代码健壮性,会这样操作,避免因为一个逗号(,),出现其他问题  
if (userId.endsWith(",")) {  
// todo 这里可以根据实际业务,抛出异常或者是直接截取  
userId = userId.substring(0, userId.length() - 1);  
}  
userIdList = Arrays.stream(userId.split(",")).toList();  
System.out.println("------------------------");  
userIdList.stream().forEach(System.out::println);  
  
// 如果是将这个字符串插入到数据库中,那么还需要考虑空字符情况,  
// 避免出现通过某个后台管理系统配置的数据,导致客户端在使用时,出现异常  
userId = "25421,,78495,23584";  
userIdList = Arrays.stream(userId.split(",")).filter(s -> StringUtils.isNoneBlank(s.trim())).toList();  
System.out.println("------------------------");  
userIdList.stream().forEach(System.out::println);  
  
// 但对于这种情况,现在还用的是foreach todo 我还没找到用stream流如何解决,  
List<String> list = new LinkedList<>();  
userId = "25421 ,78495,23584";  
for (String s : userId.split(",")) {  
list.add(s.trim());  
}  
System.out.println("------------------------");  
list.stream().forEach(System.out::println);

2.将List转为以逗号分割的字符串

// 将List转为以逗号分割的字符串  
List<String> list = Arrays.asList("25421", "84521", "78495", "23584");  
// 在我接触Stream流以前,我都是这样处理的  
StringBuffer sb = new StringBuffer();  
String userId = "";  
for (String s : list) {  
sb.append(s).append(","); // 逗号可换成其他符号  
}  
userId = sb.toString();  
if (sb.toString().endsWith(",")) {  
userId = sb.substring(0, sb.length() - 1);  
}  
System.out.println(userId);  
System.out.println("------------------------");  
// 认识Stream流之后  
if (CollectionUtils.isNotEmpty(list)) {  
userId = list.stream().collect(Collectors.joining(","));  
}  
System.out.println(userId);  
  
// 有时候还是List<Map<String,Object>>类型的数据  
// 认识Stream之前也是要遍历用StringBuffer  
List<Map<String, Object>> userIdMapList = new LinkedList<>();  
Map<String, Object> userIdMap1 = new HashMap<>();  
Map<String, Object> userIdMap2 = new HashMap<>();  
Map<String, Object> userIdMap3 = new HashMap<>();  
Map<String, Object> userIdMap4 = new HashMap<>();  
userIdMap1.put("userId", "25421");  
userIdMap2.put("userId", "84521");  
userIdMap3.put("userId", "78495");  
userIdMap4.put("userId", "23584");  
userIdMapList.add(userIdMap1);  
userIdMapList.add(userIdMap2);  
userIdMapList.add(userIdMap3);  
userIdMapList.add(userIdMap4);  
// 有空的过滤下value为null  
userId = userIdMapList.stream().  
map(item -> (String) item.get("userId")).collect(Collectors.joining(","));  
System.out.println("------------------------");  
System.out.println(userId);

3.Stream流分组结合排序

// 之前有个任务,按产品渠道分组后在按照产品类型从小到大排序,有表A、表B 通过主外键关联,由于没有设计实体类,直接用List<Map>>代替  
List<Map<String, Object>> channelMapList = new LinkedList<>();  
// 手动造数  
String[] channelS = {"A", "B", "C", "D"};  
String[] productS = {"1", "3", "4", "2"};  
for (String channel : channelS) {  
for (String product : productS) {  
Map<String, Object> channelMap = new HashMap<>();  
channelMap.put("channel", channel);  
channelMap.put("product", product);  
channelMapList.add(channelMap);  
}  
}  
channelMapList.stream().forEach(System.out::println);  
// 分组  
Map<String, List<Map<String, Object>>> channelMap = channelMapList.stream().collect(Collectors.groupingBy(item -> (String) item.get("channel")));  
System.out.println("------------------------");  
System.out.println(channelMap);  
// 按产品排序  
Set<String> keySet = channelMap.keySet();  
for (String key : keySet) {  
List<Map<String, Object>> product = channelMap.get(key).stream().sorted(Comparator.comparing(o -> o.get("product").toString())).toList();  
channelMap.put(key, product);  
} // 貌似还是不智能  
System.out.println("------------------------");  
System.out.println(channelMap);  
  
// 智能一些操作,先排序在分组  
channelMap = channelMapList.stream().sorted(Comparator.comparing(o -> o.get("product").toString())).collect(Collectors.groupingBy(item -> (String) item.get("channel")));  
System.out.println("------------------------");  
System.out.println(channelMap);  
// 总结:其实stream流这种模式写,比较简洁,但从打印结果来看,会出现一些额外参数,  
// 比如在分组后每个Map<key,List<Map>>中,List<Map>还存在channel这个属性值,或者其他一些前端用不上属性值,在实际开发中,可以在动态调整下  
// ps:像上面案例中,还会存在漏洞,比如排序用toString,如果该属性值为null,会导致空指针异常,所以实际开发中,还需要考虑其他因素

4.List集合收集

List<String> list = Arrays.asList("25421", "84521", "78495", "23584");  
List<Map<String, String>> userList = list.stream().map(s -> {  
Map<String, String> userMap = new HashMap<>();  
userMap.put("userId", s);  
userMap.put("userPhone", getUserPhoneRandom()); // 用随机数代替  
return userMap;  
}).filter(item -> ObjectUtils.isNotEmpty(item)).toList();  
System.out.println(userList);
private String getUserPhoneRandom() {  
String phone = "181"; // 省时间  
SecureRandom random = new SecureRandom();  
for (int i = 0; i < 8; i++) {  
phone += random.nextInt(10);  
}  
return phone;  
}

总结:由于我们项目中使用Map次数高于实体类,故案例都是用的Map,以后可试着写一下用实体类