1

我有一个在循环中构建字符串的程序,我的程序太慢了。现在运行大约需要 600 毫秒Oblig1Test.oppgave7。可以做些什么来加快它的速度?

Oblig1.toString

public static String toString(int[] a, char v, char h, String mellomrom)
{
    String s ="";

    s += v;

    if(a.length != 0)
    {
        for(int i = 0; i < a.length-1; i++)
        {
                s += a[i] + mellomrom; 
        }

        s += a[a.length-1];
    }

    s += h;

    return s;
}

义务1测试:

public static int oppgave7()
{
   int[] b = new int[20000];
   long tid = System.currentTimeMillis();
   Oblig1.toString(b,' ',' '," ");
   tid = System.currentTimeMillis() - tid;

  if (tid > 40)
  {
    System.out.println("Oppgave 7: Metoden "
      + "er for ineffektiv. Må forbedres!");
  }
}

public static void main(String[] args) throws IOException
{
   oppgave7();
}
4

4 回答 4

8

当您的代码中的缓慢操作是许多字符串的连接时,您可能会通过使用StringBuilder获得很多。

通过将您的toString方法更改为

public static String toString(int[] a, char v, char h, String mellomrom){
    StringBuilder sb = new StringBuilder();
    sb.append(v);
    if(a.length != 0){
        for(int i = 0; i < a.length-1; i++){
                sb.append(a[i]).append(mellomrom); 
        }
        sb.append(a[a.length-1]);
    }
    sb.append(h);
    return sb.toString();
}

我能够在我的计算机上从 493 毫秒到 22 毫秒。

于 2013-09-04T13:33:16.977 回答
3

使用StringBuilder

public static String toString(int[] a, char v, char h, String mellomrom) {
    StringBuilder sb = new StringBuilder();
    sb.append(v);
    for(int i = 0 ; i < a.length - 1 ; ++i) {
        sb.append(a[i]).append(mellomrom);
    }
    if(a.length != 0) {
        sb.append(a[a.length-1]);
    }
    sb.append(h);
    return sb.toString();
}
于 2013-09-04T13:36:05.040 回答
2

首先,变量的单字符名称?坏小子!:) 给事物起有意义的名字,它不需要任何成本。

其次,Java 中的字符串是不可变的。声明

String concatedString = concatedString + secondString

并不意味着“将 secondString 的值附加到 concatedString”,它的意思是“创建一个新字符串,即 concatedString 和 secondString 的值,丢弃 concatedString 并使 concatedString 引用引用新字符串”。换句话说,每次您使用 + 连接字符串时,您都在隐式创建一个新的 String 对象。

在循环中创建对象非常昂贵。

Java 提供了一组可变字符串,例如 StringBuilder 和 StringBuffer(后者是线程安全的,但性能较差)。请改用其中之一。

于 2013-09-04T13:37:12.310 回答
1

是的,这是一个常见的问题。

Java中的字符串是不可变的,这意味着一旦String构造了一个对象,就不能以任何方式对其进行修改,并且所有对它的操作都是通过复制内容来完成的。

在您的特定情况下,当您执行s += vor时s += a[i] + mellomrom,它实际上将字符串的内容复制s到一个 new StringBuilder,连接各个部分,然后从中生成String一个StringBuilder。所以,

s += v

变成

s = new StringBuilder(s).append(v).toString();

s += a[i] + mellomrom

变成

s = new StringBuilder(s).append(a[i]).append(mellomrom).toString();

这在循环中完成时会造成重大的性能灾难(构造两个新对象,复制内容两次)。要在循环中构造一个字符串,请使用您自己的StringBuilder实例,因此您只有一个实例,并且您不必String在每次迭代时将其转换为 a:

public static String toString(int[] a, char v, char h, String mellomrom)
{
    StringBuilder sb = new StringBuilder();
    sb.append(v);

    if(a.length != 0)
    {
        for(int i = 0; i < a.length-1; i++)
        {
            sb.append(a[i]).append(mellomrom);
        }
        sb.append(a[a.length-1]);
    }
    sb.append(h);
    return sb.toString();
}
于 2013-09-04T13:39:22.617 回答