优化此ArrayList连接方法

时间:2010-03-05 19:37:32

标签: java

我已编写此代码以连接ArrayList元素: 它可以更优化吗?或者有更好的不同方式吗?

public static String join(ArrayList list, char delim) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < list.size(); i++) {
            if (i != 0)
                buf.append(delim);
            buf.append((String) list.get(i));
        }
        return buf.toString();
    }

9 个答案:

答案 0 :(得分:2)

StringBuffer是为了线程安全而同步的,而是使用StringBuilder。

不要在循环的每次迭代中调用list.size()。将其设置为变量或使用迭代器。

另请注意,有很多库可以执行此操作,主要是google collections。请尝试以下方法:

public String join(List<?> list, char delimiter) {
    StringBuilder result = new StringBuilder();
    for (Iterator<?> i = list.iterator(); i.hasNext();) {
        result.append(i.next());
        if (i.hasNext()) {
            result.append(delimiter);
        }
    }
    return result.toString();
}

答案 1 :(得分:2)

为什么你需要一种方法?为什么不直接使用toString()方法?

public static String join(List<String> list) 
{ 
    return list.toString(); // comma delimiter with some extra stuff at start and end
} 

你可以比你写的方法做得更好。添加List接口和泛型;也许甚至收藏。它更通用,更安全;不需要演员表。

运行此类:

import java.util.Arrays;
import java.util.List;

public class ListToStringDemo
{
    public static void main(String[] args)
    {
        List<String> values = Arrays.asList(args);
        System.out.println(values);
    }
}

在命令行中使用任何字符串参数(例如,“foo bar baz bat”)并获得此输出:

C:\JDKs\jdk1.6.0_13\bin\java  ListToStringDemo foo bar baz bat
[foo, bar, baz, bat]

Process finished with exit code 0

答案 2 :(得分:2)

Here是着名的java.util.Collection团队正在做的事情,所以我认为这应该是相当不错的;)

  421       /* Returns a string representation of this collection.  The string
  422        * representation consists of a list of the collection's elements in the
  423        * order they are returned by its iterator, enclosed in square brackets
  424        * (<tt>"[]"</tt>).  Adjacent elements are separated by the characters
  425        * <tt>", "</tt> (comma and space).  Elements are converted to strings as
  426        * by {@link String#valueOf(Object)}.
  427        *
  428        * @return a string representation of this collection
  429        */
  430       public String toString() {
  431           Iterator<E> i = iterator();
  432           if (! i.hasNext())
  433               return "[]";
  434   
  435           StringBuilder sb = new StringBuilder();
  436           sb.append('[');
  437           for (;;) {
  438               E e = i.next();
  439               sb.append(e == this ? "(this Collection)" : e);
  440               if (! i.hasNext())
  441                   return sb.append(']').toString();
  442               sb.append(", ");
  443           }

另外,这就是你如何用duffymo的答案得到逗号分隔符;)

答案 3 :(得分:1)

这是否已知肯定会导致某些性能问题,或者您是否正在将此作为练习?如果没有,我不会打扰。

假设这可能会更快,但我对此表示怀疑:

StringBuffer buf = new StringBuffer();
for (int i = 0; i < list.size() - 1; i++) {
    buf.append((String) list.get(i));
    buf.append(delim);
}
buf.append((String) list.get(i));
return buf.toString();

答案 4 :(得分:1)

我的第一个想法是,Google CollectionJoiner课程将是一个有用的起点。具体来说,是public final String join(Iterable<?> parts)方法。

答案 5 :(得分:1)

#1

每次循环迭代时,你都在检查列表的大小:

for (int i = 0; i < list.size(); i++) {

由于您没有改变列表,您只需要执行一次:

for (int i = 0, j = list.size(); i < j; i++) {

#2

不是在每次迭代中检查i != 0,而是在每次迭代后附加一个分隔符:

    for (int i = 0; i < list.size(); i++) {
        buf.append((String) list.get(i));
        buf.append(delim);
    }

    // Here, convert all but the last character in the buffer to a string.

答案 6 :(得分:0)

更好,也许:

  

列出而不是ArrayList

接口程序而非实现

  

for(String string:strings)而不是for(int i ...)

根据Josh,来自1.5的foreach循环实际上更有效率,并且更容易理解

其他人已经注意到

答案 7 :(得分:0)

我怀疑它可能会显着优化(意味着变得更快)而不会变得神秘。但是,使用泛型可以改进

public static String join(List<String> list, char delim) {
   StringBuffer buf = new StringBuffer(512);
   first = true;
   for (String item : list) {
      if (first) {
         first = false;
      } else {
         buf.append(delim);
      }
      buf.append(item);
   }
}

此版本的改进:您强制要求项目仅包含编译器级别的字符串,您不必维护循环变量,并且您不需要ArrayList,这是API的实现细节不应强制执行。

答案 8 :(得分:0)

除了您收到的答案外,您还可以预先初始化StringBuilderStringBuffer的容量。这减少了内部数组在扩展时必须重新复制的次数。由于您不知道所需的确切容量,因此您可以根据元素数量估算每个元素的平均大小和倍数。

private static final int ESTIMATE_ELEM_SIZE = 8;

public static String join(Collection col, char delim)
{
    int len = col.size();
    if (len == 0)
        return "";
    StringBuilder buf = new StringBuilder(ESTIMATE_ELEM_SIZE * len);
    for (Object elem : col)
    {
        buf.append(elem).append(delim);
    }
    return buf.substring(0, buf.length() - 1);
}

这显示了其他人分享的一些技巧:使用StringBuilder,不要在循环中检查if,并使用foreach增强循环。

我还建议将第一个参数更改为有意义的最通用类型,以便它更具可重用性。在这种情况下,由于您确实不需要索引来处理每个元素,因此可以指定Collection

请注意,也不需要转发String,因为StringBuilder.append()会在必要时将元素转换为String。这允许您将其用于包含除字符串以外的其他类型对象的集合。