Java——StringJoiner 痛定思痛。 2023-06-13 09:24 23阅读 0赞 ### 简介 ### public final class StringJoiner extends Object StringJoiner是java.util包中的一个类,用于构造一个由分隔符分隔的字符序列(可选),并且可以从提供的前缀开始并以提供的后缀结尾。虽然这也可以在StringBuilder类的帮助下在每个字符串之后附加分隔符,但StringJoiner提供了简单的方法来实现,而无需编写大量代码。 `StringJoiner`用于构造由分隔符分隔的字符序列,并且可选地从提供的前缀开始并以提供的后缀结尾。在此之前添加一些东西到`StringJoiner` ,其`sj.toString()`方法,默认情况下,返回`prefix + suffix` 。 但是,如果调用了`setEmptyValue`方法,则将返回提供的`emptyValue` 。 这可用于,例如,使用一组表示法来表示空集,即创建字符串时`"{}"` ,其中`prefix`是`"{"`时, `suffix`是`"}"`和什么已被添加到`StringJoiner` 。 注意:StringJoiner其实是通过StringBuilder实现的,所以它的性能和StringBuilder差不多,它也是非线程安全的。 **字符串`"[George:Sally:Fred]"`可以构造如下:** StringJoiner sj = new StringJoiner(":", "[", "]"); sj.add("George").add("Sally").add("Fred"); String desiredString = sj.toString(); ### **日常开发中需要进行字符串拼接,如何选择** ### 1. 如果只是简单的字符串拼接,考虑直接使用"+"即可。 2. 如果是在for循环中进行字符串拼接,考虑使用StringBuilder和StringBuffer。 3. 如果是通过一个集合(如List)进行字符串拼接,则考虑使用StringJoiner。 4. 如果是对一组数据进行拼接,则可以考虑将其转换成Stream,并使用StringJoiner处理。 ### 构造方法 ### <table> <tbody> <tr> <th>构造方法和描述</th> </tr> <tr> <td><code><a rel="nofollow">StringJoiner</a>(<a rel="nofollow">CharSequence</a> delimiter)</code> <p>构造一个 <code>StringJoiner</code>与其中不带字符,没有 <code>prefix</code>或 <code>suffix</code> ,以及所提供的副本 <code>delimiter</code> 。</p> </td> </tr> <tr> <td><code><a rel="nofollow">StringJoiner</a>(<a rel="nofollow">CharSequence</a> delimiter, <a rel="nofollow">CharSequence</a> prefix, <a rel="nofollow">CharSequence</a> suffix)</code> <p>构造一个 <code>StringJoiner</code>使用的供给拷贝在不带字符 <code>prefix</code> , <code>delimiter</code>和 <code>suffix</code> 。</p> </td> </tr> </tbody> </table> 注意: 1. 当我们使用StringJoiner(CharSequence delimiter)初始化一个StringJoiner的时候,**这个delimiter其实是分隔符,并不是可变字符串的初始值。** 2. StringJoiner(CharSequence delimiter,CharSequence prefix,CharSequence suffix)的第二个和第三个参数分别是拼接后的字符串的前缀和后缀。 ### 提供的方法 ### 最常用的方法就是add方法和toString方法,类似于StringBuilder中的append方法和toString方法。 <table> <tbody> <tr> <th>修饰和类型</th> <th>方法和描述</th> </tr> <tr> <td><code><a rel="nofollow">StringJoiner</a></code></td> <td><code><a rel="nofollow">add</a>(<a rel="nofollow">CharSequence</a> newElement)</code> <p>将给定的副本 <code>CharSequence</code>值作为下一个元素 <code>StringJoiner</code>值。</p> </td> </tr> <tr> <td><code>int</code></td> <td><code><a rel="nofollow">length</a>()</code> <p>返回此 <code>StringJoiner</code>的 <code>String</code>表示的长度。</p> </td> </tr> <tr> <td><code><a rel="nofollow">StringJoiner</a></code></td> <td><code><a rel="nofollow">merge</a>(<a rel="nofollow">StringJoiner</a> other)</code> <p>添加给定的 <code>StringJoiner</code>的内容,没有前缀和后缀作为下一个元素,如果它是非空的。</p> </td> </tr> <tr> <td><code><a rel="nofollow">StringJoiner</a></code></td> <td><code><a rel="nofollow">setEmptyValue</a>(<a rel="nofollow">CharSequence</a> emptyValue)</code> <p>设置序列的字符时要使用确定的字符串表示的这个 <code>StringJoiner</code> ,而没有单元已被添加然而,就是当它是空的。</p> </td> </tr> <tr> <td><code><a rel="nofollow">String</a></code></td> <td><code><a rel="nofollow">toString</a>()</code> <p>返回当前值,由的 <code>prefix</code> ,值添加由迄今分离 <code>delimiter</code>和 <code>suffix</code> ,除非没有元素已经在这种情况下,被添加 <code>prefix + suffix</code>或 <code>emptyValue</code>被返回的字符</p> </td> </tr> </tbody> </table> ### **原理** ### 主要看一下add方法: public StringJoiner add(CharSequence newElement) { prepareBuilder().append(newElement); return this; } private StringBuilder prepareBuilder() { if (value != null) { value.append(delimiter); } else { value = new StringBuilder().append(prefix); } return value; } 可以得知StringJoiner其实就是依赖StringBuilder实现的,StringJoiner性能损耗应该和直接使用StringBuilder差不多**。** 在Java doc中有这样一句话: > A StringJoiner may be employed to create formatted output from a Stream using Collectors.joining(CharSequence) 如果有这样一个List: List<String> list = ImmutableList.of("Hollis","hollischuang","Java干货"); 如果想要把他拼接成一个以下形式的字符串: Hollis,hollischuang,Java干货 可以通过以下方式: StringBuilder builder = new StringBuilder(); if (!list.isEmpty()) { builder.append(list.get(0)); for (int i = 1, n = list.size(); i < n; i++) { builder.append(",").append(list.get(i)); } } builder.toString(); 还可以使用: list.stream().reduce(new StringBuilder(), (sb, s) -> sb.append(s).append(','), StringBuilder::append).toString(); 但是输出结果稍有些不同,需要进行二次处理: Hollis,hollischuang,Java干货, 还可以使用"+"进行拼接: list.stream().reduce((a,b)->a + "," + b).toString(); 以上几种方式,要么是代码复杂,要么是性能不高,或者无法直接得到想要的结果。为了满足类似这样的需求,Java 8中提供的StringJoiner就派上用场了。以上需求只需要一行代码: list.stream().collect(Collectors.joining(":")) 即可。上面用的表达式中,Collector.joining的源代码如下: public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix) { return new CollectorImpl<>( () -> new StringJoiner(delimiter, prefix, suffix), StringJoiner::add, StringJoiner::merge, StringJoiner::toString, CH_NOID); } Collector.joining的实现原理就是借助了StringJoiner,或许在Collector中直接使用StringBuilder似乎也可以实现类似的功能,只不过稍微麻烦一些;所以Java 8提供StringJoiner丰富Stream的用法,而且StringJoiner可以方便的增加前缀和后缀,比如希望得到的字符串是"\[Hollis,hollischuang,Java干货\]"而不是"Hollis,hollischuang,Java干货"的话,StringJoiner的优势就更加明显了。
还没有评论,来说两句吧...