龙空技术网

Java Split():轻视limit参数带来的Bug

庆余粟 104

前言:

现在各位老铁们对“java split 方法详解”大概比较珍视,兄弟们都需要知道一些“java split 方法详解”的相关文章。那么小编也在网摘上搜集了一些有关“java split 方法详解””的相关知识,希望朋友们能喜欢,大家一起来了解一下吧!

前两天在排查个bug,问题的根节倒是不复杂,但整个过程也是小有收获。

埋雷

数据库实体中有这么个字段:

@Convert(converter = MapConverter.class)private Map<String, String> links;

MapConverter的实现

public class MapConverter implements AttributeConverter<Map<String, String>, String> {    @Override    public String convertToDatabaseColumn(Map<String, String> strMap) {        return strMap == null ? null : strMap.toString();    }    @Override    public Map<String, String> convertToEntityAttribute(String s) {		// 空值处理        try {            Map<String, String> map = new IdentityHashMap<>();            // DB的列存的是字符串,形如 {key1=val1, key2=val2}, 所以这里去掉首尾的大括号,然后切分            String string = s.substring(1, s.length() - 1);            String[] list = string.split(",");            for (String str : list) {                String[] con = str.trim().split("=");                map.put(con[0], con[1]);            }            return map;        } catch (Exception e) {            ...        }		...    }}

在这个ORM模型中,MapConverter定义了将对象中的Map结构如何存储到数据库的列中,以及如何从列解析到对象中。

踩雷

在生产环境,发现存入:

strMap.put("toutiao", ";)strMap.put("xiaomi", ";)

读取出来的toutiao链接仅为";

而且在存入DB接口,返回结果是正常的;查询结果就是不正常,而且更新其他字段后,发现DB中存的也仅仅是"{toutiao=, ...}".

在排除了缓存等原因之后,将目光聚焦到MapConverter上,但是:convertToDatabaseColumn方法,不可能存在截断处理,那为什么DB中存的是不完整的链接了?

难不成convertToEntityAttribute这个负责读取DB内容进行解析映射的方法能兴风作浪?

屏气读到:

String[] con = str.trim().split("=");

会发现,split没有填入任何参数,这意味着切分所用的pattern将被尽可能多的执行,所以它取con[1]只能取到";,这能解释了读取的问题

但是它如何影响DB中的存储结果了?

因为用的是ORM嘛

当你更新时,先查询这个对象,这个时候,会用到"convertToEntityAttribute", 它已经背弃你的初衷,返回了一个错误的结果;然后更新实体对象,持久化到DB中,这时DB的结果自然也是错误的。

清雷

那如何解决了?

造轮子这种事情还是要谨慎的,如果可以交给Jackson去转换,可以大大降低这种各种边际情况的发生吧

那非要自己切分了?split的limit的请了解一下:

split其实就是用正则表达式去匹配提取,它的另一个参数limit常常会被忽视,但确实非常重要的参数。

public String[] split(String regex, int limit)regex -- 这是在限定的正则表达式。limit -- 这个控制模式施加的数的次数,因此,会影响所得到的数组的长度

总的来说:

如果 n < 0,那么模式将被应用尽可能多的次数,而且数组可以是任何长度。如果 n = 0,那么模式将被应用尽可能多的次数,数组可以是任何长度,并且结尾空字符串将被丢弃。如果 n > 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n,而且数组的最后一项将包含所有超出最后匹配的定界符的输入。

应用在本处, 上述可改成如下(记得在放进map的时候,加上NPE判断等)

String[] con = str.trim().split("=", 2);

标签: #java split 方法详解