文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

放弃 StringBuilder!用Java8的StringJoiner

2024-12-03 00:22

关注

 在阅读项目代码时,突然看到了StringJoiner这个类的使用,感觉很有意思。

对实际开发中也有用,原理上是运用了StringBuilder的一个拼接字符串的封装处理。

为什么会新增这样一个string辅助类?

原有的stringbuilder太死板,不支持分割,如果想让最终的字符串以逗号隔开,需要这样写 

  1. StringBuilder sb = new StringBuilder();  
  2. IntStream.range(1,10).forEach(i-> 
  3.     sb.append(i+"");  
  4.     if( i < 10){  
  5.         sb.append(",")  
  6.     }  
  7. }); 

是不是太死板了,不好用,StringJoiner怎样写呢? 

  1. StringJoiner sj = new StringJoiner(",");  
  2. IntStream.range(1,10).forEach(i->sj.add(i+"")); 

有哪些平时用的还比较少的功能:

让我实现StringJoiner,我会怎么办呢?

jdk实现的源码分析

  1. private final String prefix;  
  2.     private final String delimiter;  
  3.     private final String suffix;  
  4.       
  5.     private StringBuilder value;  
  6.       
  7.     private String emptyValue; 

其实从成员变量的注释里就能看出他们的作用和需要注意的点了

  1. public StringJoiner(CharSequence delimiter,  
  2.                         CharSequence prefix,  
  3.                         CharSequence suffix) {  
  4.         Objects.requireNonNull(prefix, "The prefix must not be null");  
  5.         Objects.requireNonNull(delimiter, "The delimiter must not be null");  
  6.         Objects.requireNonNull(suffix, "The suffix must not be null");  
  7.         // make defensive copies of arguments  
  8.         this.prefix = prefix.toString();  
  9.         this.delimiter = delimiter.toString();  
  10.         this.suffix = suffix.toString();  
  11.         // !!!构造时就直接将emptyValue拼接好了。  
  12.         thisthis.emptyValue = this.prefix + this.suffix;  
  13.     } 

为什么要一开始就构造好呢?如果我想直接自定义emptyValue直接用构造函数初始化不是更方便吗?是因为绝大多数场景下都不会自定义emptyValue的场景吗?不对啊,感觉这个场景非常必要啊。。。

  1. public StringJoiner add(CharSequence newElement) {  
  2.         prepareBuilder().append(newElement);  
  3.         return this;  
  4.  
  5. private StringBuilder prepareBuilder() {  
  6.         // 从构造函数和类变量的声明可以看出,没有添加元素前stringbuilder是没有初始化的  
  7.         if (value != null) {  
  8.             // 已经有元素存在的情况下,添加元素前先将分隔符添加进去  
  9.             value.append(delimiter);  
  10.         } else {  
  11.             // 没有元素存在的情况下先把前缀加进去  
  12.             value = new StringBuilder().append(prefix);  
  13.         }  
  14.         return value;  

可以看出再添加元素的过程中就已经把前缀和分割字符什么的都处理好了,全部都在stringbuilde中了,唯一没有处理的就是后缀。 为什么?这样做tostring什么的时候真的超级方便的有木有。。。。。

  1. public String toString() {  
  2.     if (value == null) {  
  3.         // 这里如果没有自定义空值就是前缀+后缀咯。。 
  4.         return emptyValue;  
  5.     } else {  
  6.         // 为什么不直接value.toString()+suffix?????  
  7.         if (suffix.equals("")) {  
  8.             return value.toString();  
  9.         } else {  
  10.             int initialLength = value.length();  
  11.             String result = value.append(suffix).toString();  
  12.             // reset value to pre-append initialLength  
  13.             value.setLength(initialLength);  
  14.             return result;  
  15.         }  
  16.     }  

为什么不直接value.toString()+suffix?答案在merge方法

  1. public StringJoiner merge(StringJoiner other) {  
  2.         Objects.requireNonNull(other);  
  3.         if (other.value != null) {  
  4.             final int length = other.value.length();  
  5.             // 下面这段注释是说避免merge(this)时受影响,为什么?  
  6.             // lock the length so that we can seize the data to be appended  
  7.             // before initiate copying to avoid interference, especially when  
  8.             // merge 'this'  
  9.             StringBuilder builder = prepareBuilder();  
  10.             builder.append(other.value, other.prefix.length(), length);  
  11.         }  
  12.         return this;  
  13.     }  
  14. private StringBuilder prepareBuilder() {  
  15.         if (value != null) {  
  16.             value.append(delimiter);  
  17.         } else {  
  18.             value = new StringBuilder().append(prefix);  
  19.         }  
  20.         return value;  
  21.     } 

merge的思路是用当前的striingBuilder去append other的value(必须去掉前缀),源码注释中的merge 'this'问题是什么呢?prepareBuilder()的时候可能会先append(delimiter),如果other就是this,那么length其实就多了一个delimiter,此时append还是得以添加前的length为准。

merge的实现方式决定了toString时不能直接value.append(suffix).toString(),因为 builder.append(other.value, other.prefix.length(), length);这行代码,默认加上suffix后这里的merge的length得减去suffix的length(嗯,看来作者是想得多好多),而且merge时得把另外一个sj的内容append到当前这个sj的suffix之前(想想就麻烦多了~)

  1. public int length() {  
  2.         // Remember that we never actually append the suffix unless we return  
  3.         // the full (present) value or some sub-string or length of it, so that  
  4.         // we can add on more if we need to.  
  5.         return (value != null ? value.length() + suffix.length() :  
  6.             emptyValue.length());  
  7.     } 

没什么好说的,记住length不只是add的元素的length,还有前后缀。

总结

  1. public StringJoiner setEmptyValue(CharSequence emptyValue) {  
  2. // 注意这个Objects.requireNonNull方法是return的第一个参数。。。  
  3.         this.emptyValue = Objects.requireNonNull(emptyValue,  
  4.             "The empty value must not be null").toString();  
  5.         return this;  
  6.  

 

来源:Java编程内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯