当前位置: 首页 > 科技观察

抛弃StringBuilder!在看Java8的StringJoiner

时间:2023-03-15 23:45:05 科技观察

的项目代码时,突然看到了StringJoiner类的使用,感觉很有意思。在实际开发中也很有用。原理上是利用了StringBuilder对拼接字符串的封装。为什么要增加这样一个字符串辅助类呢?原来的stringbuilder太死板了,不支持切分。如果你想用逗号分隔最后的字符串,你需要这样写StringBuildersb=newStringBuilder();IntStream.range(1,10).forEach(i->{sb.append(i+"");if(i<10){sb.append(",")}});是不是太死板了不好用,StringJoiner怎么写?StringJoinersj=newStringJoiner(",");IntStream.range(1,10).forEach(i->sj.add(i+""));平时用的比较少的函数有哪些:setEmptyValue,默认emptyValue是一个前缀加一个后缀,用户可以自定义emptyValuemerge(StringJoinerother),合并另一个joiner长度,当前长度,如果为空,看长度emptyValue并让我实现StringJoiner,我该怎么办?维护一个List,在toString的最后join。优点:实现起来很方便缺点:list太浪费空间(展开是根据系数展开)在StringBuilder的基础上改造(jdk实现方法是源码分析成员变量privatefinalStringprefix;privatefinalStringdelimiter;privatefinalStringsuffix;/**StringBuildervalue--atanytime,thecharactersconstructedfromthe*prefix,theaddedelementseparatedbythedelimiter,butwithoutthe*suffix,sothatwecanmoreeasilyaddelementswithouthavingtojigger*thesuffixeachtime.*/privateStringBuildervalue;/**Bydefault,thestringconsistingofprefix+suffix,returnedby*toString(),orpropertiesofvalue,whennoelementshaveyetbeenadded,*i.e.whenitisempty.Thismaybeoverriddenbytheusertobesome*othervalueincludingtheemptyString.*/privateStringemptyValue;其实从成员变量的注释中就可以看出它们的作用和需要注意的地方。后缀必须otbenull");//对参数进行防御性复制this.prefix=prefix.toString();this.delimiter=delimiter.toString();this.suffix=suffix.toString();//!!!直接构造空值thisthis.emptyValue=this。prefix+this.suffix;}为什么要在最开始构造呢?如果我想直接自定义emptyValue,直接用构造函数初始化不是更方便吗?因为在大多数场景下,它不会自动定义emptyValue的场景?不,我觉得这个场景很有必要...添加元素publicStringJoineradd(CharSequencenewElement){prepareBuilder().append(newElement);returnthis;}privateStringBuilderprepareBuilder(){//从构造函数和类变量中可以从添加元素之前没有初始化stringbuilder的语句可以看出if(value!=null){//如果已经有元素,则在添加元素之前添加分隔符value.append(delimiter);}else{//如果没有元素,先添加前缀value=newStringBuilder().append(prefix);}returnvalue;}可以看出在添加元素的过程中已经处理了前缀和拆分字符是的,一切都在stringbuilde中,唯一没有处理的是后缀.为什么?做tostring之类的时候真的超级方便...关键toStringpublicStringtoString(){if(value==null){//这里如果没有自定义空值就是前缀+后缀。.returnemptyValue;}else{//为什么不直接value.toString()+suffix????if(suffix.equals("")){returnvalue.toString();}else{intinitialLength=value.length();Stringresult=value.append(suffix).toString();//resetvaluetoppre-appendinitialLengthvalue.setLength(initialLength);returnresult;}}}为什么不直接value.toString()+suffix呢?答案在合并方法中)受影响,为什么?//lockthelengthsothatwecanseizethedatatobeappended//beforeinitiatecopyingtoavoidinterference,especiallywhen//merge'this'StringBuilderbuilder=prepareBuilder();builder.append(other.value,other.prefix.length(),length);}returnthis;}privateStringBuilderprepareBuilder(){if(value!=null){value.append(delimiter);}else{value=newStringBuilder().append(prefix);}returnvalue;}merge的思路是利用当前的stringingBuilder追加other的value(prefix必须被删除),源代码在评论中合并'this'有什么问题?当prepareBuilder()可能是先append(delimiter),如果other是这个,那么length其实多了一个delimiter,这时候append还是可以以add之前的length为准。merge的实现决定了toString不能直接value.append(suffix).toString(),因为builder.append(other.value,other.prefix.length(),length);这行代码,默认加suffix后,这里merge的长度要减去suffix的长度(嗯,看来作者想多了),而且merge的时候还要追加另外一个sj的内容当前sj的后缀前(想想就更麻烦了~))+suffix.length():emptyValue.length());}没什么好说的,记住length不仅仅是add元素的长度,还有prefix和suffix。总结基于StringBuilder的实现,添加时添加前缀和分隔符,从不添加后缀。它仅在调用toString和length时添加到计算中。由此带来的合并操作的极大便利!!!!!学习了,确实不错emptyValue是不是一定要在构造的时候生成?如果用户想拥有自己的默认值,是否需要在注入之前构造一个实例?...这还是有点奇怪。Objects是一种工具方法,它本身返回验证值,这很好。publicStringJoinersetEmptyValue(CharSequenceemptyValue){//注意Objects.requireNonNull方法是return的第一个参数。..this.emptyValue=Objects.requireNonNull(emptyValue,"Theemptyvaluemustnotbenull").toString();returnthis;}