【问题标题】:What's the most elegant way to concatenate a list of values with delimiter in Java?在 Java 中用分隔符连接值列表的最优雅方法是什么?
【发布时间】:2010-12-11 03:50:19
【问题描述】:

我从来没有找到一种简洁的方法来做以下事情。

假设我有一个字符串列表/数组。

abc
def
ghi
jkl

我想将它们连接成一个用逗号分隔的字符串,如下所示:

abc,def,ghi,jkl

在Java中,如果我写这样的东西(请原谅语法),

String[] list = new String[] {"abc","def","ghi","jkl"};
String str = null;
for (String s : list)
{
   str = str + s + "," ;
}

System.out.println(str);

我会得到

abc,def,ghi,jkl,  //Notice the comma in the end

所以我必须将上面的for循环重写如下

...
for (int i = 0; i < list.length; i++)
{
   str = str + list[i];
   if (i != list.length - 1)
   {
     str = str + ",";
   }
}
...

这可以在 Java 中以更优雅的方式完成吗?

我当然会使用 StringBuilder/Buffer 来提高效率,但我想说明这一点,但不会过于冗长。优雅,我的意思是避免丑陋的(?)if 在循环内检查的解决方案。

【问题讨论】:

标签: java string


【解决方案1】:

使用Guava's (formerly google-collections) joiner class:

Joiner.on(",").join(list)

完成。

【讨论】:

  • +1 用于谷歌收藏。是的,是的,我知道——“仅用于字符串连接的外部依赖项?!?!” ——但它可以使你的代码更短+更具表现力,如果你学习 API,它会在一个小时内收回成本。 :)
  • 一旦您查看了 api,您将使用 ist 进行的不仅仅是字符串连接。
  • 你说得对 - 如果外部 api 可以多次使用 - 这是最好的解决方案。
  • @Thorbjorn:请参阅 youtube.com/watch?v=ZeO_J2OcHYMyoutube.com/watch?v=9ni_KEkHfto 了解为什么应该使用 G-C 的深入解释。在 java 中使用几乎任何复杂的数据结构时,它都简化了很多样板。
  • 为什么这很酷:现在您想跳过空值?只需在“on”和“join”调用之间插入“.skipNulls()”。还是将 null 视为空字符串?很简单,这就是'.useForNull("")'。等等。
【解决方案2】:

这是我的版本:Java Tricks: Fastest Way to Collecting Objects in a String

StringBuilder buffer = new StringBuilder ();
String delim = "";
for (Object o: list)
{
    buffer.append (delim);
    delim = ", "; // Avoid if(); assignment is very fast!
    buffer.append (o);
}
buffer.toString ();

另外一个好处:如果循环中的代码更复杂,那么这种方法将产生正确的结果,而不需要复杂的if()s。

还要注意,对于现代 CPU,分配只会发生在缓存中(或者可能只发生在寄存器中)。

结论:虽然这段代码乍一看很奇怪,但它有很多优点。

【讨论】:

  • 它不是很漂亮 - 每次迭代都初始化 delim。
  • 如果您的博文被删除,请提供您的解决方案。
  • @Gonzo:if() 比分配慢。分配只是一个指针操作,它总是发生在相同的地址上,所以 CPU 可能会使用寄存器并将所有内容保存在缓存中。此外,代码紧凑,设置不变(无需在循环之外做部分工作),循环中的代码始终相同。
  • @Aaron:我同意它更紧凑。更快,没有。即使您在直接汇编中编写,也不会有所作为。此外,智能编译器无论如何都会展开和优化它。
  • ...但是要说干净的代码:在循环之后使用builder.setLength(builder.length() - 1); 可能是最干净的(并且不需要像deleteCharAt(int) 那样的System.arraycopy(..)
【解决方案3】:
StringBuilder builder = new StringBuilder();
for (String st: list) {
    builder.append(st).append(',');
}
builder.deleteCharAt(builder.length());
String result = builder.toString();

不要使用 '+' 表示字符串连接。速度很慢。

【讨论】:

    【解决方案4】:

    看这里:

    http://snippets.dzone.com/posts/show/91

    关于这个话题的完整讨论。

    【讨论】:

    • 感谢您的链接。我正在寻找一种更优雅的方法(可能涉及更少的代码行)。就我而言,性能并不是一个主要问题。
    • 我不喜欢你可以在外面做的检查
    【解决方案5】:

    我敢打赌,在任何中型 Java 项目的类路径中,都有几个名为“StringUtil”、“StringsUtil”、“Strings”的类或任何类似的类。最有可能的是,它们中的任何一个都将提供连接功能。以下是我在项目中找到的一些示例:

    org.apache.commons.lang.StringUtils.join(...)
    org.apache.wicket.util.string.Wicket.join(...)
    org.compass.core.util.StringUtils.arrayToDelimitedString(...)
    

    由于您将来可能希望摆脱一些外部依赖项,您可能希望这样做:

    public static final MyStringUtils {
        private MyStringUtils() {}
    
        public static String join(Object[] list, String delim) {
            return org.apache.commons.lang.StringUtils.join(list, delim);
        }
    }
    

    现在这就是我所说的“优雅”;)

    【讨论】:

    • 为什么要创建一个新类来包装对 org.apache.commons.lang.StringUtils.join 的调用?这如何消除外部依赖关系?
    • @DerekSpringer 它不会删除外部依赖项。将依赖项隐藏在 MyStringUtils 之类的东西中只会更容易更改实现。因此,可以通过仅更改 MyStringUtils 类来移除外部依赖。
    【解决方案6】:

    检查这是否有用:

    List<Integer> numbers=new ArrayList<Integer>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        numbers.add(6);
        String str = " ";
        for(Integer s:numbers){
        str=str+s+" , ";
        }
        System.out.println(str.substring(0,str.length()-2));
    

    【讨论】:

      【解决方案7】:

      我会使用StringBuffer 来实现此功能。 String 是不可变的,因此每次连接两个 Strings 时,都会创建一个新对象。

      更高效的是使用StringBuffer

      String[] list = new String[] {"abc","def","ghi","jkl"};
      StringBuffer str = new StringBuffer();
      for (String s : list) {
         str.append(s);
         str.append(",");
      }
      str.deleteCharAt(str.length());
      System.out.println(str); //automatically invokes StringBuffer.toString();
      

      【讨论】:

      • 你不应该在不必要的地方使用 StringBuffer,它是线程安全且缓慢的,我会改用 StringBuilder。您还必须删除最后一个逗号
      【解决方案8】:
      for (int i = 0; i < list.length-1; i++) {
          str = str + list[i];
          str = str + ",";    
      }
      str = str + list[list.length-1] 
      

      【讨论】:

      • 使用字符串连接不是很快。我认为这段代码也很难阅读
      • 我知道字符串连接速度很快,这不是重点,是的,它的可读性较差,只是指出了其他选项来执行 OP 要求的操作
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-14
      • 1970-01-01
      • 2011-04-01
      • 1970-01-01
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多