登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

Java StringJoiner merge 为什么不保留对方前后缀

来源:17golang原创

时间:2026-11-08 01:51:04 391浏览 收藏

StringJoiner.merge 不会把来源对象的 prefix 和 suffix 再套到目标对象上。它读取来源 joiner 的内部元素内容,把这段内容作为目标 joiner 的一个新元素追加;如果来源使用了不同的分隔符,来源内部元素会先按自己的分隔符拼成一个整体。

官方文档:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/StringJoiner.html

merge(other) 合并的是来源对象去掉前后缀后的内容,而不是完整的 other.toString()。因此目标 joiner 的前后缀仍由目标对象负责,来源的格式外壳不会重复出现。
  • 目标对象保留自己的 prefix、suffix 和 delimiter。
  • 来源对象只贡献内部元素;来源的 prefix、suffix 不参与合并。
  • 来源分隔符与目标不同时,来源内部文本会作为目标的一个整体元素追加。
  • 来源为空时,merge 对目标没有效果;本文只讨论非空来源的格式边界。

merge 实际追加了什么内容

可以把 StringJoiner 看成“内部元素集合 + 自己的渲染格式”。调用 toString() 时,当前对象才会把自己的前缀、分隔符和后缀拼到内部元素周围。merge 不会把来源的完整字符串结果拿来再次包裹,而是取来源的内部内容作为一个元素放进目标对象。

例如,目标 joiner 的格式是方括号,来源 joiner 的格式是圆括号。来源最终显示为 (C;D),但合并时目标得到的不是完整格式复制;来源的圆括号属于来源的展示边界,不会成为目标的外层边界。

Java StringJoiner merge 中目标前后缀与来源内部内容边界的静态结构说明图
图1:说明图把目标 StringJoiner 的格式边界与来源 joiner 的内部内容分开表示;这是静态结构图,不是运行截图。

用最小代码重现前后缀边界

下面的示例让目标和来源使用不同的前后缀,然后调用一次 merge。目标外层符号来自目标对象,来源内部的 C;D 被作为一个整体元素放入目标。

import java.util.StringJoiner;

public class StringJoinerMergeDemo {
    public static void main(String[] args) {
        StringJoiner target = new StringJoiner("|", "[", "]");
        target.add("A").add("B");

        StringJoiner source = new StringJoiner(";", "(", ")");
        source.add("C").add("D");

        // merge 只吸收 source 的内部内容,不复制 source 的前缀和后缀。
        target.merge(source);

        // 目标对象负责最终的方括号,来源对象负责内部的分号分隔。
        System.out.println(target);
    }
}

这里的关键不是把两个字符串直接相加,而是两个 joiner 的职责不同:source 先把自己的元素组织成内部片段,target 再把这个片段当成一个元素参与自己的渲染。

[A|B|C;D]

这也解释了“为什么不保留对方前后缀”:前后缀不是来源元素本身,而是来源对象输出时使用的展示边界;merge 的契约明确排除了这两个边界。

分隔符不同,为什么来源会变成一个整体元素

如果目标使用 |,来源使用 ;,两者不能简单地把来源的每个元素拆开后改用目标分隔符。官方契约选择把来源的内部元素按来源分隔符连接成一段,再把这段作为目标的单个元素追加。这样来源内部的组织方式不会被目标分隔符重新解释。

因此,下面两种想法的结果不同:

  • target.merge(source):把来源内部的 C;D 作为一个元素追加,目标结果类似 [A|B|C;D]。
  • 逐个调用 target.add:把 C、D 分别交给目标,目标分隔符会参与每个元素之间的连接,结果会类似 [A|B|C|D]。

如果业务要求保留来源的整体格式,merge 适合表达层级组合;如果业务要求把来源元素拆平到目标分隔符下,就应明确遍历来源数据并逐个 add,不要把 merge 当成扁平化操作。

Java StringJoiner 不同分隔符下来源内部内容作为单个元素合并的静态结构说明图
图2:说明图展示目标分隔符、来源分隔符和合并后单元素之间的边界;这是解释图,不是性能或运行结果。

排查 merge 结果不符合预期时,先看这三个判断

第一,看调用方向。target.merge(source) 修改的是目标对象,目标的前后缀决定最终外层显示;把调用方向写反,结果的外层格式也会跟着改变。

第二,看你要的是“组合”还是“摊平”。merge 把来源内部内容作为一个元素加入目标,适合保留来源内部的分隔关系;若想让每个来源元素都使用目标分隔符,需要从原始元素集合重新添加。

第三,不要拿 source.toString() 的完整结果去推断 merge 的输入。来源的 prefix 和 suffix 只在来源自己转换成字符串时参与输出,不能据此认为它们会作为普通元素进入目标。

import java.util.StringJoiner;

public class StringJoinerFlattenDemo {
    public static void main(String[] args) {
        StringJoiner target = new StringJoiner("|", "[", "]");
        // 需要扁平化时,显式把每个业务元素交给目标 joiner。
        target.add("A").add("B");
        target.add("C").add("D");

        // 逐个 add 会让目标分隔符作用于 C 和 D。
        System.out.println(target);
    }
}

这个例子没有调用 merge,因为目标是扁平化而不是组合。选择 API 前先写清楚“来源是一整个元素,还是一组要重新分隔的元素”,通常就能避免前后缀和分隔符的误解。

一张表记住 StringJoiner.merge 的归属

对象/属性merge 后的作用排查结论
目标 prefix保留并包住最终结果最终外层前缀看目标对象
目标 suffix保留并包住最终结果最终外层后缀看目标对象
来源 prefix/suffix不作为元素进入目标不会因为 merge 重复包裹
来源内部元素按来源分隔符组成一个整体元素不同分隔符时不会被目标重新拆分
空来源对目标没有效果先确认来源是否真正添加过元素

常见问题

merge 是不是等价于 target.add(source.toString())?

不是。这样写会把来源的前缀和后缀也当成普通文本加入目标;merge 的契约明确使用来源去掉前后缀后的内部内容。

怎样让来源的每个元素都使用目标分隔符?

不要依赖 merge 做拆平。保留原始元素集合,遍历后逐个调用目标的 add;这样目标分隔符才会作用于每一项。

为什么来源的圆括号没有出现在结果里?

因为圆括号是来源 joiner 的展示边界,不是来源内部元素。merge 只把来源内容作为一个元素追加,最终外层格式由目标对象决定。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>