Подтвердить что ты не робот

Каковы преимущества использования идентичных строковых литералов вместо конечной переменной?

Я сталкивался с классом, который включает многократное использование строкового литерала "foo".

Я хотел бы знать, каковы преимущества и влияние (с точки зрения создания объекта, использования памяти и скорости) использования этого подхода вместо объявления строки как окончательной и замены всех литералов конечной переменной?

Например (хотя, очевидно, не реальное использование слова):

private static final String FINAL_STRING = "foo";

public void stringPrinter(){
    for(int i=0;i<10;i++){
        System.out.println(FINAL_STRING);
    }
}

Versus:

public void stringPrinter(){
    for(int i=0;i<10;i++){
        System.out.println("foo");
    }
}

Что предпочтительнее и почему (при условии, что строковое значение останется постоянным)?

Приведет ли приведенный выше (второй) пример к созданию 10 объектов String или JVM поймет, что фактически используется только один литерал, и создаст одну ссылку. Если да, есть ли какое-либо преимущество в объявлении строки как окончательной (как в первом примере)?

Если интерпретируемый код заменяет строковый литерал одной ссылкой, это все равно применяется, если один и тот же литерал встречается в нескольких местах:

public void stringPrinter(){
    for(int i=0;i<5;i++){
        System.out.println("foo"); // first occurence
        System.out.println("foo"); // second occurence
    }
}
4b9b3361

Ответ 1

Они будут точно такими же. Литерал интернирован (любое выражение постоянной времени компиляции, которое приводит к тому, что строка имеет тот же экземпляр, что и все другие константы/литералы) в обоих случаях, а интеллектуальный компилятор + время выполнения не должно быть проблемой, уменьшая оба варианта до наиболее оптимизированного.

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

Ответ 2

Из JLS
Константы времени компиляции типа String всегда "интернированы", чтобы обмениваться уникальными экземплярами, используя метод String.intern.

Итак, нет, там будет только один строковый объект.

Как отмечает Mark, это строго вопрос ремонтопригодности, а не производительности.

Ответ 3

Преимущество не в производительности, а в ремонтопригодности и надежности.

Позвольте мне привести пример, который я натолкнул совсем недавно. Программист создал функцию, которая приняла параметр String, который идентифицировал тип транзакции. Затем в программе он сравнивал строки с этим типом. Как:

if (type.equals("stock"))
{ ... do whatever ... }

Затем он вызвал эту функцию, передав ей значение "Stock".

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

Если вместо этого он объявил окончательный статический, скажем

final static String stock="stock";

Тогда, в первый раз, когда он попытался передать "Сток" вместо "акции", он получил бы ошибку времени компиляции.

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

Использование конечной статики дает как минимум x преимущества:

(1) Если вы неправильно произнесете это, вы получите ошибку времени компиляции, а не возможно тонкую ошибку времени выполнения.

(2) Статический объект может присваивать значащее имя значению. Что более понятно:

if (employeeType.equals("R")) ...

или

if (employeeType.equals(EmployeeType.RETIRED)) ...

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

Ответ 4

Все литералы String хранятся в кеше String (это относится ко всем классам)

Использование константы может сделать код более четким, дать строке некоторый контекст и сделать код более удобным для поддержания esp, если одна и та же строка появляется в нескольких местах.

Ответ 5

Эти строковые литералы интернализируются, поэтому в цикле не создаются новые объекты String. Тем не менее, использование одного и того же буква дважды может быть признаком запаха кода; но не с точки зрения скорости или использования памяти.

Ответ 6

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