Работа со строками
Строка представляет собой последовательность символов. Для работы со строками в Java определен класс String, который предоставляет ряд методов для манипуляции строками. Физически объект String представляет собой ссылку на область в памяти, в которой размещены символы.
Для создания новой строки мы можем использовать один из конструкторов класса String, либо напрямую присвоить строку в двойных кавычках:
При работе со строками важно понимать, что объект String является неизменяемым ( immutable ). То есть при любых операциях над строкой, которые изменяют эту строку, фактически будет создаваться новая строка.
Поскольку строка рассматривается как набор символов, то мы можем применить метод length() для нахождения длины строки или длины набора символов:
А с помощью метода toCharArray() можно обратно преобразовать строку в массив символов:
Строка может быть пустой. Для этого ей можно присвоить пустые кавычки или удалить из стоки все символы:
В этом случае длина строки, возвращаемая методом length(), равна 0.
Класс String имеет специальный метод, который позволяет проверить строку на пустоту — isEmpty() . Если строка пуста, он возвращает true:
Переменная String может не указывать на какой-либо объект и иметь значение null :
Значение null не эквивалентно пустой строке. Например, в следующем случае мы столкнемся с ошибкой выполнения:
Так как переменная не указывает ни на какой объект String, то соответственно мы не можем обращаться к методам объекта String. Чтобы избежать подобных ошибок, можно предварительно проверять строку на null:
Основные методы класса String
Основные операции со строками раскрывается через методы класса String, среди которых можно выделить следующие:
concat() : объединяет строки
valueOf() : преобразует объект в строковый вид
join() : соединяет строки с учетом разделителя
сompareTo() : сравнивает две строки
charAt() : возвращает символ строки по индексу
getChars() : возвращает группу символов
equals() : сравнивает строки с учетом регистра
equalsIgnoreCase() : сравнивает строки без учета регистра
regionMatches() : сравнивает подстроки в строках
indexOf() : находит индекс первого вхождения подстроки в строку
lastIndexOf() : находит индекс последнего вхождения подстроки в строку
startsWith() : определяет, начинается ли строка с подстроки
endsWith() : определяет, заканчивается ли строка на определенную подстроку
replace() : заменяет в строке одну подстроку на другую
trim() : удаляет начальные и конечные пробелы
substring() : возвращает подстроку, начиная с определенного индекса до конца или до определенного индекса
Обработка строк в Java. Часть I: String, StringBuffer, StringBuilder
Что вы знаете о обработке строк в Java? Как много этих знаний и насколько они углублены и актуальны? Давайте попробуем вместе со мной разобрать все вопросы, связанные с этой важной, фундаментальной и часто используемой частью языка. Наш маленький гайд будет разбит на две публикации:
String
Строка — объект, что представляет последовательность символов. Для создания и манипулирования строками Java платформа предоставляет общедоступный финальный (не может иметь подклассов) класс java.lang.String. Данный класс является неизменяемым (immutable) — созданный объект класса String не может быть изменен. Можно подумать что методы имеют право изменять этот объект, но это неверно. Методы могут только создавать и возвращать новые строки, в которых хранится результат операции. Неизменяемость строк предоставляет ряд возможностей:
- использование строк в многопоточных средах (String является потокобезопасным (thread-safe) )
- использование String Pool (это коллекция ссылок на String объекты, используется для оптимизации памяти)
- использование строк в качестве ключей в HashMap (ключ рекомендуется делать неизменяемым)
Создание
Мы можем создать объект класса String несколькими способами:
1. Используя строковые литералы:
Строковый литерал — последовательность символов заключенных в двойные кавычки. Важно понимать, что всегда когда вы используете строковой литерал компилятор создает объект со значением этого литерала:
2. С помощью конструкторов:
Если копия строки не требуется явно, использование этих конструкторов нежелательно и в них нет необходимости, так как строки являются неизменными. Постоянное строительство новых объектов таким способом может привести к снижению производительности. Их лучше заменить на аналогичные инициализации с помощью строковых литералов.
Конструкторы могут формировать объект строки с помощью массива символов. Происходит копирование массива, для этого используются статические методы copyOf и copyOfRange (копирование всего массива и его части (если указаны 2-й и 3-й параметр конструктора) соответственно) класса Arrays, которые в свою очередь используют платформо-зависимую реализацию System.arraycopy.
Можно также создать объект строки с помощью массива байтов. Дополнительно можно передать параметр класса Charset, что будет отвечать за кодировку. Происходит декодирование массива с помощью указанной кодировки (если не указано — используется Charset.defaultCharset(), который зависит от кодировки операционной системы) и, далее, полученный массив символов копируется в значение объекта.
Ну и наконец-то конструкторы использующие объекты StringBuffer и StringBuilder, их значения (getValue()) и длину (length()) для создания объекта строки. С этими классами мы познакомимся чуть позже.
Приведены примеры наиболее часто используемых конструкторов класса String, на самом деле их пятнадцать (два из которых помечены как deprecated).
Длина
Важной частью каждой строки есть ее длина. Узнать ее можно обратившись к объекту String с помощью метода доступа (accessor method) length(), который возвращает количество символов в строке, например:
Конкатенация
Конкатенация — операция объединения строк, что возвращает новую строку, что есть результатом объединения второй строки с окончанием первой. Операция для объекта String может быть выполнена двумя способами:
1. Метод concat
Важно понимать, что метод concat не изменяет строку, а лишь создает новую как результат слияния текущей и переданной в качестве параметра. Да, метод возвращает новый объект String, поэтому возможны такие длинные «цепочки».
2. Перегруженные операторы «+» и «+=«
Это одни с немногих перегруженных операторов в Java — язык не позволяет перегружать операции для объектов пользовательских классов. Оператор «+» не использует метод concat, тут используется следующий механизм:
Используйте метод concat, если слияние нужно провести только один раз, для остальных случаев рекомендовано использовать или оператор «+» или StringBuffer / StringBuilder. Также стоит отметить, что получить NPE (NullPointerException), если один с операндов равен null, невозможно с помощью оператора «+» или «+=«, чего не скажешь о методе concat, например:
Форматирование
Класс String предоставляет возможность создания форматированных строк. За это отвечает статический метод format, например:
Методы
Благодаря множеству методов предоставляется возможность манипулирования строкой и ее символами. Описывать их здесь нет смысла, потому что Oracle имеет хорошие статьи о манипулировании и сравнении строк. Также у вас под рукой всегда есть их документация. Хотелось отметить новый статический метод join, который появился в Java 8. Теперь мы можем удобно объединять несколько строк в одну используя разделитель (был добавлен класс java.lang.StringJoiner, что за него отвечает), например:
Это не единственное изменение класса в Java 8. Oracle сообщает о улучшении производительности в конструкторе String(byte[], *) и методе getBytes().
Преобразование
1. Число в строку
2. Строку в число
StringBuffer
Строки являются неизменными, поэтому частая их модификация приводит к созданию новых объектов, что в свою очередь расходует драгоценную память. Для решения этой проблемы был создан класс java.lang.StringBuffer, который позволяет более эффективно работать над модификацией строки. Класс является mutable, то есть изменяемым — используйте его, если Вы хотите изменять содержимое строки. StringBuffer может быть использован в многопоточных средах, так как все необходимые методы являются синхронизированными.
Создание
Существует четыре способа создания объекта класса StringBuffer. Каждый объект имеет свою вместимость (capacity), что отвечает за длину внутреннего буфера. Если длина строки, что хранится в внутреннем буфере, не превышает размер этого буфера (capacity), то нет необходимости выделять новый массив буфера. Если же буфер переполняется — он автоматически становиться больше.
Модификация
В большинстве случаев мы используем StringBuffer для многократного выполнения операций добавления (append), вставки (insert) и удаления (delete) подстрок. Тут все очень просто, например:
Все остальные методы для работы с StringBuffer можно посмотреть в документации.
StringBuilder
StringBuilder — класс, что представляет изменяемую последовательность символов. Класс был введен в Java 5 и имеет полностью идентичный API с StringBuffer. Единственное отличие — StringBuilder не синхронизирован. Это означает, что его использование в многопоточных средах есть нежелательным. Следовательно, если вы работаете с многопоточностью, Вам идеально подходит StringBuffer, иначе используйте StringBuilder, который работает намного быстрее в большинстве реализаций. Напишем небольшой тест для сравнения скорости работы этих двух классов:
Спасибо за внимание. Надеюсь статья поможет узнать что-то новое и натолкнет на удаление всех пробелов в этих вопросах. Все дополнения, уточнения и критика приветствуются.
Строки в Java
Как в большинстве других языков программирования, строка в Java – это последовательность символов. Но, в отличие от многих языков, которые реализуют строки как символьные массивы, в Java строки реализуются как объекты типа String .
Реализация строк в виде встроенных объектов обеспечивает полный комплект свойств, которые делают обработку строк очень удобной. Например, в Java существуют методы для сравнения двух строк, поиска подстроки, конкатенации (сцепления) двух строк и изменения регистра символов строки. Имеется несколько способов создания String-объектов , что облегчает их построение.
Несколько неожиданно, что после создания String-объекта символы, входящие в строку, нельзя изменять. Сначала это кажется серьезным ограничением. Однако это не так. Над этим объектом можно выполнять все типы строковых операций. Для того чтобы изменить версию существующей строки, нужно создать новый объект типа String , который содержит необходимую модификацию. Исходная строка остается неизменной. Этот подход используется, потому что фиксированные, неизменяемые строки можно реализовать более эффективно, чем изменяемые. Для тех случаев, когда желательна изменяемая строка, существует компаньон класса String с именем StringBuffer , чьи объекты содержат строки, которые могут изменяться после их создания.
Классы String и StringBuffer определены в пакете java.lang . Таким образом, они доступны всем программам автоматически. Оба объявлены как final, что означает, что ни один из этих классов не может иметь подклассов. При этом допускаются некоторые оптимизации, которые увеличивают эффективность строковых операций.
И последнее. Когда говорят, что строки в объектах типа String являются неизменяемыми, это означает, что содержимое String-объекта не может быть модифицировано после того, как он был создан. Однако переменную, объявленную как String-ссылка , можно в любое время изменить так, чтобы она указывала на другой String-объект .
Чтобы создать пустой объект типа String , необходимо поступить следующим образом:
String s = new String ();
Данная операция создает экземпляр класса String , не содержащий символов (пустую строку).
Часто необходимо создавать строки с начальными значениями. Чтобы создать String-объект , инициализированный массивом символов, используйте следующий конструктор:
String(char chars[])
Например:
Этот конструктор инициализирует (объектную) переменную s строкой "abc" .
Можно также создать массив строк. Например, так:
Часто используемые методы класса String
Длина строки определяется количеством содержащихся в ней символов. Для получения этого значения вызовите метод length() . Пример:
Для соединения строк используются встроенные операции «+» и «+=».
Если нам требуется узнать, какой символ находится в строке на конкретной позиции, можем использовать метод charAt . Результатом работы метода будет символ типа char. Параметр, который передается в метод — целое число. Первый символ в строке, подобно массивам, имеет индекс 0.
Пример 5: определить последний символ в строке.
Если мы хотим работать со строкой, как с массивом символов, можем конвертировать строку в массив при помощи метода toCharArray .
Пример 6: поменять в строке символы пробела на точки при помощи преобразования в массив символов (для этой задачи есть более простое решение, нежели преобразование в массив, но об этом чуть позже).
Для извлечения подстроки из строки применяются методы substring(int beginIndex, int endIndex) или substring(int beginIndex) . Они возвращает новую строку, которая является подстрокой используемой строки. В параметрах метода нужно указать индекс строки, с которого начинается подстрока и индекс, которым заканчивается. Также возможно указывать только начальный индекс. В этом случае будет возвращена подстрока от начального индекса и до конца строки.
Для разбиения строк на части используется метод split(String regex) , который разбивает строку на основании заданного регулярного выражения.
Поиск в строке выполняет функция contains(CharSequence s) . Она проверяет, содержит ли строка заданную последовательность символов и возвращает true или false .
Функция endsWith(String suffix) проверяет завершается ли строка определенными символами. Назначение функции startsWith(String prefix) ясно, а вот ее версия startsWith(String prefix, int toffset) позволяет указать позицию с которой необходимо начать поиск префикса.
Функции toLowerCase() и toUpperCase() используются для преобразования строки в заданный регистр. Используются они, например когда вам надо выполнять команду, введенную пользователем и вам не важен регистр.
Функции replace(char oldChar, char newChar) и replace(CharSequence target, CharSequence replacement) выполняют замену в строке одного символа или подстроки на другой символ или подстроку.
Переписать рассмотренный выше фрагмент кода, заменяющий в строке пробелы на точки можно переписать с использованием этой функции так:
Пример обработки строк на Java
Для проверки равенства строк надо применять функцию equals , использовать для этого встроенный оператор == нельзя, так как он сравнит не значения строк, а объекты.
Если вам нужно узнать какая из двух строк «больше», например вы хотите упорядочить слова как в словаре — применяйте функцию int compareTo(String anotherString) . Обратите внимание, что она возвращает не boolean , а целое число, которое интерпретируется следующим образом:
- нулевое значение, если строки равны:4
- целое отрицательное число, если первая строка предшествует второй4
- целое положительное число, если первая строка следует за второй.
Рассмотрим пример с именами «Маша» и «Миша». При сравнении этих двух имен (пример 15), метод compareTo укажет, что имя «Маша» предшествует имени «Миша» (выдав отрицательное число) или наоборот, «Миша» следует за «Маша» (выдав положительное число). При упорядочивании имен по алфавиту мы бы упорядочили эти имена именно так. Метод в данном случае определяет, что числовое значение буквы «а» в «Маша» меньше, чем числовое значение «и» в Миша.
Для сравнения строк без учета регистра символов используется функция compareToIgnoreCase(String str) :
Строковый пул Java
Строковый пул в java — пример шаблона разработки ‘облегчения’ (flyweight). То есть по возможности не создавать копии завершенных объектов и не удалять их пока они используются.
Ниже приведены некоторые плюсы которые дает строковый пул:
- на одну и ту же строку могут ссылаться различные объекты
- кеширование строк
- уменьшение расхода памяти (результат первого)
- нет нужды в синхронизации на них в многопоточных приложениях
- при этом кешируется и хеш код строки, а значит повышается
быстродействие объектов типа HashMap;
При этом следует иметь в виду что строки в пуле живут дольше. А значит они доступны любому, имеющему доступ к дампу памяти программы. Поэтому секретные вещи как пароль лучше вообще хранить в виде символьного массива.
Явно сохранить строку в пуле можно методом intern . Интернирование иногда используется для оптимизации программы, чтобы вместо equal использовать ==.
Где-то читал, что имена классов также сохраняются в пуле. Но в андроиде на одном из устройств (Sony Erricson Xperia mini) это оказалось не так, пришлось их интернировать явно.
Преобразование данных в строки и обратно
В Java есть готовые решения по преобразования различных типов данных в строку и наоборот.
Преобразование простых типов в строку делается вызовом метода String.valueOf(arg).
Классы обертки простых типов имеют статический метод для создание объекта из строки SomeType.valueOf(String s). Например, Boolean.valueOf(String s) — возвращает true, если s не равно null и эквивалентно «true» без учета регистра символов.
Для преобразования классов в строку переопределяется метод toString(). По умолчанию он возвращает имя класса.
Другой способ преобразования в строку — использование апи по форматированию строк по шаблону.
числа в строки
- String.valueOf(простой_тип) — создание строки из значения простого типа;
- Integer.toBinaryString(int i) — записать число в двоичной системе (как беззнаковое число);
- Integer.toHexString(int i) — записать число в шестнадцатиричной системе (как беззнаковое число);
- Integer.toOctalString(int i) — записать число в восьмеричной системе (как беззнаковое число);
Строки в числа
- Long.parseLong(String s) — возвращает число типа long, записанное в виде строки (целое знаковое десятичное число);
- Long.valueOf(String s) — аналогично предыдущему, но возвращает объект типа Long;
- Long.parseLong(String s, int radix) — возвращает число типа long записанное в указанной системе исчесления (с основанием до 36);
- Long.valueOf(String s, int radix) — аналогично предыдущему, но возвращает объект типа Long;
Аналогичные методы имеют классы Integer, Short, Float, Double.
дата, время и строки
Для преобразования даты и времени в строку и обратно используется класс SimpleDateFormat.
Форматирование строк по шаблону
Форматирование строки в стиле функции printf языка C поддерживается с помощью:
- Formatter — класс для форматирования строки;
- Formattable — интерфейс форматирования для объектов;
- System.out.printf(…) — форматированный вывод в системную консоль;
- String.format(…) — создание отформатированной строки;
Естественно форматирование адаптировано к языку java, т.е. поддерживаются такие java типы как byte, BigDecimal и Calendar. Более жесткая проверка типов. Возможность использования локализации.
структура шаблона
- argument_index — опциональный параметр указывающий номер аргумента, первый аргумент — «1$», второй — «2$», и т.д.;
- flags — опциональный параметр, набор символов модифицирующих формат вывода. Набор флагов зависит от conversionх;
- width — ширина, опциональный параметр задающий минимальное число символов, которое должно быть записано;
- precision — точность, опциональный параметр обычно ограничивающий число выводимых символов, более спец. значения зависит от conversion;
- conversion — преобразование, обязательный параметр символ задающий как аргумент должен быть отформатирован. Множество допустимых значений для конкретного аргумента зависит от типа аргумента;
преобразования
- ‘b’, ‘B’ — в логический тип, если аргумент null, выводится строка «false». Если аргумент типа boolean или Boolean, вызывается String.valueOf(). В остальных случаях результат «true»;
- ‘h’, ‘H’ — в шестнадатиричное целое число. Если аргумент null, выводится «null». В остальных случаях вызывается Integer.toHexString(arg.hashCode());
- ‘sv, ‘S’ — в строку. Если аргумент null, выводится «null». Если аргумент с интерфейсом Formattable, то вызывается его метод formatTo. В остальных случаях вызывается метод аргумента arg.toString();
- ‘c’, ‘C’ — в юникод символ;
- ‘d’ — в целое десятиченое число;
- ‘o’ — в целое восмиричное числов;
- ‘x’, ‘X’ — в целое шестнадцатириченое число;
- ‘e’, ‘E’ — вещественное число в научной нотации;
- ‘f’ — десятичное вещественое число;
- ‘g’, ‘G’ — вещественное число в научной нотации или в десятичном формате в зависимости от точности (параметр precision), значение округляется;
- ‘a’, ‘A’ — шестнадцатиричное вещественное число с точкое и экспонентой ;
- ‘t’, ‘T’ — префикс для преобразования временных значений, далее идут уточнияющие символы преобразования;
- ‘%’ — вывод сивола ‘%’ (‘\u0025’);
- ‘n’ — вывод разделителя строк используемого на текущей платформе;
интерфейс Formattable
Служит для форматирования объекта в строку. Если он не определен то для форматирования используется метод toString. Ниже приведен пример форматирования класса для использования в http get запросе.
Class String
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. For example:
is equivalent to:
Here are some more examples of how strings can be used:
The class String includes methods for examining individual characters of the sequence, for comparing strings, for searching strings, for extracting substrings, and for creating a copy of a string with all characters translated to uppercase or to lowercase. Case mapping is based on the Unicode Standard version specified by the Character class.
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. For additional information on string concatenation and conversion, see The Java Language Specification.
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
A String represents a string in the UTF-16 format in which supplementary characters are represented by surrogate pairs (see the section Unicode Character Representations in the Character class for more information). Index values refer to char code units, so a supplementary character uses two positions in a String .
The String class provides methods for dealing with Unicode code points (i.e., characters), in addition to those for dealing with Unicode code units (i.e., char values).
Unless otherwise noted, methods for comparing Strings do not take locale into account. The Collator class provides methods for finer-grain, locale-sensitive String comparison.