Почему это производительность разница

import java.util.Calendar;

public class MainClass
{
  public static void main(String args[])
  {
    String s = new String("ABCD");

    long swapStart = Calendar.getInstance().getTimeInMillis();
    for(int i=0; i<s.length()/2;i++)
    {
        char left = s.charAt(i);
        char right = s.charAt(s.length()-(i+1));
        s=s.substring(0, i)+right+s.substring(i+1, s.length()-(i+1))+left+s.substring(s.length()-i, s.length());
    }
    long swapStop = Calendar.getInstance().getTimeInMillis();

    long bufStart = Calendar.getInstance().getTimeInMillis();
    String str = new String("ABCD");
    StringBuffer strBuf = new StringBuffer(str);
    str = strBuf.reverse().toString();
    long bufStop = Calendar.getInstance().getTimeInMillis();

    System.out.println(swapStop-swapStart);
    System.out.println(bufStop-bufStart);
  }
}

***** в новой строке ("ABCD") строки, если я предоставлю действительно большую строку, скажем, пару сотен буквенных чисел

***** в консольном выводе есть:

61
0

***** буфер строк всегда вычисляется в 0 миллисекундах, и мой алгоритм замены символов занимает размер строки

В. Почему мой своп-алгоритм не может сделать это за 0 миллисекунд, и почему stringbuffer всегда делает это за 0 миллисекунд?


Я проверил исходный код Java и StringBuffer.reverse() реализован следующим образом:

public AbstractStringBuilder reverse() {
    boolean hasSurrogate = false;
    int n = count - 1;
    for (int j = (n-1) >> 1; j >= 0; --j) {
        char temp = value[j];
        char temp2 = value[n - j];
        if (!hasSurrogate) {
            hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
                || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
        }
        value[j] = temp2;
        value[n - j] = temp;
    }
    if (hasSurrogate) {
        // Reverse back all valid surrogate pairs
        for (int i = 0; i < count - 1; i++) {
            char c2 = value[i];
            if (Character.isLowSurrogate(c2)) {
                char c1 = value[i + 1];
                if (Character.isHighSurrogate(c1)) {
                    value[i++] = c1;
                    value[i] = c2;
                }
            }
        }
    }
    return this;
}

В. Пожалуйста, объясните суррогатную вещь.

1 ответ

Решение

Q1: есть разница в производительности, потому что ваш код подкачки создает много String объекты, которые обрабатываются, в то время как другая подпрограмма работает напрямую с массивом символов и не требует дополнительного создания объекта. Давайте рассмотрим вашу строку кода:

s=s.substring(0, i)+right+s.substring(i+1, s.length()-(i+1))+left+s.substring(s.length()-i, s.length());

Это делает такую ​​работу:

s = [new String 1] + char + [new String 2] + char + [new String 3]

Вот и 4 новых String объекты (показано три, плюс один в результате добавления String объекты. Кроме того, каждая из 3 показанных новых строк имеет вызов подстроки, для обработки которой требуется время. Кроме того, вы выполняете всю эту работу в цикле for, чтобы она повторялась для каждого персонажа!

Манипулирование строками удобно, но дорого. Манипулирование массивами является прямым, не требует дополнительных объектов или блоков памяти, поэтому выполняется намного быстрее.

Q2: Суррогаты - это особый случай символов Юникода, созданный для обработки более длинных символов Юникода. Смотрите эту статью для более подробной информации. Порядок hi / low частей суррогата важен, поэтому для своп-кода было бы неправильно менять эти два символа на обратные, поэтому, если они найдены, их порядок возвращается таким, каким он должен быть.

Другие вопросы по тегам