Использование String в цикле [закрыт]
Закрыт. Этот вопрос необходимо уточнить или дополнить подробностями. Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение.
Закрыт 2 года назад .
Наткнулся на информацию, что при конкатенации строк на Java с помощью оператора +, например, в цикле for, каждый раз создается новый объект String, что приводит к потере памяти и увеличению времени работы программы. Так ли это? И чем заменить сложение строк в цикле? Stringbilder грузит конкретно и точно приводит к повышенному расходу памяти
Отслеживать
задан 24 дек 2021 в 13:11
Arty Morris Arty Morris
1,493 2 2 золотых знака 6 6 серебряных знаков 13 13 бронзовых знаков
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Заменить сложение строк чем-то более быстрым чем StringBuilder практически нечем, так как StringJoiner , String::join , и др. под капотом используют его, впрочем как и сам оператор + , о чём указано в документации:
The implementation of the string concatenation operator is left to the discretion of a Java compiler, as long as the compiler ultimately conforms to The Java™ Language Specification. For example, the javac compiler may implement the operator with StringBuffer , StringBuilder , or java.lang.invoke.StringConcatFactory depending on the JDK version.
Вольный перевод
Реализация оператора конкатенации строк оставляется на усмотрение Java компилятора, поскольку в конечном итоге компилятор соответствует спецификации языка Java JLS. Например, javac компилятор может реализовать этот оператор, используя StringBuffer , StringBuilder , или java.lang.invoke.StringConcatFactory в зависимости от версии JDK.
Также StringBuilder быстрее потокобезопасного StringBuffer за счёт отсутствия синхронизации, о чём также указано в документации, и поэтому именно он рекомендуется в однопоточном коде:
This class provides an API compatible with StringBuffer , but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
Для увеличения производительности StringBuilder при работе с большими строками, может понадобиться установить его объём capacity при создании экземпляра:
StringBuilder large = new StringBuilder(Integer.MAX_VALUE); // максимальный размер
Конкатенация строк и производительность
Советы от 5 февраля 2002 «Запись методов toString » (источник и перевод на JavaGu.ru) включали следующее предложение:
Обратите внимание, что использование «+» в toString для построения возвращаемого значения не всегда является самым эффективным подходом. Возможно, вы захотите использовать вместо этого StringBuffer .
Читатель технических советов отметил, что в документации по Java говорится о том, что для фактической реализации оператора + применяется StringBuffer . Поэтому возникает вопрос, какой выигрыш в производительности, если он существует, вы получите при явном использовании StringBuffer в ваших программах? В этой статье делается попытка ответить на этот вопрос.
Для начала рассмотрим пример, в котором строка формируется путем повторения одного и того же символа:
class MyTimer <
private final long start;
public MyTimer () start = System.currentTimeMillis () ;
>
public long getElapsed () return System.currentTimeMillis () — start;
>
>
public class AppDemo1 static final int N = 47500 ;
public static void main ( String args [])
// создать строку при помощи оператора +
MyTimer mt = new MyTimer () ;
String str1 = «» ;
for ( int i = 1 ; i str1 = str1 + «*» ;
>
System.out.println ( «elapsed time #1 = » + mt.getElapsed ()) ;
// создать строку при помощи StringBuffer
mt = new MyTimer () ;
StringBuffer sb = new StringBuffer () ;
for ( int i = 1 ; i sb.append ( «*» ) ;
>
String str2 = sb.toString () ;
System.out.println ( «elapsed time #2 = » + mt.getElapsed ()) ;
// проверка на равенство
if ( !str1.equals ( str2 )) System.out.println ( «str1/str2 mismatch» ) ;
>
>
>
После выполнения этой программы вы должны получить примерно следующий результат:
elapsed time # 1 = 61890
elapsed time # 2 = 16
Подход №2 явно использует StringBuffer , тогда как подход №1 использует его неявно, как часть реализации оператора + . Вы можете исследовать байт-коды, использующиеся для реализации первого подхода при помощи команды:
javap -c -classpath . AppDemo1
Разница в «+» и StringBuffer
Откуда такая огромная разница между этими двумя подходами? Во втором подходе символы добавляются в StringBuffer , что довольно эффективно. А в первом подходе не используется этот метод? На самом деле нет. Выражение:
str1 = str1 + «*» ;
не добавляет символы к строке str1 . Это происходит из-за того, что Java-строки постоянны, они не изменяются после создания. Вот что происходит в действительности:
- StringBuffer создается
- str1 копируется в него
- «*» добавляется в буфер
- Результат преобразуется в строку
- Ссылка str1 меняется для указания на эту строку
- Старая строка, на которую ранее ссылалась переменная str1 , делается доступной для сборщика мусора.
Цикл проходит через N итераций, и на каждой итерации содержимое str1 (содержащей N-1 символов) должно быть скопировано в буфер. Такое поведение подразумевает, что первый подход имеет квадратичную или худшую производительность. «Квадратичная» означает, что время выполнения пропорционально квадрату N. Есть вероятность эффективно заморозить приложение при применении такого типа цикла.
В примере AppDemo1 демонстрируется ситуация, когда периодически присоединяется одна строка к другой, так что обе строки должны быть скопированы во временную область ( StringBuffer ), создана новая строка и, затем, ссылка на оригинальную строку заменяется ссылкой на новую строку.
Но что если вы не выполняете этот тип операции, а вместо этого, просто имеете некоторый код, похожий на следующий:
public String toString () <
return «X=» + x + » Y=» + y;
>
Здесь нет цикла или повторений и нет строки, которая становится все длиннее и длиннее. Есть какой-либо вред от применения + вместо StringBuffer в этом примере?
Поясняющий пример
В примере AppDemo1 демонстрируется ситуация, когда периодически присоединяется одна строка к другой, так что обе строки должны быть скопированы во временную область ( StringBuffer ), создана новая строка и, затем, ссылка на оригинальную строку заменяется ссылкой на новую строку.
Но что если вы не выполняете этот тип операции, а вместо этого, просто имеете некоторый код, похожий на следующий:
public String toString () <
return «X=» + x + » Y=» + y;
>
Здесь нет цикла или повторений и нет строки, которая становится все длиннее и длиннее. Есть какой-либо вред от применения + вместо StringBuffer в этом примере?
Для ответа на этот вопрос рассмотрим дополнительный код:
class MyPoint <
private final int x, y;
private final String cache;
public MyPoint ( int x, int y ) this .x = x;
this .y = y;
cache = «X=» + x + » Y=» + y;
>
public String toString1 () return «X=» + x + » Y=» + y;
>
public String toString2 () StringBuffer sb = new StringBuffer () ;
sb.append ( «X=» ) ;
sb.append ( x ) ;
sb.append ( » Y=» ) ;
sb.append ( y ) ;
return sb.toString () ;
>
public String toString3 () String s = «» ;
s = s + «X=» ;
s = s + x;
s = s + » Y=» ;
s = s + y;
return s;
>
public String toString4 () return cache;
>
>
class MyTimer private final long start;
public MyTimer () start = System.currentTimeMillis () ;
>
public long getElapsed () return System.currentTimeMillis () — start;
>
>
public class AppDemo2 static final int N = 1000000 ;
public static void main ( String args []) MyPoint mp = new MyPoint ( 37 , 47 ) ;
String s1 = null ;
String s2 = null ;
String s3 = null ;
String s4 = null ;
MyTimer mt = new MyTimer () ;
for ( int i = 1 ; i s1 = mp.toString1 () ;
>
System.out.println ( «toString1 » + mt.getElapsed ()) ;
mt = new MyTimer () ;
for ( int i = 1 ; i s2 = mp.toString2 () ;
>
System.out.println ( «toString2 » + mt.getElapsed ()) ;
mt = new MyTimer () ;
for ( int i = 1 ; i s3 = mp.toString3 () ;
>
System.out.println ( «toString3 » + mt.getElapsed ()) ;
mt = new MyTimer () ;
for ( int i = 1 ; i s4 = mp.toString4 () ;
>
System.out.println ( «toString4 » + mt.getElapsed ()) ;
// проверка исправности для того, чтобы убедиться,
// что результаты, возвращенные из каждого метода toString идентичны
if ( !s1.equals ( s2 ) || !s2.equals ( s3 ) || !s3.equals ( s4 )) System.out.println ( «check error» ) ;
>
>
>
В этой программе создается класс MyPoint , который используется для представления точек X,Y . В ней реализуются различные методы toString для класса. Результат выполнения программы может выглядеть примерно так:
toString1 2797
toString2 2703
toString3 5656
toString4 32
Расшифровка результатов
Первые два способа, использующие + и StringBuffer , имеют примерно одинаковую производительность. Поэтому вы можете сделать вывод, что эти два способа фактически идентичны. Генерируемый для toString1 байт-код указывает, что создается StringBuffer , а затем различные строки просто добавляются к нему. Полученный код очень похож на toString2 .
Но не все так просто. Первая проблема в том, что вы не всегда сможете сформулировать возвращаемое из toString значение в виде отдельного выражения. toString3 и toString1 показывают идентичные результаты. Но время работы toString3 в два раза больше по причине, описанной в примере AppDemo1 . Пример AppDemo2 демонстрирует ситуацию, когда надо создать возвращаемое значение за один раз. В этом случае toString2 , использующий явно StringBuffer , является более хорошим выбором.
Другая проблема касается высказывания, найденного в «Спецификации по языку программирования Java» в разделе 15.18.1.2, в котором говорится:
Реализация может выполнить преобразование и конкатенацию за один шаг, чтобы избежать создания и удаления промежуточного объекта String . Для увеличения производительности повторных конкатенаций строки компилятор Java может использовать класс StringBuffer или аналогичную технику для уменьшения количества промежуточных объектов String , создающихся при вычислении выражения.
Это утверждение говорит о том, что компилятор Java не обязательно оптимизирует такое выражение как:
str1 + str2 + str3 + .
как это сделано для метода toString1 , а может вместо этого создать промежуточные строковые объекты.
Поэтому будьте осторожны при использовании оператора + , особенно для длинных строк или в циклах.
Отметим, что существует даже более быстрый способ реализации toString для этого примера. MyPoint является постоянным классом. Это означает, что его экземпляры не могут быть модифицированы после создания. Учитывая это, возвращаемое из toString значение всегда будет одним и тем же. Поскольку значения одинаковы, оно может быть вычислено один раз в конструкторе MyPoint и затем просто возвращено из toString4 .
Такой вид кэширования часто очень полезен, но есть и отрицательные стороны. Если класс является изменяемым, то кэширование может не иметь смысла. Тоже самое можно сказать и для ситуаций, когда вычисление значения кэша трудоемко, когда кэш занимает много памяти, или когда метод toString вызывается нечасто.
Ссылки
Дополнительная информация по этой теме находится в разделе 15.18.1 «Оператор конкатенации строк +» в «Спецификации по языку программирования Java, второе издание (http://java.sun.com/docs/books/jls/), и в разделе 5 «Строки» книги «Настройка производительности Java» Jack Shirazi.
A может Вас также заинтересует что-нибудь из этого:
- Разное → Теория и практика Java: Динамическая компиляция и измерение производительности
- Java сниппеты → Какой длины ваша строка?
- Java Standard Edition → Блокировки
- Java сниппеты → Блоки статической и объектной инициализации
- Java сниппеты → Методы для работы с переменным количеством аргументов
- Java Standard Edition → Производительность операций ввода/вывода в Java
Объединение строк в Java
Java предоставляет значительное количество методов и классов, предназначенных для объединения строк.
В этом уроке мы рассмотрим некоторые из них, а также обрисуем в общих чертах некоторые распространенные ловушки и плохие практики.
2. Построитель строк
Прежде всего, это скромный StringBuilder. Этот класс предоставляет набор утилит для построения строк , упрощающих работу со строками .
Давайте создадим быстрый пример конкатенации строк, используя класс StringBuilder :
StringBuilder stringBuilder = new StringBuilder(100); stringBuilder.append("ForEach"); stringBuilder.append(" is"); stringBuilder.append(" awesome"); assertEquals("ForEach is awesome", stringBuilder.toString());
Внутри StringBuilder поддерживает изменяемый массив символов. В нашем примере кода мы объявили начальный размер 100 с помощью конструктора StringBuilder . Из-за этого объявления размера StringBuilder может быть очень эффективным способом объединения строк .
Также стоит отметить, что класс StringBuffer является синхронизированной версией StringBuilder .
Хотя синхронизация часто является синонимом безопасности потоков, ее не рекомендуется использовать в многопоточных приложениях из -за шаблона построителя StringBuffer . В то время как отдельные вызовы синхронизированного метода являются потокобезопасными, множественные вызовы — нет .
3. Оператор сложения
Далее следует оператор сложения (+). Это тот же самый оператор, который приводит к сложению чисел и перегружается для конкатенации при применении к строкам.
Давайте кратко рассмотрим, как это работает:
String myString = "The " + "quick " + "brown " + "fox. "; assertEquals("The quick brown fox. ", myString);
На первый взгляд это может показаться гораздо более лаконичным, чем вариант StringBuilder . Однако при компиляции исходного кода символ + транслируется в цепочки вызовов StringBuilder.append() . Из-за этого смешивание « метода конкатенации StringBuilder и + считается плохой практикой .
Кроме того, следует избегать конкатенации строк с помощью оператора + внутри цикла . Поскольку объект String неизменяем, каждый вызов конкатенации приведет к созданию нового объекта String .
4. Строковые методы
Сам класс String предоставляет целый набор методов для объединения строк.
4.1. String.concat
Неудивительно, что метод String.concat является нашим первым портом захода при попытке конкатенации объектов String . Этот метод возвращает объект String , поэтому объединение методов в цепочку является полезной функцией.
String myString = "Both".concat(" fickle") .concat(" dwarves") .concat(" jinx") .concat(" my") .concat(" pig") .concat(" quiz"); assertEquals("Both fickle dwarves jinx my pig quiz", myString);
В этом примере наша цепочка начинается с литерала String , затем метод concat позволяет нам объединять вызовы в цепочку для добавления дополнительных строк .
4.2. String.format
Далее следует метод String.format , который позволяет нам внедрять различные объекты Java в шаблон String .
Сигнатура метода String.format принимает одну строку , обозначающую наш шаблон . Этот шаблон содержит символы ‘%’ для обозначения того, где в нем должны быть размещены различные объекты « .
Как только наш шаблон объявлен, он принимает массив объектов varargs , который вводится « в шаблон.
Давайте посмотрим, как это работает, на быстром примере:
String myString = String.format("%s %s %.2f %s %s, %s. ", "I", "ate", 2.5056302, "blueberry", "pies", "oops"); assertEquals("I ate 2.51 blueberry pies, oops. ", myString);
Как мы видим выше, метод внедрил наши строки в правильный формат.
4.3. String.join (Java 8+)
Если наше приложение работает на Java 8 или выше , мы можем воспользоваться методом String.join . При этом мы можем соединить массив строк с общим разделителем , гарантируя, что не будут пропущены пробелы.
String[] strings = "I'm", "running", "out", "of", "pangrams!">; String myString = String.join(" ", strings); assertEquals("I'm running out of pangrams!", myString);
Огромным преимуществом этого метода является то, что вам не нужно беспокоиться о разделителе между строками.
5. StringJoiner (Java 8+)
StringJoiner абстрагирует всю функциональность String.join в простой в использовании класс. Конструктор принимает разделитель с необязательным префиксом и суффиксом . Мы можем добавлять строки , используя хорошо названный метод add .
StringJoiner fruitJoiner = new StringJoiner(", "); fruitJoiner.add("Apples"); fruitJoiner.add("Oranges"); fruitJoiner.add("Bananas"); assertEquals("Apples, Oranges, Bananas", fruitJoiner.toString());
Используя этот класс вместо метода String.join , мы можем добавлять строки во время работы программы ; Нет необходимости сначала создавать массив!
Перейдите к нашей статье о StringJoiner для получения дополнительной информации и примеров.
6. Массивы.toString
Что касается массивов, класс Array также содержит удобный метод toString , который прекрасно форматирует массив объектов. Массивы . Метод toString также вызывает метод toString любого вложенного объекта, поэтому нам нужно убедиться, что он определен.
String[] myFavouriteLanguages = "Java", "JavaScript", "Python">; String toString = Arrays.toString(myFavouriteLanguages); assertEquals("[Java, JavaScript, Python]", toString);
К сожалению, массивы. Метод toString не настраивается и выводит только строку , заключенную в квадратные скобки.
7. Collectors.joining (Java 8+)
Наконец, давайте взглянем на метод Collectors.joining , который позволяет нам направлять вывод Stream в одну строку.
ListString> awesomeAnimals = Arrays.asList("Shark", "Panda", "Armadillo"); String animalString = awesomeAnimals.stream().collect(Collectors.joining(", ")); assertEquals("Shark, Panda, Armadillo", animalString);
Использование потоков открывает доступ ко всем функциям, связанным с Java 8 Stream API , таким как фильтрация, сопоставление, итерация и многое другое.
8. Подведение итогов
В этой статье мы подробно рассмотрели множество классов и методов, используемых для объединения строк « в языке Java.
Как всегда, исходный код доступен на GitHub .
- 1. Введение
- 2. Построитель строк
- 3. Оператор сложения
- 4. Строковые методы
- 4.1. String.concat
- 4.2. String.format
- 4.3. String.join (Java 8+)
Java String. Вопросы к собеседованию и ответы на них, ч.1


Класс String один из наиболее широко используемых классов в Java. В статье приведены некоторые важные вопросы к собеседованию по Java String и ответы на них. Они будут очень полезны для получения полного представления о классе String и подготовят к любому вопросу, касающемуся класса String на собеседовании.
1. Что такое String в Java? Какой это тип данных?
String — это класс в Java, который прописан в пакете java.lang. Это не примитивный тип данных, как int и long. Класс String представляет строковый набор символов. Строки используются практически по всех Java-приложениях, и есть несколько фактов, которые мы должны знать о классе String. Это неизменяемый ( immutable ) и финализированный тип данных в Java и все объекты класса String виртуальная машина хранит в пуле строк. Еще одной особенностью String является способ получения объектов класса String используя двойные кавычки и перегружая оператор “+” для конкатенации.
2. Какие есть способы создания объекта String?
Мы можем создавать объекты используя оператор new, как и для любого другого класса в Java или мы можем использовать двойные кавычки для создания объекта String . Также есть несколько конструкторов класса String для получения строки из массива символов, массива байтов, а также используя StringBuffer или StringBuilder .
String str = new String("abc"); String str1 = "abc";Когда мы создаем строку используя двойные кавычки, виртуальная машина Java ищет в пуле строк другую строку с таким же значением. Если строка найдена, то возвращается только ссылка на существующий объект класса String , иначе создается новый объект с полученным значением, и сохраняется в пул. Когда мы используем оператор new, виртуальная машина создает объект String , но не хранит его в пуле строк. Мы можем использовать метод intern() для сохранения строки в пуле строк, или получения ссылки, если такая строка уже находится в пуле.
3. Напишите метод проверки, является ли строка палиндромом.
Строка называется палиндромом, если она одинаково читается в обоих направлениях. К примеру “аба” является строкой-палиндромом. Класс String не предоставляет никакого метода для реверса строки, зато классы StringBuffer и StringBuilder имеют метод реверсирования, при помощи которого мы можем проверить, является ли наша строка палиндромом или нет.
private static boolean isPalindrome(String str)
Иногда собеседующий может попросить не использовать другие классы для этой проверки, в таком случае мы можем сравнивать символы в строке с обоих сторон для проверки на палиндром.
private static boolean isPalindromeString(String str) < if (str == null) return false; int length = str.length(); System.out.println(length / 2); for (int i = 0; i < length / 2; i++) < if (str.charAt(i) != str.charAt(length - i - 1)) return false; >return true; >4. Напишите метод удаления данного символа из строки.
Мы можем использовать метод replaceAll для замены всех вхождений в строку другой строкой. Обратите внимание на то, что метод получает в качестве аргумента строку, поэтому мы используем класс Character для создания строки из символа, и используем её для замены всех символов на пустую строку.
private static String removeChar(String str, char ch)
5. Как мы можем перевести строку в верхний регистр или нижний регистр?
Мы можем использовать методы класса String toUpperCase и toLowerCace для получения строки в верхнем и в нижнем регистре. Эти методы имеют перегруженный вариант, принимающий аргумент Locale , и используют его правила локализации для преобразования строки в верхний или нижний регистр.
6. Что делает метод subSequence?
Java 1.4 ввела интерфейс CharSequence , класс String наследует этот интерфейс, и это единственная причина реализации метода subSequence в классе String . Внутри он вызывает метод substring . Простой пример использования метода:
public class StringSubsequence < public static void main(String[] args) < String str = "www.journaldev.com"; System.out.println("Last 4 char String: "+str.subSequence(str.length()-4, str.length())); System.out.println("First 4 char String: "+str.subSequence(0, 4)); System.out.println("website name: "+str.subSequence(4, 14)); //substring vs subSequence System.out.println("substring == subSequence ? " +(str.substring(4, 14) == str.subSequence(4, 14))); System.out.println("substring equals subSequence ? " +(str.substring(4, 14).equals(str.subSequence(4, 14)))); >>На выходе программа покажет следующее:
Last 4 char String: .com First 4 char String: www. website name: journaldev substring == subSequence ? false substring equals subSequence ? trueВ идеале вы должны всегда использовать метод substring .
7. Как сравнить две строки в Java?
Класс String наследует интерфейс Comparable и имеет два варианта метода compareTo() . Метод compareTo(String anotherString) сравнивает объект String с полученным аргументом String лексикографически. Если текущая строка предшествует полученной строке, метод возвращает отрицательное значение типа integer, и если строка следует за полученным аргументом, то возвращает положительное значение integer . Если метод возвращает 0, значит строка имеет то же значение, в таком случае метод equals(String str) так же вернет true. compareToIgnoreCase(String str) : этот метод подобен предыдущему, за исключением того, что он игнорирует регистр символов. Он использует CASE_INSENSITIVE_ORDER Comparator для регистронезависимого сравнения. Если возвращаемое значение равно нулю, тогда метод equalsIgnoreCase(String str) так же вернет true. Давайте рассмотрим небольшой пример, объясняющий эти методы:
public class StringCompareToExample < public static void main(String[] args) < String str = "ABC"; System.out.println(str.compareTo("DEF")); System.out.println(str.compareToIgnoreCase("abc")); >>Программа выведет следующее:
8. Как преобразовать строку в символ и обратно?
Это вопрос с подвохом, поскольку строка – это последовательность символов, поэтому мы можем преобразовать её только в единичный символ. Мы можем использовать метод charAt для получения символа, находящегося в указанной позиции или мы можем использовать метод toCharArray() для преобразования строки в массив символов. Простой пример, показывающий как преобразовать строку в символ и символ в строку в Java.
import java.util.Arrays; public class StringToCharToString < public static void main(String[] args) < //String to char array String str = "123"; char[] chArr = str.toCharArray(); System.out.println("String to char array: "+Arrays.toString(chArr)); //String to char char c = str.charAt(1); System.out.println("String to char: "+c); //char to String String s = Character.toString(c); System.out.println("char to String: "+s); //удалить все заданные символы из строки System.out.println("removing all chars from String: " +removeCharFromString("1ABCD12DW", '1')); >private static String removeCharFromString(String str, char c) < return str.replaceAll(Character.toString( c ), ""); >>Программа выведет следующее:
String to char array: [1, 2, 3] String to char: 2 char to String: 2 removing all chars from String: ABCD2DW9. Как преобразовать строку в массив байтов и обратно?
Мы можем использовать метод getBytes() для преобразования строки в массив байтов и мы можем использовать конструктор new String(byte[] arr) для преобразования массива байтов в строку.
import java.util.Arrays; public class StringByteArray < public static void main(String[] args) < String str = "www.journaldev.com"; //преобразование String в byte array byte[] byteArr = str.getBytes(); System.out.println("String to byte array : "+Arrays.toString(byteArr)); //преобразование byte array и String String str1 = new String(byteArr); System.out.println("byte array to String : "+str1); //посмотрим, str и str1 одинаковые или нет System.out.println("str == str1? " + (str == str1)); System.out.println("str.equals(str1)? " + (str.equals(str1))); >>Программа выведет следующее:
String to byte array : [119, 119, 119, 46, 106, 111, 117, 114, 110, 97, 108, 100, 101, 118, 46, 99, 111, 109] byte array to String : www.journaldev.com str == str1? false str.equals(str1)? true10. Можем ли мы использовать строку в конструкции switch.
Этот хитрый вопрос, используется для проверки ваших знаний о текущем развитии языка. Java 7 расширяет возможности оператора switch для использования строк, ранние версии Java не поддерживают этого. Если вы реализуете условный поток для строк, вы можете использовать условия if-else и вы можете использовать оператор switch, если используете Java 7 или поздние версии. Небольшой пример использования строки в операторе switch и другой метод, который показывает такую же логику, используя условия if-else .
public class SwitchStringExample < public static void main(String[] args) < printColorUsingSwitch("red"); printColorUsingIf("red"); // оператор switch регистрозависимый printColorUsingSwitch("RED"); printColorUsingSwitch(null); >private static void printColorUsingIf(String color) < if (color.equals("blue")) < System.out.println("BLUE"); >else if (color.equals("red")) < System.out.println("RED"); >else < System.out.println("INVALID COLOR CODE"); >> private static void printColorUsingSwitch(String color) < switch (color) < case "blue": System.out.println("BLUE"); break; case "red": System.out.println("RED"); break; default: System.out.println("INVALID COLOR CODE"); >> >Программа выведет следующее:
RED RED INVALID COLOR CODE Exception in thread "main" java.lang.NullPointerException at com.journaldev.util.SwitchStringExample.printColorUsingSwitch(SwitchStringExample.java:24) at com.journaldev.util.SwitchStringExample.main(SwitchStringExample.java:10)- использование строк в конструкции switch делает код читабельнее, убирая множественные цепи условий if-else .
- строки в switch чувствительны к регистру, пример выше показывает это.
- оператор switch использует метод String.equals() для сравнения полученного значения со значениями case, поэтому добавьте проверку на NULL во избежание NullPointerException .
- согласно документации Java 7 для строк в switch , компилятор Java формирует более эффективный байткод для строк в конструкции switch , чем для сцепленных условий if-else .
- убедитесь, что это будет использоваться с Java 7 или поздней версии, иначе получите xception .
11. Напишите программу, печатающую все перестановки строки.
Это непростой вопрос, и мы должны использовать рекурсию для нахождения всех перестановок строки, например перестановками “AAB” могут быть “AAB”, “ABA” и “BAA”. Также нам необходимо использовать Set для того, чтобы убедиться, что у нас нет дубликатов строк. Для получения всех перестановок, мы для начала берем первый символ строки и переставляем оставшиеся символы. Если String = “ABC” Первый символ char = A и оставшиеся перестановки BC и CB. Теперь мы можем вставить первый символ в доступные позиции в перестановках. BC -> ABC, BAC, BCA CB -> ACB, CAB, CBA Пример программы:
import java.util.HashSet; import java.util.Set; public class StringHelper < public static SetpermutationFinder(String str) < Setperm = new HashSet(); //Handling error scenarios if (str == null) < return null; >else if (str.length() == 0) < perm.add(""); return perm; >char initial = str.charAt(0); // первый символ String rem = str.substring(1); // полная строка без первого символа Set words = permutationFinder(rem); for (String strNew : words) < for (int i = 0;i<=strNew.length();i++)< perm.add(charInsert(strNew, initial, i)); >> return perm; > public static String charInsert(String str, char c, int j) < String begin = str.substring(0, j); String end = str.substring(j); return begin + c + end; >public static void main(String[] args) < String s = "AAC"; String s1 = "ABC"; String s2 = "ABCD"; System.out.println("\nPermutations for " + s + " are: \n" + permutationFinder(s)); System.out.println("\nPermutations for " + s1 + " are: \n" + permutationFinder(s1)); System.out.println("\nPermutations for " + s2 + " are: \n" + permutationFinder(s2)); >>Вывод программы:
Permutations for AAC are: [AAC, ACA, CAA] Permutations for ABC are: [ACB, ABC, BCA, CBA, CAB, BAC] Permutations for ABCD are: [DABC, CADB, BCAD, DBAC, BACD, ABCD, ABDC, DCBA, ADBC, ADCB, CBDA, CBAD, DACB, ACBD, CDBA, CDAB, DCAB, ACDB, DBCA, BDAC, CABD, BADC, BCDA, BDCA]