Почему это производительность разница
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 частей суррогата важен, поэтому для своп-кода было бы неправильно менять эти два символа на обратные, поэтому, если они найдены, их порядок возвращается таким, каким он должен быть.