专栏首页Java那些事上线后发现自己写了个Bug,一通操作后终于解决了

上线后发现自己写了个Bug,一通操作后终于解决了

记录一次在写代码时愚蠢的操作,本文涉及到的知识点:String不可变性 出自公众号:Java3y

一、交代背景

我这边有一个系统,提供一个RPC接口去发送短信。外部调用我的接口需要传入手机号等等参数,我这边负责解析这些参数、做一些业务的处理,然后调用短信渠道商的接口发送短信。

每当调用完短信渠道商的接口时,我会对这次发送的记录入库(存入MySQL中),同样地短信渠道商会返回发送或失败的回执给我,我也会入库(存入MySQL中)。

那天,有人来找到我,说某个手机号收不到短信,用户并没有屏蔽短信(欠费、关机)等等一些操作,就是收不到短信。

于是我就去排查啦,首先我先去DB里边找有没有对应的发送记录,发现这条记录是存在的,而且在DB上看不出来有什么异常。

  • 所以,这就排除了这个操作在中途被拦截的情况(因为已经入库了,就肯定调用过短信运营商的接口)

后来就去捞日志,看看调用短信运营商返回的Result对象的信息是什么,然后就去问了一下短信运营商可能出现这种问题的原因是什么。那边回复的是:“如果是部分的手机号出现这种状况,是不是你们的手机号没有trim啊?

于是,我又去捞日志,发现手机号后面真的带有一个空格(扎心了,之前一直看不到)。要处理这个问题就变得异常简单了,我只要在入口里边对手机号进行trim就好了。

二、编写代码

我这边是支持同一条短信向多个手机号发送,于是手机号我这边用的是HashSet来进行接收。对手机号进行trim我写下了如下的代码:

// 说明:Task对象 有个 key属性,这个key属性的类型是HashSet

if (task.getKey() != null && task.getKey().size() > 0) {
    for (String s : task.getKey()) {
        s.trim();
    }
}

代码很简单,我做的就两步:

  • 判断是否为null,不为null值则遍历手机号集合
  • 对每个手机号进行trim

上面的代码有问题吗?必须有问题啊,没问题我还写啥。

下面写个小Demo,我们会发现:在代码的11行上调用trim()方法后,在12行再输出,还是会有空格的情况。

代码示例

2.1 为什么会有这种错觉?

其实,我们在初学Java的时候,肯定会学到String类。在学习的时候也是明确String是不可变的,但总是有个感觉我们把String对象给改了,为什么?

不可变的String

我觉得第一点是这样的:我们操作的往往是可变的对象,对象的某些属性改了,我们就认为已经改了。比如下面的代码:

HashSet<Student> students = getStudent();
for (Student s1 : students) {
    s1.setName("Java3y");
}

执行完,我们就认为在HashSet里边的Student的名字全改成Java3y了,而实际上也是如此。

我觉得第二点是这样的:我们平时操作String对象,都是直接把操作后的结果传过去,这看起来就像修改原对象了一样。比如下面类似的代码:

// 去重
String phone = "   137888888888    ";
sendPhone(phone.trim());

// 转成大写后输出
System.out.println(phone.toUpperCase());

// ... 等等

返回一个新的String对象

2.2 怎么改

现在问题已经知道了,String对象是不可变的,对String对象进行操作,“看似”把原来的String对象改了,实际上是生成了一个新的String对象。

回到我那个问题,也很好解决,把trim好的手机号设置到HashSet就行了

// 说明:Task对象 有个 key属性,这个key属性的类型是HashSet

HashSet<String> hs = new HashSet();
if (task.getKey() != null && task.getKey().size() > 0) {
    for (String s : task.getKey()) {
        hs.add(s.trim());
    }
}
task.setKey(hs);

本文分享自微信公众号 - 程序员乔戈里(CXYqiaogeli)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 这样规范写代码,同事直呼“666”

    乔戈里
  • BATJ面试必会之Java IO 篇

    实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。

    乔戈里
  • 【图解】记一次手撕算法面试:字节跳动的面试官把我四连击了

    字节跳动这家公司,应该是所有秋招的公司中,对算法最重视的一个了,每次面试基本都会让你手撕算法,今天这篇文章就记录下当时被问到的几个算法题,并且每个算法题我都详细...

    乔戈里
  • 记一次愚蠢的操作--String不可变性

    我这边有一个系统,提供一个RPC接口去发送短信。外部调用我的接口需要传入手机号等等参数,我这边负责解析这些参数、做一些业务的处理,然后调用短信渠道商的接口发送短...

    Java3y
  • 配置文件properties读取使用的好方法

      首先在spring配置文件applicationContext.xml中配置、

    老梁
  • SQL基础用法(实例二)

    用户1112962
  • Meta Learning 入门:MAML 和 Reptile

    七期飞跃计划还剩7个名额,联系小编,获取你的专属算法工程师学习计划(联系小编SIGAI_NO1)

    SIGAI学习与实践平台
  • 第三节,SpringBoot集成shrio,Redis缓存session与权限

    https://gitee.com/DencyCheng/springboot-shrio/tree/dev/

    DencyCheng
  • 深度学习未来的黑科技

    对于物理学家来说,这并不是一个好时代。 ? 奥斯卡·博伊金 至少对于奥斯卡·博伊金来说是这样的。这位2002年毕业于美国加州大学洛杉矶分校的物理学博士,四年前,...

    IT派
  • Android开发实现读取Assets下文件及文件写入存储卡的方法

    本文实例讲述了Android开发实现读取Assets下文件及文件写入存储卡的方法。分享给大家供大家参考,具体如下:

    砸漏

扫码关注云+社区

领取腾讯云代金券