Какие проблемы с памятью (или производительностью) имеют эти два подхода? - PullRequest
2 голосов
/ 11 марта 2020

Будучи начинающим Java стажером и читая о классе String , и все еще несколько сбит с толку относительно концепции памяти String Pool . Итак, я решил написать метод для прописного имени пользователя в форме «john» меняется на «John», используя следующий код:

1-й подход

   String firstUpper = username.substring(0, 1).toUpperCase();
   String restLower = username.substring(1).toLowerCase();
   return firstUpper.concat(restLower);

2-й подход

   return username.substring(0,1).toUpperCase().concat(username.substring(1).toLowerCase());

Ответы [ 3 ]

2 голосов
/ 11 марта 2020

Никаких реальных последствий для производительности или какой-либо инфляции памяти.

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

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

1 голос
/ 11 марта 2020

На самом деле вы должны предпочесть использовать StringBuffer или StringBuilder для таких вещей.

Однако пул строк не имеет ничего общего с обоими подходами.

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

String someString = new String("Shark");

How many strings will be created by the following code snippet? How many strings will exist in the string pool?

И ответ таков: будет создана только одна строка, но две строки будут существовать. Литерал "Shark" String будет помещен в пул строк во время компиляции, а вызов конструктора создаст новый объект String во время выполнения, который будет находиться не в пуле строк, а в куче; и имеет право на сборку мусора, когда выполняются нормальные условия.

Если бы мы назвали .intern() на нем - new String("Shark").intern(), тогда ответ будет «только одна строка будет создана, и будет существовать только одна строка. .intern() вернет ссылку на «Акулу» из пула строк, помещенного туда во время компиляции, и строка, созданная new String("Shark"), будет собираться мусором, поскольку ничто больше не ссылается на нее.

Другой пример вопроса о пуле строк будет такой:

        String s1 = "Shark";
        String s2 = "Shark";
        String s3 = new String("Shark");
        String s4 = new String("Shark").intern();

        System.out.println("s1 == s2 :"+(s1==s2));
        System.out.println("s1 == s3 :"+(s1==s3));
        System.out.println("s1 == s4 :"+(s1==s4));

What will be printed out by this code snippet?

Что, конечно, распечатает это:

s1 == s2 :true
s1 == s3 :false
s1 == s4 :true

Для полноты приведенный выше пример создаст ровно одну строку в строке pool и один в куче: один для двух идентичных литералов "Shark" - во время компиляции, один в куче для экземпляра new String("Shark"), а new String("Shark").intern() вернет ссылку на литерал "Shark", созданный в время компиляции.

КАЖДЫЙ строковый литерал попадет в пул строк. Что-нибудь сделать с типичными вопросами пула строк.

1 голос
/ 11 марта 2020

Это в основном эквивалентные подходы. Но если вы действительно хотите сделать это перформансом, и только первая буква должна быть в верхнем регистре, тогда

username.setCharAt(0, (Character.toUpperCase(username.charAt(0)));

Вы можете применить это к остальной части строки, чтобы сделать другие символы строчными, как

for (int i = 1; i < username.length(); i++)
    username.setCharAt(i, (Character.toLowerCase(username.charAt(i)));

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

РЕДАКТИРОВАТЬ

Сохранение пула строк много места за счет создания строки немного более медленным способом (для обработки пула).

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

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

Однако, используя оператор new, мы заставляем класс String создать новый объект String в пространстве кучи. Мы можем использовать метод intern (), чтобы поместить его в пул или обратиться к другому объекту String из пула строк с таким же значением.

Источник: https://www.journaldev.com/797/what-is-java-string-pool

Итак, если вы хотите сравнить String pool с тем, чтобы он не использовался, вам нужно создать и воссоздать те же строковые литералы, а также сделать это с помощью оператора new. В стресс-тесте вы можете сравнить их относительные показатели. Если бы я хотел сделать сравнение, я бы провел этот тест в качестве начала:

for (int i = 0; i < 100000; i++) {
    String foo = "abc";
}

против

for (int i = 0; i < 100000; i++) {
    String foo = new String("abc");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...