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. 不管是修改哪處的代碼都最好檢查一下引用,避免修復小問題引出大問題
相關文章
相關標籤/搜索