详解Spring的StringUtils踩坑记录

起因

最近在写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()方法的逻辑很简单

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

而我的问题就是由第二点引起的,因为类型不相同┴─┴︵╰(‵□′╰)

教训总结

  1. 不建议使用Spring的StringUtils的isEmpty()对非String类型的对象判空。(这里建议换成apache common的StringUtils或者Google Guava的Strings,这两个工具包都是类型强约束的)
  2. 无论是修改哪处的代码都最好检查一下引用,避免修复小问题引出大问题

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java中StringUtils工具类进行String为空的判断解析

    判断某字符串是否为空,为空的标准是str==null或str.length()==0 1.下面是StringUtils判断是否为空的示例: StringUtils.isEmpty(null) = true StringUtils.isEmpty("") = true StringUtils.isEmpty(" ") = false //注意在 StringUtils 中空格作非空处理 StringUtils.isEmpty(" ") = fals

  • 基于StringUtils工具类的常用方法介绍(必看篇)

    前言:工作中看到项目组里的大牛写代码大量的用到了StringUtils工具类来做字符串的操作,便学习整理了一下,方便查阅. isEmpty(String str) 是否为空,空格字符为false isNotEmpty(String str) 是否为非空,空格字符为true isBlank(String str) 是否为空,空格字符为true isNotBlank(String str) 是否为非空,空格字符为false trim(String str)去除字符串两端的控制符,空字符串.null

  • javaScript字符串工具类StringUtils详解

    本文实例为大家分享了javaScript字符串工具类的具体代码,供大家参考,具体内容如下 StringUtils = { isEmpty: function(input) { return input == null || input == ''; }, isNotEmpty: function(input) { return !this.isEmpty(input); }, isBlank: function(input) { return input == null || /^\s*$/.t

  • java自定义封装StringUtils常用工具类

    自定义封装StringUtils常用工具类,供大家参考,具体内容如下 package com.demo.utils; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * 字符串操作工具类 * @author dongyangyang * @Date 2016/12/28 23:12 * @Version 1.0 * */ public class StringUtils { /** * 首字

  • StringUtils工具包中字符串非空判断isNotEmpty和isNotBlank的区别

    在项目中,我们用的最多的是StringUtils中的非空判断方法,相信大部分人都用过IsNotEmpty或者isEmpty方法 今天我们要提到的,是isNotBlank public static boolean isNotEmpty(String str) 判断某字符串是否非空,等于!isEmpty(String str),这里不能排除空格字符 下面是示例: StringUtils.isNotEmpty(null) = false StringUtils.isNotEmpty("")

  • Java StringUtils字符串分割转数组的实现

    我们在日常开发时会经常遇到将一个字符串按照指定的字符进行分割. 这时,我们往往会想到使用str.split(","),进行处理得到分割后的数组. 然而, 使用split()方法在分割特殊的字符时是需要转移的.如小数点"." 下面我为大家推荐一种可以无需转义,即可分割的方法. 使用 org.springframework.util.StringUtils 中的 delimitedListToStringArray(str,delimiter) 进行测试 public

  • Java中StringUtils工具类的一些用法实例

    StringUtils 方法的操作对象是 java.lang.String 类型的对象,是 JDK 提供的 String 类型操作方法的补充,并且是 null 安全的(即如果输入参数 String 为 null 则不会抛出 NullPointerException ,而是做了相应处理,例如,如果输入为 null 则返回也是 null 等,具体可以查看源代码). 除了构造器,StringUtils 中一共有130多个方法,并且都是 static 的,所以我们可以这样调用 StringUtils.x

  • 详解Spring的StringUtils踩坑记录

    起因 最近在写CRUD的时候,发现有个分页的VO写的健壮性比较差,一时手痒改了一下,没想到改了之后好几个功能都出现了问题. 原VO关键代码如下: public class PageVo implements Serializable{ // ...省略所有无关代码 Map<String, String> query } 这个VO是用于从前端分页查询时传参,而query是用于传递查询条件的(这里不讨论用Map传参是否合理).当前端无查询条件时则会导致query为null,如果不注意容易出现NPE

  • 详解spring cloud feign踩坑记录

    1:多客户端时,feign接口抽取到公共jar中,此时,客户端的启动类上需要对该jar中feign所在的包进行扫描,要在spring和feign中同时注册,否则启动时会报:"Consider defining a bean of type '******Feign' in your configuration." @SpringBootApplication @EnableTransactionManagement @EnableDiscoveryClient @ComponentSc

  • Spring Data JPA踩坑记录(@id @GeneratedValue)

    目录 Spring Data JPA踩坑记录 JPA踩坑:No property xxx found for type xxx 问题发现 问题解决 Spring Data JPA踩坑记录 最近在做自己的一个项目时 使用了spring jpa 由于数据库用的是mysql 在给实体类entity 的id给注解时@Id遇到了一个坑 自己找了许久才在stackoverflow 上找到了答案 注意 再查询数据库的时候并不会因此报错 而当你的主键是自增的时候 在添加数据的时候就会报错了 看看我们的实体类 注

  • 详解小程序BackgroundAudioManager踩坑之旅

    由于贵公司业务发展需要,切图仔开始写起了小程序啦(兴奋地搓小手手) 贵公司是知识付费平台,需要音频播放课程,同时希望用户在退出小程序后依然可以听课.在这种情况下,小程序的API--BackgroundAudioManager就派得上用场啦. 在看完官方文档,信心满满地写完提测后,测试小姐姐找出的bug比我的工资还多!!(

  • 详解升级react-router 4 踩坑指南

    一.前言 上午把近日用React做的一个新闻项目所依赖的包升级到了最新的版本,其中从react-router(2.8.1)升级到react-router(4.1.2)中出现了很多问题, 故总结一下在升级过程中遇到的问题. 二.react-router,V4版本修改内容 1. 所有组件更改为从react-router-dom导入 之前的所有路由组件均是从react-router中导入,在我之前的项目中,导入相关组件如下: //v2 import {Router,Route,hashHistory}

  • 详解Spring Boot下使用logback 记录多个文件日志

    背景 这两天遇到一个比较有意思的日志问题. 近期对我之前的python代码进行java的重构, 一方面是因为java使用的医疗库非常健全稳定, 可以商用. 另一方面是因为java速度快, 这个库的实现的效率也高, 性能是Python版本的好几倍. 但是作为这个项目的唯一作者, 我的癖好也成为这个项目的风格. 这个项目会给很多部署工程师使用. 当然项目的可用性和性能作为第一考虑的因素, 但是作为一个懒人, 对使用软件时候的复杂部署过程和混乱调试信息深恶痛绝. 所以我在项目中使用了高度可配置/易用和

  • 详解vue-class迁移vite的一次踩坑记录

    目录 what happen 探究 解决 总结 what happen 最进项目从 vue-cli 迁移到了 vite,因为是 vue2 的项目,使用了 vue-class-component类组件做 ts 支持.当然迁移过程并没有那么一帆风顺,浏览器控制台报了一堆错,大致意思是某某方法为 undefined,无法调用.打印了下当前 this,为 undefined 的方法都来自于 vuex-class 装饰器下的方法.这就是一件很神奇的事,为什么只有 vuex-class 装饰器下的方法才会为

  • 详解element-ui 组件el-autocomplete使用踩坑记录

    项目遇到一个比较麻烦的需求,保存用户填写的历史记录,项目使用的element-ui,自然就使用了el-autocomplete组件,然后就是各种踩坑,以下记录以下写代码过程中遇到的问题 createFilter(queryString, filed) { console.log("createFilter==" + queryString) return (item) => { switch (filed) { case 'cardNum': break case 'cardPa

  • 详解vue-socket.io使用教程与踩坑记录

    目录 前言 我遇到的问题 使用教程 安装 引入(main.js) 使用(Page.vue) 解决方案 结合connect事件+store+路由守卫实现拦截 请先允许我狠狠吐个槽:vue-socket.io相关中文博客实在太少太少,来来去去就那么几篇,教程也比较零散,版本也比较老,就算我有暴风式搜索还是找不到解决问题的方案,然后我怒了,开始看源码.写测试demo.几乎把相关的issues都看了一遍,折腾1天后终于...搞定了,下面总结一下~ 考虑到很多小伙伴看完文章还是一头雾水或者无法复现方案,附

  • 详解Spring Cloud Feign 熔断配置的一些小坑

    1.在使用feign做服务调用时,使用继承的方式调用服务,加入Hystrix的熔断处理fallback配置时,会报错,已解决. 2.使用feign默认配置,熔断不生效,已解决. 最近在做微服务的学习,发现在使用feign做服务调用时,使用继承的方式调用服务,加入Hystrix的熔断处理fallback配置时,会报错,代码如下: @RequestMapping("/demo/api") public interface HelloApi { @GetMapping("user/

随机推荐