charAt () или подстрока? Который быстрее?

Возможно иметь утечки, если неуправляемые ресурсы не становятся убранными правильно. Классы, которые реализуют IDisposable, могут протечь.

Однако регулярные ссылки на объект не требуют явного управления памятью путем, более низкие языки уровня делают.

11
задан estacado 4 November 2009 в 08:39
поделиться

5 ответов

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

import org.junit.Assert;
import org.junit.Test;

public class StringCharTest {

    // Times:
    // 1. Initialization of "s" outside the loop
    // 2. Init of "s" inside the loop
    // 3. newFunction() actually checks the string length,
    // so the function will not be optimized away by the hotstop compiler

    @Test
    // Fastest: 237ms / 562ms / 2434ms
    public void testCacheStrings() throws Exception {
        // Cache all possible Char strings
        String[] char2string = new String[Character.MAX_VALUE];
        for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
            char2string[i] = Character.toString(i);
        }

        for (int x = 0; x < 10000000; x++) {
            char[] s = "abcdefg".toCharArray();
            for (int i = 0; i < s.length; i++) {
                newFunction(char2string[s[i]]);
            }
        }
    }

    @Test
    // Fast: 1687ms / 1725ms / 3382ms
    public void testCharToString() throws Exception {
        for (int x = 0; x < 10000000; x++) {
            String s = "abcdefg";
            for (int i = 0; i < s.length(); i++) {
                // Fast: Creates new String objects, but does not copy an array
                newFunction(Character.toString(s.charAt(i)));
            }
        }
    }

    @Test
    // Very fast: 1331 ms/ 1414ms / 3190ms
    public void testSubstring() throws Exception {
        for (int x = 0; x < 10000000; x++) {
            String s = "abcdefg";
            for (int i = 0; i < s.length(); i++) {
                // The fastest! Reuses the internal char array
                newFunction(s.substring(i, i + 1));
            }
        }
    }

    @Test
    // Slowest: 2525ms / 2961ms / 4703ms
    public void testNewString() throws Exception {
        char[] value = new char[1];
        for (int x = 0; x < 10000000; x++) {
            char[] s = "abcdefg".toCharArray();
            for (int i = 0; i < s.length; i++) {
                value[0] = s[i];
                // Slow! Copies the array
                newFunction(new String(value));
            }
        }
    }

    private void newFunction(String string) {
        // Do something with the one-character string
        Assert.assertEquals(1, string.length());
    }

}
15
ответ дан 3 December 2019 в 01:53
поделиться

Ответ: не имеет значения .

Профилируйте свой код. Это ваше узкое место?

15
ответ дан 3 December 2019 в 01:53
поделиться

Действительно ли newFunction нужно принимать String ? Было бы лучше, если бы вы могли заставить newFunction взять char и называть его так:

newFunction(s.charAt(i));

Таким образом вы избегаете создания временного объекта String.

Чтобы ответить на ваш запрос. вопрос: Трудно сказать, какой из них эффективнее. В обоих примерах необходимо создать объект String , содержащий только один символ. Что более эффективно, зависит от того, как String.substring (...) и Character.toString (...) реализованы в вашей конкретной реализации Java. Единственный способ узнать это - запустить вашу программу через профилировщик и посмотреть, какая версия использует больше ЦП и / или больше памяти. Обычно вы не должны

4
ответ дан 3 December 2019 в 01:53
поделиться

Я бы не хотел говорить о двух опубликованных вами фрагментах. Я согласен с Уиллом в том, что это почти наверняка не имеет отношения к общей производительности вашего кода - и если это не так, вы можете просто внести изменения и определить для себя, что быстрее всего для ваших данных с вашей JVM на вашем оборудовании.

Тем не менее, вероятно, что второй фрагмент будет лучше, если вы сначала преобразовали String в массив char, а затем выполнили свои итерации по массиву. Таким образом, накладные расходы String будут выполняться только один раз (преобразование в массив) вместо каждого вызова. Кроме того, вы можете затем передать массив непосредственно конструктору String с некоторыми индексами, что более эффективно, чем брать char из массива для передачи его индивидуально (который затем превращается в массив из одного символа):

String s = "abcdefg";
char[] chars = s.toCharArray();
for(int i = 0; i < chars.length; i++) {
    newFunction(String.valueOf(chars, i, 1));
}

Но чтобы усилить мою первую мысль, когда вы смотрите на то, что вы на самом деле избегаем при каждом вызове String.charAt () - это две проверки границ, (ленивое) логическое ИЛИ и добавление. Это не будет иметь никакого значения. Также нет разницы в конструкторах String.

По сути, обе идиомы хороши с точки зрения производительности (ни одна из них не является сразу явно неэффективной), поэтому вам не следует больше тратить время на работу с ними, если профилировщик не покажет, что это занимает много количество времени выполнения вашего приложения. И даже тогда вы почти наверняка могли бы получить больший прирост производительности, реструктурируя свой вспомогательный код в этой области (например, newFunction принимает всю строку); java.lang.String к этому моменту довольно хорошо оптимизирован.

2
ответ дан 3 December 2019 в 01:53
поделиться

Сначала я бы получил базовый char [] из исходной String с помощью String.toCharArray (), а затем перешел бы к вызову newFunction.

Но я согласен с Джеспером, что это было бы лучше всего если бы вы могли просто работать с символами и избегать всех строковых функций ...

0
ответ дан 3 December 2019 в 01:53
поделиться
Другие вопросы по тегам:

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