Существует ли более быстрый метод затем StringBuilder для макс. конкатенации строк шага 9-10?

У меня есть этот код к 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% времени выполнения были потрачены в этом методе. Я могу оптимизировать больше?

6
задан Pentium10 25 May 2010 в 21:06
поделиться

11 ответов

некоторые идеи:

1) Вы инициализируете StringBuilder с расчетной максимальной емкостью? Это может сэкономить время, затрачиваемое на перераспределение и копирование внутреннего массива.

2) Возможно, вы можете добавить в цикл запятую в конце и избежать условия для длины строки внутри цикла. Вместо этого добавьте одно условие в конце метода и при необходимости удалите запятую.

3
ответ дан 10 December 2019 в 02:43
поделиться

Прежде всего, я не буду повторно использовать StringBuilder и всегда буду создавать новый экземпляр. Это, безусловно, будет быстрее, потому что это позволит GC использовать область кучи молодого поколения.

Еще одна маленькая уловка, которая позволяет исключить хотя бы один оператор if, - это переписать ваш код следующим образом:

    String separator = "";
    for (int i = 0; i <= step; i++) {
        ...
        sb.append(separator);
        sb.append(rm.msg);
        separator = ", ";
    }
5
ответ дан 10 December 2019 в 02:43
поделиться

Вы можете сделать следующее изменение (показывающее только различия):

    String separator = "";
    for (int i = 0; i <= step; i++) {
    // ...
        sb.append(separator).append(rm.msg);
        separator = ", ";
    }

Это избавляет от лишнего if 9 раз ценой добавления пустой строки один раз. Вы должны измерить, помогает ли это вообще с данными, которые вы используете, прежде чем решите оставить это изменение :-)

.
1
ответ дан 10 December 2019 в 02:43
поделиться

Используйте 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/

0
ответ дан 10 December 2019 в 02:43
поделиться

Имейте отдельную копию массива 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 секунда.

0
ответ дан 10 December 2019 в 02:43
поделиться

Если ваша функция должна объединять элементы массива, почему вы передаете все эти сумасшедшие значения и неиспользуемые параметры?

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();
}
0
ответ дан 10 December 2019 в 02:43
поделиться

Иногда просто больше нечего оптимизировать. Я думаю, что это один из таких случаев. Вы можете попытаться сэкономить инструкцию или две, но в принципе вы не получите намного быстрее.

Я думаю, что единственное, что остается для оптимизации, это рассмотреть почему вы вызываете его 18864 раза и можно ли вообще избежать некоторых из этих вызовов. Возможно, некоторые из них не нужны, или, возможно, в некоторых случаях вы можете кэшировать результат.

0
ответ дан 10 December 2019 в 02:43
поделиться

Сначала пройдитесь по каждому элементу в стеке, посчитав сумму всех длин строк.

Затем вы можете использовать

sb.ensureCapacity(totalEndLength);

Построитель строк работает как список массивов, поэтому вы можете перестраивать этот массив с большинством ваших добавлений.

0
ответ дан 10 December 2019 в 02:43
поделиться

Если ваш mStack - это коллекция, а не массив, вы можете просто сделать mStack.toString(), что выведет читаемую строку массива. Это может быть проще, чем писать свой собственный.

0
ответ дан 10 December 2019 в 02:43
поделиться

16% времени выполнения в этом методе включая или исключая вызываемые методы? Вызов getCurrentMsg () может быть скрытой проблемой, если он создает много объектов.

Кроме того, я предлагаю извлечь все необходимые строки из вашего стека, а затем вызвать

StringUtils.join (myStrings, ",")

, используя библиотеку общего доступа Apache . Попробуйте полагаться на проверенный код для таких низкоуровневых вещей вместо того, чтобы оптимизировать его самостоятельно через день. В конце концов, это даст вам лучшие результаты оптимизации, потому что вы сможете сосредоточиться на общей картине (то есть на общем дизайне вашего программного обеспечения).

0
ответ дан 10 December 2019 в 02:43
поделиться

Немного мини-оптимизации... вынесите 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();
}

Другие предложения:

  • Убедитесь, что при создании StringBuilder вы установили его начальную длину в приличное значение
  • Я не уверен в контексте остального кода, но, возможно, вы можете предварительно убедиться, что mStack[i] не будет null, и что mStack[i].getCurrentMessage() не будет null или пустым - это позволит вам вынести больше операторов if за пределы цикла.
0
ответ дан 10 December 2019 в 02:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: