在之前编写业务代码时, 遇到了一个比较神奇的现象, 如标题中描述的那样: 在对list 集合使用 add/set 方法并且遍历的去添加对象时, 只会添加最后一个元素的问题 . 下面就进行简单的分析,
现有一个需求: 在请求时携带一个map, 该map里面的key有几个. 那么, 在返回结果集 map中就需要将对应的 key 和 value 捞出来一起展示, 如果结果不止一个map, 则将这些map放入一个list中
模拟代码片如下
结果演示 可以看到, 在上面结果集 resultListMap遍历过程中, 我们根据请求 requestMap的key 去结果集中寻找key对应的value 然后放入 responseMap, 因为结果集map 不止一个, 所以将其放入list 中. 但是,
List<User> userList = new ArrayList<>(2);
User u1 = new User();
for (int i = 0; i < 5; i++) {
u1.setId(i);
u1.setPwd("odd taxi"+ i);
u1.setUsername("小早川"+ i);
userList.add(u1);
}
for (User user : userList) {
System.out.println("user = " + user);
}
结合上面问题和调试结果, 以及资料可知: 1. List 中的 add, set 方法在添加对象(Object) 或者是集合(Collection)时, 添加的是对对象的引用 因此, 如果在循环外声明要保存的对象或集合, 但是却在循环内赋值的话, 就会导致上述问题 2. 因为在循环外对象或者集合只声明了一次, 因此无论如何赋值, 只会保存最后一次赋值. 而在循环内 list.add 方法添加的实际上只相当于对最后一次插入的对象或者集合的引用
List<User> userList = new ArrayList<>(2);
User u1 ;
for (int i = 0; i < 5; i++) {
u1 = new User();
u1.setId(i);
u1.setPwd("odd taxi"+ i);
u1.setUsername("小早川"+ i);
userList.add(u1);
}
for (User user : userList) {
System.out.println("user = " + user);
}
根据上述思路我们去解决实际问题, 对比下修改前和修改后的代码
//---------------------修改前---------------------
//模拟请求
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("id", "");
requestMap.put("passwd", "");
requestMap.put("userName", "");
//模拟结果集
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("id", "1");
resultMap.put("passwd", "odd taxi");
resultMap.put("userName", "小早川");
Map<String, Object> resultMap2 = new HashMap<>();
resultMap2.put("id", "2");
resultMap2.put("passwd", "Brazilian war dance");
resultMap2.put("userName", "白川");
List<Map<String, Object>> resultListMap = new ArrayList<>();
resultListMap.add(resultMap);
resultListMap.add(resultMap2);
//模拟响应
List<Map<String, Object>> responseListMap = new ArrayList<>();
Map<String, Object> responseMap = new HashMap<>();
// 实现: 根据请求map中的 key, 返回所有结果集中含有请求map所带k的list.map集合
for (Map<String, Object> resMap : resultListMap) {
requestMap.forEach((k, v) -> {
responseMap.put(k, resMap.get(k));
});
responseListMap.add(responseMap);
}
System.out.println("responseListMap = " + responseListMap);
//---------------------修改后---------------------
//模拟请求
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("id", "");
requestMap.put("passwd", "");
requestMap.put("userName", "");
//模拟结果集
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("id", "1");
resultMap.put("passwd", "odd taxi");
resultMap.put("userName", "小早川");
Map<String, Object> resultMap2 = new HashMap<>();
resultMap2.put("id", "2");
resultMap2.put("passwd", "Brazilian war dance");
resultMap2.put("userName", "白川");
List<Map<String, Object>> resultListMap = new ArrayList<>();
resultListMap.add(resultMap);
resultListMap.add(resultMap2);
//模拟响应
List<Map<String, Object>> responseListMap = new ArrayList<>();
// 实现: 根据请求map中的 key, 返回所有结果集中含有请求map所带k的list.map集合
for (Map<String, Object> resMap : resultListMap) {
// 问题修改: 将 list 需要 add 的对象/集合 放到循环内进行初始化!!!
Map<String, Object> responseMap = new HashMap<>();
requestMap.forEach((k, v) -> {
responseMap.put(k, resMap.get(k));
});
responseListMap.add(responseMap);
}
System.out.println("responseListMap = " + responseListMap);
1. List 中的 add, set 方法在添加对象(Object) 或者是集合(Collection)时, 添加的是对对象的引用 2. 在循环外声明对象或集合, 在循环内使用list.add 就会导致list 中引用的数据地址全部都是最后一次添加的元素地址 如果想要避免. 只需要将被add的对象/集合在循环内初始化即可
参考: https://blog.csdn.net/ww77889126/article/details/84952631