使用StringTokenizer还原HashMap引入多余字符问题排查
问题根源
你遇到的不是正常现象,完全是操作错误导致的。直接调用String.valueOf(HashMap)得到的是HashMap默认的toString()输出,格式是{key1=value1, key2=value2, ...},这种格式只是用来打印查看的,根本不适合用来反序列化还原HashMap:
- 键值对之间用
,分隔,但如果value本身包含逗号或空格,StringTokenizer会把这些字符当成分隔标记,导致拆分错误; - 字符串首尾的
{}是格式字符,会被混入拆分后的结果; StringTokenizer默认按空白字符拆分,带空格的value会被直接截断。
你的还原代码里,比如第一个token可能是{INFILEDFT=Y,,用split("=")后得到key是{INFILEDFT,value是Y,,这就是你看到的异常情况。
正确的解决方法
不要用toString()传递HashMap,推荐用以下几种靠谱的方式:
1. Java原生序列化(Serializable)
只要HashMap的键和值都实现Serializable接口(String、基本类型包装类都默认实现了),就可以把对象转成字节数组,再转成Base64字符串传递:
// 发送方:将HashMap转成Base64字符串 import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.util.Base64; import java.util.HashMap; public static String hashMapToString(HashMap<String, String> map) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(map); oos.close(); return Base64.getEncoder().encodeToString(bos.toByteArray()); } // 接收方:将Base64字符串还原成HashMap import java.io.ByteArrayInputStream; import java.io.ObjectInputStream; import java.util.Base64; import java.util.HashMap; public static HashMap<String, String> stringToHashMap(String str) throws Exception { byte[] data = Base64.getDecoder().decode(str); ByteArrayInputStream bis = new ByteArrayInputStream(data); ObjectInputStream ois = new ObjectInputStream(bis); HashMap<String, String> map = (HashMap<String, String>) ois.readObject(); ois.close(); return map; }
2. JSON序列化(更直观,推荐新手)
用JSON库(比如Gson或Jackson)把HashMap转成JSON字符串,还原也非常简单,而且JSON格式可读性强:
比如用Gson(需要先导入Gson依赖,Maven的话加<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.10.1</version></dependency>):
// 发送方:转成JSON字符串 import com.google.gson.Gson; import java.util.HashMap; Gson gson = new Gson(); String jsonStr = gson.toJson(cParmValueKv); cArgs[1] = jsonStr; // 接收方:还原成HashMap import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.util.HashMap; HashMap<String, String> cKeyValueMap = gson.fromJson(jsonStr, new TypeToken<HashMap<String, String>>(){}.getType());
3. 手动定义分隔规则(不推荐,仅作了解)
如果不想用序列化库,必须手动处理字符串,得定义不会出现在value里的特殊分隔符:
// 发送方:自定义格式,比如用"|||"分隔键值对,用"==="分隔key和value import java.util.HashMap; import java.util.Map; StringBuilder sb = new StringBuilder(); for (Map.Entry<String, String> entry : cParmValueKv.entrySet()) { sb.append(entry.getKey()).append("===").append(entry.getValue()).append("|||"); } // 去掉最后一个分隔符 String str = sb.substring(0, sb.length() - 4); cArgs[1] = str; // 接收方:拆分字符串 import java.util.HashMap; String[] keyValuePairs = str.split("\\|\\|\\|"); HashMap<String, String> map = new HashMap<>(); for (String pair : keyValuePairs) { String[] kv = pair.split("==="); if (kv.length == 2) { map.put(kv[0], kv[1]); } }
注意:这种方式要求value里不能包含你选的分隔符,否则还是会出错,所以不如序列化靠谱。
总结
你不需要手动处理那些多余字符,问题的核心是用了错误的方式传递HashMap。换掉String.valueOf(HashMap)的方式,用上面的序列化方法就能彻底解决问题。
内容的提问来源于stack exchange,提问作者Louise

