最近在写 CRUD
的时候,发现有个分页的 VO
写的健壮性比较差,一时手痒改了一下,没想到改了之后好几个功能都出现了问题。
原 VO
关键代码如下:
public class PageVo implements Serializable{ // ...省略所有无关代码 Map<String, String> query }
这个 VO
是用于从前端分页查询时传参,而 query
是用于传递查询条件的(这里不讨论用 Map
传参是否合理)。当前端无查询条件时则会导致 query
为 null
,如果不注意容易出现 NPE
。
所以我就改造成下面这样了。
public class PageVo implements Serializable{ // ...省略所有无关代码 Map<String, String> query=new HashMap<> }
但是没想到就是这么简单的改造居然都翻车(・ε・`)
没办法,只好去排查问题。
想过很多种原因,但是我真没想到居然是因为这样(/‵Д′)/~ ╧╧,不多说了,问题关键代码如下:
if (StringUtils.isEmpty(page.getQuery())) { // 省略处理逻辑 }
居然用 StringUtils
去判断一个 Map
是否为空,好歹也换个 CollectionUtils
啊(╬ ̄皿 ̄)凸
虽然是前人挖坑,但是为什么 Spring
的 StringUtils
居然设计成支持 Object
入参呢o_o ....
想了一下,还是去看看源码吧
StringUtils
的 isEmpty()
方法源码超级简单,三行代码搞定(其实严格来说就一行代码):
public static boolean isEmpty(@Nullable Object str) { return (str == null || "".equals(str)); }
既然我的 Map
对象不为 null
,那么问题应该是因为 String
的 equals()
方法。不多说,继续跟踪源码
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()
方法的逻辑很简单
null
则返回 true
String
类型返回 false
this
对象都为 String
就比较它们内置的 char[]
数组长度和每个 char
元素是否相同,满足则返回 true
,否则返回 false
而我的问题就是由第二点引起的,因为类型不相同┴─┴︵╰(‵□′╰)
Spring
的 StringUtils
的 isEmpty()
对非 String
类型的对象判空。(这里建议换成 apache common
的 StringUtils
或者 Google Guava
的 Strings
,这两个工具包都是类型强约束的)