Spring的StringUtils踩坑记录

原由

最近在写CRUD的时候,发现有个分页的VO写的健壮性比较差,一时手痒改了一下,没想到改了以后好几个功能都出现了问题。前端

VO关键代码以下:apache

public class PageVo implements Serializable{
    // ...省略全部无关代码
    Map<String, String> query
    
}

这个VO是用于从前端分页查询时传参,而query是用于传递查询条件的(这里不讨论用Map传参是否合理)。当前端无查询条件时则会致使querynull,若是不注意容易出现NPE数组

因此我就改形成下面这样了。工具

public class PageVo implements Serializable{
    // ...省略全部无关代码
    Map<String, String> query=new HashMap<>
    
}

可是没想到就是这么简单的改造竟然都翻车(・ε・`)源码分析

没办法,只好去排查问题。this

发现问题

想过不少种缘由,可是我真没想到竟然是由于这样(/‵Д′)/~ ╧╧,很少说了,问题关键代码以下:设计

if (StringUtils.isEmpty(page.getQuery())) {
    // 省略处理逻辑
}

竟然用StringUtils去判断一个Map是否为空,好歹也换个CollectionUtils啊(╬ ̄皿 ̄)凸code

虽然是前人挖坑,可是为何Spring`StringUtils竟然设计成支持Object入参呢o_o ....对象

想了一下,仍是去看看源码吧get

源码分析

StringUtilsisEmpty()方法源码超级简单,三行代码搞定(其实严格来讲就一行代码):

public static boolean isEmpty(@Nullable Object str) {
    return (str == null || "".equals(str));
}

既然个人Map对象不为null,那么问题应该是由于Stringequals()方法。很少说,继续跟踪源码

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        // 问题出在这里
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

这个equals()方法的逻辑很简单

  1. 入参为null则返回true
  2. 入参不为String类型返回false
  3. 入参对象和this对象都为String就比较它们内置的char[]数组长度和每一个char元素是否相同,知足则返回true,不然返回false

而个人问题就是由第二点引发的,由于类型不相同┴─┴︵╰(‵□′╰)

教训总结

  1. 不建议使用SpringStringUtilsisEmpty()对非String类型的对象判空。(这里建议换成apache commonStringUtils或者Google GuavaStrings,这两个工具包都是类型强约束的)
  2. 不管是修改哪处的代码都最好检查一下引用,避免修复小问题引出大问题
相关文章
相关标签/搜索