У меня есть этот код к concate некоторые элементы массива:
StringBuilder sb = new StringBuilder();
private RatedMessage joinMessage(int step, boolean isresult) {
sb.delete(0, sb.length());
RatedMessage rm;
for (int i = 0; i <= step; i++) {
if (mStack[i] == null)
continue;
rm = mStack[i].getCurrentMsg();// msg is built upfront, this just returns, it's a getter method call
if (rm == null || rm.msg.length() == 0)
continue;
if (sb.length() != 0) {
sb.append(", ");
}
sb.append(rm.msg);
}
rm.msg=sb.toString();
return rm;
}
Важный массив содержит макс. 10 объектов, таким образом, это не совсем очень.
Мой вывод трассировки говорит мне, что этот метод называют 18864 раза, 16% времени выполнения были потрачены в этом методе. Я могу оптимизировать больше?
некоторые идеи:
1) Вы инициализируете StringBuilder с расчетной максимальной емкостью? Это может сэкономить время, затрачиваемое на перераспределение и копирование внутреннего массива.
2) Возможно, вы можете добавить в цикл запятую в конце и избежать условия для длины строки внутри цикла. Вместо этого добавьте одно условие в конце метода и при необходимости удалите запятую.
Прежде всего, я не буду повторно использовать StringBuilder и всегда буду создавать новый экземпляр. Это, безусловно, будет быстрее, потому что это позволит GC использовать область кучи молодого поколения.
Еще одна маленькая уловка, которая позволяет исключить хотя бы один оператор if, - это переписать ваш код следующим образом:
String separator = "";
for (int i = 0; i <= step; i++) {
...
sb.append(separator);
sb.append(rm.msg);
separator = ", ";
}
Вы можете сделать следующее изменение (показывающее только различия):
String separator = "";
for (int i = 0; i <= step; i++) {
// ...
sb.append(separator).append(rm.msg);
separator = ", ";
}
Это избавляет от лишнего if 9 раз ценой добавления пустой строки один раз. Вы должны измерить, помогает ли это вообще с данными, которые вы используете, прежде чем решите оставить это изменение :-)
.Используйте StringBuilder + StringUtils из Apache Commons Lang. Цикл по String с разделителем и перебором - вот что такое StringUtils!
private RatedMessage joinMessage(int step, boolean isresult) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i <= step; i++) {
WhateverTypeIsFromMStackVariable stackVariable = mStack[i];
String message = getMessage(stackVariable);
if(StringUtils.isNotEmpty(message)) {
builder.append(message).append(", ");
}
}
RatedMessage rm = new RatedMessage();
rm.msg = StringUtils.chomp(builder.toString(), ", ");
return rm;
}
private static String getMessage(WhateverTypeIsFromMStackVariable stackVariable) {
if(stackVariable != null) {
RatedMessage message = stackVariable.getCurrentMsg();
if(message != null) {
return message.msg;
}
}
return null;
}
Apache Commons Lang находится здесь: http://commons.apache.org/lang/
Имейте отдельную копию массива mStack
со строковым представлением, по умолчанию инициализированного пустой строкой, так что ваш цикл будет:
String [] mStackCopy = new String[]{"","","","","","","","","","",};
// or mstackCopy = new String[mStack.length];
// for( int i = 0 ; i < mStackCopy.lenght ; i++ ) { mStack[i] = "" }
Также создайте StringBuilder с достаточной емкостью:
StringBuilder sb = new StringBuilder( 10000 );// 10k chars or whatever makes sense.
Итак, когда вам нужно создать сообщение, вы должны просто:
for (int i = 0; i <= step; i++) {
sb.append( mStackCopy[i] );
}
И пустые части не вызовут проблем, потому что они уже пусты:
Вы можете даже жестко закодировать его:
sb.append( mStackCopy[0]);
sb.append( mStackCopy[1]);
sb.append( mStackCopy[2]);
sb.append( mStackCopy[3]);
sb.append( mStackCopy[4]);
sb.append( mStackCopy[5]);
sb.append( mStackCopy[6]);
sb.append( mStackCopy[7]);
sb.append( mStackCopy[8]);
sb.append( mStackCopy[9]);
Но это вызовет больше боли чем облегчение в будущем, гарантировано.
Когда вы добавляете что-то в свой mStack:
MStack item = new MStack();
item.setCurrentMessage("Some message");
....
Просто сделайте копию сообщения и уже добавьте «,».
addToMStack(int position, MStackItem item ) {
mStack[position] = item;
mStackCopy[position] = item.getCurrentMessage() + ", ";
}
И в зависимости от появления нулей (если оно мало) вы можете их поймать
addToMStack(int position, MStackItem item ) {
if( item == null ) { return; }
mStack[position] = item;
try {
mStackCopy[position] = item.getCurrentMessage() + ", ";
} catch( NullPointerException npe ){}
}
Что ужасно
Или проверить это:
addToMStack(int position, MStackItem item ) {
if( item == null ) { return; }
mStack[position] = item;
mStackCopy[position] = item.getCurrentMessage() + ", ";
}
Я почти уверен, что ваш метод делает что-то еще, что вы не показываете нам. Наверное, причина в этом.
Кроме того, 16% не так уж и плохо, если 100% - это 1 секунда.
Если ваша функция должна объединять элементы массива, почему вы передаете все эти сумасшедшие значения и неиспользуемые параметры?
private string joinMessage( string[] myArray)
{
StringBuilder sbr = new StringBuilder();
for(int i = 0; i < myArray.Length; i++)
{
if(!string.IsNullOrEmpty(myArray[i])
{
sbr.Append(myArray[i]);
sbr.Append(",")
}
}
return sbr.ToString();
}
Иногда просто больше нечего оптимизировать. Я думаю, что это один из таких случаев. Вы можете попытаться сэкономить инструкцию или две, но в принципе вы не получите намного быстрее.
Я думаю, что единственное, что остается для оптимизации, это рассмотреть почему вы вызываете его 18864 раза и можно ли вообще избежать некоторых из этих вызовов. Возможно, некоторые из них не нужны, или, возможно, в некоторых случаях вы можете кэшировать результат.
Сначала пройдитесь по каждому элементу в стеке, посчитав сумму всех длин строк.
Затем вы можете использовать
sb.ensureCapacity(totalEndLength);
Построитель строк работает как список массивов, поэтому вы можете перестраивать этот массив с большинством ваших добавлений.
Если ваш mStack - это коллекция, а не массив, вы можете просто сделать mStack.toString()
, что выведет читаемую строку массива. Это может быть проще, чем писать свой собственный.
16% времени выполнения в этом методе включая или исключая вызываемые методы? Вызов getCurrentMsg () может быть скрытой проблемой, если он создает много объектов.
Кроме того, я предлагаю извлечь все необходимые строки из вашего стека, а затем вызвать
StringUtils.join (myStrings, ",")
, используя библиотеку общего доступа Apache . Попробуйте полагаться на проверенный код для таких низкоуровневых вещей вместо того, чтобы оптимизировать его самостоятельно через день. В конце концов, это даст вам лучшие результаты оптимизации, потому что вы сможете сосредоточиться на общей картине (то есть на общем дизайне вашего программного обеспечения).
Немного мини-оптимизации... вынесите test-for-comma за пределы цикла.
private RatedMessage joinMessage(int step, boolean isresult) {
sb.delete(0, sb.length());
for (int i = 0; i <= step; i++) {
if (mStack[i] == null)
continue;
rm = mStack[i].getCurrentMsg();
if (rm == null || rm.msg.length() == 0)
continue;
sb.append(rm.msg).append(", ");
}
if (sb.length() > 2) {
sb.delete(sb.length() - 2, 2);
}
return sb.toString();
}
Другие предложения: