【问题标题】:Java - How to join many list values into a single string with delimiter at end of each valueJava - 如何将多个列表值连接到单个字符串中,每个值的末尾都有分隔符
【发布时间】:2020-01-15 15:26:30
【问题描述】:

如何通过在每行末尾附加 '\n' 将数百万个值的列表加入单个字符串 -

输入数据在列表中:

   list[0] = And the good south wind still blew behind,
   list[1] =  But no sweet bird did follow,
   list[2] =  Nor any day for food or play
   list[3] =  Came to the mariners' hollo!

下面的代码通过在末尾附加换行符将列表连接成一个字符串 -

String joinedStr = list.collect(Collectors.joining("\n", "{", "}"));    

但是,问题是如果列表包含数百万个数据,则加入失败。我的猜测是 String 对象由于尺寸大而无法处理数百万行。

请提出建议。

【问题讨论】:

  • 您遇到什么错误或异常?如果与垃圾收集器有关,请尝试为 VM 提供更多内存。
  • 不是字符串,是你的内存不够。数百万个字符串需要大量空间

标签: java join java-8 java-stream


【解决方案1】:

尝试编写一个巨大的字符串的问题在于,您必须先将整个内容保存在内存中,然后再对其进行进一步处理。

如果字符串太大而无法放入内存,则只有两种选择:

  1. 增加可用内存,或
  2. 首先避免在内存中保留一个巨大的字符串

这个字符串可能注定要进行一些进一步的处理 - 可能它正在被写入数据库中的 blob,或者它可能是 HTTP 响应的主体。它不是为了好玩而建造的。

可能更可取的是写入某种流(可能是OutputStream 的实现),一次可以读取一个字符。如果消费者知道您发送的内容的上下文,他们可以选择基于分隔符进行缓冲,或者他们可以等到他们拥有整个内容。

您最好使用支持back pressure 的东西,这样如果消费者速度太慢,您可以暂停写入。

具体的外观将取决于您要完成的任务。

【讨论】:

    【解决方案2】:

    也许您可以使用专门为处理大型字符串而设计的 StringBuilder 来实现。这是我的做法:

    StringBuilder sb = new StringBuilder();
    for (String s : list) sb.append(s).append("\n");
    
    return s.toString();
    

    虽然没有测试过这段代码,但它应该可以工作

    【讨论】:

    • 上面的代码有效,因为它有一个返回语句,而不是将其存储在字符串变量中。如果不是返回,## String var = s.toString(); ##它不起作用。 JVM 内存大小超出。
    • 这与 joining 收集器在内部所做的没有什么不同。
    • @ShakthiRaj String 对象所需的内存不会改变,无论您是返回引用还是将其存储到局部变量中。
    • 那么,字符串内存大小是否取决于jvm堆内存?如果是这种情况,java处理是否依赖于jvm内存。因为我正在尝试为数百万行执行此过程。有没有其他方法可以在不更改内存的情况下实现这一点,即使它意味着处理至少十万行
    • @ShakthiRaj 我不明白你在问什么。当然,要在内存中保存一个大字符串,您需要有足够的内存。如果这个例子碰巧在一个测试中工作,但在一个细微的、不相关的改变之后失败了,这意味着字符串可能勉强适合内存,但是由于你想做的不仅仅是在内存中拥有一个字符串,所以没有增加更多内存的方法。
    猜你喜欢
    • 2016-07-20
    • 1970-01-01
    • 1970-01-01
    • 2019-01-09
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    相关资源
    最近更新 更多