记一次愚蠢的操作--String不可变性

Bertha 。 2021-09-30 05:14 439阅读 0赞

前言

只有光头才能变强。

文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y

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

一、交代背景

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

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

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

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

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

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

二、编写代码

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

  1. // 说明:Task对象 有个 key属性,这个key属性的类型是HashSetif (task.getKey() != null && task.getKey().size() > 0) { for (String s : task.getKey()) { s.trim(); }}
  2. if (task.getKey() != null && task.getKey().size() > 0) {
  3. for (String s : task.getKey()) {
  4. s.trim();
  5. }
  6. }

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

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

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

640?wx\_fmt=png 代码示例

2.1 为什么会有这种错觉?

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

640?wx\_fmt=png 不可变的String

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

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

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

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

  1. // 去重String phone = " 137888888888 ";sendPhone(phone.trim());// 转成大写后输出System.out.println(phone.toUpperCase());// ... 等等
  2. String phone = " 137888888888 ";
  3. sendPhone(phone.trim());
  4. // 转成大写后输出
  5. System.out.println(phone.toUpperCase());
  6. // ... 等等

640?wx\_fmt=png 返回一个新的String对象

2.2 怎么改

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

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

  1. // 说明:Task对象 有个 key属性,这个key属性的类型是HashSetHashSet<String> hs = new HashSet();if (task.getKey() != null && task.getKey().size() > 0) { for (String s : task.getKey()) { hs.add(s.trim()); }}task.setKey(hs);
  2. HashSet<String> hs = new HashSet();
  3. if (task.getKey() != null && task.getKey().size() > 0) {
  4. for (String s : task.getKey()) {
  5. hs.add(s.trim());
  6. }
  7. }
  8. task.setKey(hs);

最后

这个B写了一篇文章来解释自己是怎么“合理“写Bug的,真tm不要脸。

推荐阅读:

  • 大佬准备了一年时间拿到今日头条offer

  • 进程之间究竟有哪些通信方式?—— 告别死记硬背

  • 什么是列式存储?
  • 硬核干货长文!Hbase来了解一下不?
  • 程序员的快乐就是这么朴素无华且枯燥
  • 互联网/电商/广告常见的术语
  • 拿到一台新的Windows电脑,我会做什么?
  • 在公司做的项目和自己在学校做的有什么区别

640?wx\_fmt=jpeg

200多篇 原创 技术文章 海量视频资源 精美脑图 面试题

长按扫码可关注获取

欢迎关注640?wx\_fmt=png点个再看640?wx\_fmt=png

发表评论

表情:
评论列表 (有 0 条评论,439人围观)

还没有评论,来说两句吧...

相关阅读

    相关 String可变性

    什么是不可变类? > 这样理解: > 一个对象在创建完成后,不能去改变它的状态,不能改变它的成员变量(如果成员变量包含基本数据类型,那么这个基本数据类型的值不能改变;