Используя идентичные строковые литералы вместо конечной переменной? - PullRequest
29 голосов
/ 28 января 2011

Я сталкивался с классом, который включает многократное использование строкового литерала "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
    }
}

Ответы [ 6 ]

31 голосов
/ 28 января 2011

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

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

22 голосов
/ 28 января 2011

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

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

Как отмечает Марк, это строго вопрос обслуживания, а не производительности.

8 голосов
/ 28 января 2011

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

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

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

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

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

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

final static String stock="stock";

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

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

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

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

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

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

или

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

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

3 голосов
/ 28 января 2011

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

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

2 голосов
/ 28 января 2011

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

1 голос
/ 28 января 2011

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

...