Java字符串拼接的优雅方式
格式化:String.format(“我是%s小学的学生,我喜欢%s”,”阳光”,”太阳”);
MessageFormat.format(“hello,{0}. I am {1}.”, arg0, arg1)
数组拼接 :String.join(“_”, list)

背景

字符串拼接不管是在业务上,还是写算法时都会频繁使用到。对于Java来说,字符串拼接有着很多种方式,他们之间的区别是什么,对应不同的业务哪种更好用呢。

image.png

String底层原理

在讨论字符串拼接时,首先需要知道String的底层原理。

我们这里只讨论jdk1.8之后的情况,看下结构


      
  1. private final byte[] value;
  2. 复制代码

这一行代码已经可以说明很多东西。字符串实质就是不可变的byte数组。因为不可变,所以对他进行拼接对他拼接实际就是生成了多个对象,这就是不鼓励对字符串进行拼接的原因。但不可变也有很多好处,例如线程安全、可以存在字符串缓冲池复用字符串等。

拼接的方法

经典但有时不优雅的 +


      
  1. String a = "123";
  2. String b = "456";
  3. String c = a + b;
  4. 复制代码

c这个字符串就是ab拼接起来的字符串,“123456”

这段代码反编译出来的代码是


      
  1. String c = (new StringBuilder()).append(a).append(b).toString();
  2. 复制代码

可以看出这个 + 是Java的语法糖,他实际上是调用的StringBuilder,通过append()来进行拼接。关于StringBuilder我们后面再讲,先来讲下这个用法的优缺点。

优点

“+”,最大的优点就是简洁。如果两个字符串需要首尾拼接,+号义不容辞的成为了最好的使用方式。

缺点

说到缺点的话就多了。简洁也是他的最大缺点,也就是不够灵活

业务一

有一个字符串List,我需要把他们拼接起来,怎么办?


      
  1. for(String tmp:list){
  2. s += tmp;
  3. }
  4. 复制代码

简洁的一批,但是他隐藏着很大的问题!

image.png

上面说到这种拼接方式实际是通过StringBuilder的append的方法。你不需要知道他的原理,你只需要知道,每次循环,他都会new一个StringBuilder对象。创建对象的开销是很大的,如果List有几千几万,内存开销和时间开销是不能接受的!

所以阿里巴巴的规范说到:

img

表面上是推荐,实际就是禁止。写算法会消耗大量时间导致不通过,业务也会因为这种方式提高了无故的开销,属于领导看了想打死的代码。

业务二

大家好,我叫XX,我是来自XXX学校的大X学生,我的爱好是XXX。

一个经典的模板,我需要替换掉中间的XXX为controller的参数,怎么办呢?


      
  1. String s = "大家好,我叫"+name+"我是来自"+school+"学校的大"+num+“学生,我的爱好是”+aihao;
  2. 复制代码

属于可用但极其丑陋的代码。如果其他接口也需要这个模板,我还要把这段话复制到所有位置上吗?如果我要改动这个,我要对所有代码进行改动吗。

万能的StringBuilder

先介绍下StringBuilder的原理。把字符串拼接想象成数组就很好理解了,StringBuilder有点类似于ArrayList,可变数组。


      
  1.    /**
  2.     * The value is used for character storage.
  3.     */
  4.    char[] value;
  5. 复制代码

区别就是没有final修饰,当到达阈值时进行扩容操作。append方法就是往后插入。

那么就可以解决上面业务一的问题了。


      
  1. StringBuilder sb = new StringBuilder();
  2. for(String tmp:list){
  3. sb.append(tmp);
  4. }
  5. String s = sb.tostring();
  6. 复制代码

相比于上面,只创建了一个StringBuilder对象,减少循环创建的开销。

线程安全的StringBuffer

StringBuffer与StringBuilder相比,有线程安全的优势,通过上锁的方式。同时导致效率略低于StringBuilder。

灵活的String.format()

这个严格来说应该叫做格式化,但也可以用来拼接。

熟悉c语言的应该能够懂,我这里举一个例子


      
  1. String msg = String.format(“我是%s小学的学生,我爱吃%s”,"阳光","屎");
  2. //输出 我是阳光小学的学生,我爱吃屎
  3. 复制代码

使用字符串链代替%s,生成需要的字符串。也不仅可以拼接字符串,可以看下下图(偷的图,没全部验证过,错了别找我)

类型

这种方式就解决了业务二的问题。通过编写枚举或者常量字符串留出对应的位置,使用时再用String.format()拼接

有点绿色的concat

为什么说他绿色呢,就是我还没有找到他有什么优势。


      
  1. String s = "123".concat("456");
  2. //结果等价于
  3. String s = "123" + "456";
  4. 复制代码

concat方法的原理是数组扩容后复制之前的内容并写新的内容,和StringBuilder底层有点相像。

但是相比于“+”号来说,既不简便,又没有什么效率上的提高。在循环字符串拼接的条件,效率上会略有一点优势,但是这种情况是根本不被允许的,所以concat就很鸡肋。

JDK1.8优雅写法

刚才提到业务一的解决办法可以使用朴素的StringBuilder来解决,但是对于业务代码来说有一点冗长。

Jdk1.8给出了优雅的答案


      
  1. String s = String.join("_", list);
  2. 复制代码

一行代码,就可以把list里的字符串通过“_”拼接起来。

经典的Guava

guava是我们crud程序员的好伙伴,这里就不用多说了。我们最常接触到的其实就是guava的本地缓存和字符串操作。


      
  1. String result = Joiner.on(",").join(list);
  2. 复制代码

也是简洁的一句话,但是相比于jdk本土的字符串方法来说,他还有一些其他的特性。例如可以把为null的数组给跳过或者替换掉等等。功能要比jdk的要丰富一点。在正常的web项目里基本都会有Guava的依赖,使用起来还是很方便的。

总结

这篇文章偏重于代码编写方面,如何写出简洁高效的代码,是我们要追求的。不要让你写的垃圾代码恶心到接手的同事就好了。

image.png

作者:张小明dashing

链接:https://juejin.cn/post/6989518930884689927

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

https://blog.csdn.net/weixin_45839894/article/details/119274961

原文地址:http://www.cnblogs.com/sunny3158/p/16831789.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性