Какие нюансы у строк в java
Перейти к содержимому

Какие нюансы у строк в java

  • автор:

Работа со строками

Строка представляет собой последовательность символов. Для работы со строками в Java определен класс String, который предоставляет ряд методов для манипуляции строками. Физически объект String представляет собой ссылку на область в памяти, в которой размещены символы.

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

public static void main(String[] args) < String str1 = "Java"; String str2 = new String(); // пустая строка String str3 = new String(new char[] ); String str4 = new String(new char[], 3, 4);//3 -начальный индекс, 4 -кол-во символов System.out.println(str1); // Java System.out.println(str2); // System.out.println(str3); // hello System.out.println(str4); // come >

При работе со строками важно понимать, что объект String является неизменяемым ( immutable ). То есть при любых операциях над строкой, которые изменяют эту строку, фактически будет создаваться новая строка.

Поскольку строка рассматривается как набор символов, то мы можем применить метод length() для нахождения длины строки или длины набора символов:

String str1 = "Java"; System.out.println(str1.length()); // 4

А с помощью метода toCharArray() можно обратно преобразовать строку в массив символов:

String str1 = new String(new char[] ); char[] helloArray = str1.toCharArray();

Строка может быть пустой. Для этого ей можно присвоить пустые кавычки или удалить из стоки все символы:

String s = ""; // пустая строка if(s.length() == 0) System.out.println("String is empty");

В этом случае длина строки, возвращаемая методом length(), равна 0.

Класс String имеет специальный метод, который позволяет проверить строку на пустоту — isEmpty() . Если строка пуста, он возвращает true:

String s = ""; // пустая строка if(s.isEmpty()) System.out.println("String is empty");

Переменная String может не указывать на какой-либо объект и иметь значение null :

String s = null; // строка не указывает на объект if(s == null) System.out.println("String is null");

Значение null не эквивалентно пустой строке. Например, в следующем случае мы столкнемся с ошибкой выполнения:

String s = null; // строка не указывает на объект if(s.length()==0) System.out.println("String is empty"); // ! Ошибка

Так как переменная не указывает ни на какой объект String, то соответственно мы не можем обращаться к методам объекта String. Чтобы избежать подобных ошибок, можно предварительно проверять строку на null:

String s = null; // строка не указывает на объект if(s==null || s.length()==0) System.out.println("String is empty");

Основные методы класса String

Основные операции со строками раскрывается через методы класса String, среди которых можно выделить следующие:

  • concat() : объединяет строки
  • valueOf() : преобразует объект в строковый вид
  • join() : соединяет строки с учетом разделителя
  • сompareTo() : сравнивает две строки
  • charAt() : возвращает символ строки по индексу
  • getChars() : возвращает группу символов
  • equals() : сравнивает строки с учетом регистра
  • equalsIgnoreCase() : сравнивает строки без учета регистра
  • regionMatches() : сравнивает подстроки в строках
  • indexOf() : находит индекс первого вхождения подстроки в строку
  • lastIndexOf() : находит индекс последнего вхождения подстроки в строку
  • startsWith() : определяет, начинается ли строка с подстроки
  • endsWith() : определяет, заканчивается ли строка на определенную подстроку
  • replace() : заменяет в строке одну подстроку на другую
  • trim() : удаляет начальные и конечные пробелы
  • substring() : возвращает подстроку, начиная с определенного индекса до конца или до определенного индекса
  • toLowerCase() : переводит все символы строки в нижний регистр
  • toUpperCase() : переводит все символы строки в верхний регистр

Разберем работу этих методов.

15. Java – Строки и методы класса String

Строки – представляют собой последовательность символов. Строки в Java широко используются и являются объектами.

Платформа Java предоставляет класс строк (class String) для создания и работы со строками.

Создание строк

Наиболее простой способ создать строку:

String greeting = "Здравствуй, мир!"; 

После каждого раза, когда компилятор встречает строковый литерал в коде, он создает строковый объект (String) со значение, в данном случае «Здравствуй, мир!».

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

Пример

public class Test < public static void main(String args[])< char[] helloArray = < 'П', 'р', 'и', 'в', 'е', 'т', '.'>; String helloString = new String(helloArray); System.out.println(helloString); > > 

Получим следующий результат:

Привет. 

Примечание: Класс строк является неизменяемым, так что как только он будет создан, строковый объект не может быть изменен. Если есть необходимость сделать много изменений в строке символов, следует использовать классы строки буфера (String Buffer) и построитель строки (String Builder Classes).

Длина строки

Методы, используемые для получения информации об объекте, известны как методы доступа. Один из методов доступа, который можно использовать со строками является метод length(), он возвращает количество символов, содержащихся в строковом объекте.

Ниже представлен пример метода length(), который поможет определить длину строки.

Пример

public class Test < public static void main(String args[]) < String s = "Я стану отличным программистом!"; int len = s.length(); System.out.println( "Длина строки: " + len + " символ."); >> 

Получим следующий результат:

Длина строки: 31 символ. 

Объединение строк в Java

Класс строк включает метод для объединения двух строк:

string1.concat(string2); 

Возвращает новую строку string1, с добавленной строкой string2 в конце. Вы также можете использовать метод concat() со строковыми литералами:

"Меня зовут ".concat("Олег"); 

Чаще строки объединяют оператором +:

"Здравствуй," + " мир" + "!" 
Здравствуй мир! 

Давайте посмотрим на следующем примере.

Пример

public class Test < public static void main(String args[]) < String string1 = "отличным "; System.out.println("Я стану " + string1 + "программистом!"); >> 

Получим следующий результат:

Я стану отличным программистом! 

Создание формата строк

Мы уже изучали методы printf() и format() для вывода на печать с отформатированными числами. Класс строк в Java обладает эквивалентным методом format(), который возвращает строковый объект, а не потоковый объект (PrintStream).

Использование строкового статического метода format() позволяет создавать строку нужного формата, который можно использовать повторно, в отличие от одноразовых операторов print. Например вместо:

System.out.printf("Значение переменной float = " + "%f, пока значение integer " + "переменная = %d, и string " + "= %s", floatVar, intVar, stringVar); 

Вы также можете написать:

String fs; fs = String.format("Значение переменной float = " + "%f, пока значение integer " + "переменная = %d, и string " + "= %s", floatVar, intVar, stringVar); System.out.println(fs); 

Методы класса строк

Ниже приведен список методов, поддерживаемых классом строк.

Методы с описанием
1 char charAt(int index)
Возвращает символ по указанному индексу.
2 int compareTo(Object o)
Сравнивает данную строку с другим объектом.
3 int compareTo(String anotherString)
Сравнивает две строки лексически.
4 int compareToIgnoreCase(String str)
Сравнивает две строки лексически, игнорируя регистр букв.
5 String concat(String str)
Объединяет указанную строку с данной строкой, путем добавления ее в конце.
6 boolean contentEquals(StringBuffer sb)
Возвращает значение true только в том случае, если эта строка представляет собой ту же последовательность символов как указанно в буфере строки (StringBuffer).
7 static String copyValueOf(char[] data)
Возвращает строку, которая представляет собой последовательность символов, в указанный массив.
8 static String copyValueOf(char[] data, int offset, int count)
Возвращает строку, которая представляет собой последовательность символов, в указанный массив.
9 boolean endsWith(String suffix)
Проверяет заканчивается ли эта строка указанным окончанием.
10 boolean equals(Object anObject)
Сравнивает данную строку с указанным объектом.
11 boolean equalsIgnoreCase(String anotherString)
Сравнивает данную строку с другой строкой, игнорируя регистр букв.
12 byte getBytes()
Кодирует эту строку в последовательность байтов с помощью платформы charset, сохраняя результат в новый массив байтов.
13 byte[] getBytes(String charsetName
Кодирует эту строку в последовательность байтов с помощью платформы charset, сохраняя результат в новый массив байтов.
14 void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
Копирует символы из этой строки в массив символов назначения.
15 int hashCode()
Возвращает хэш-код для этой строки.
16 int indexOf(int ch)
Возвращает индекс первого вхождения указанного символа в данной строке.
17 int indexOf(int ch, int fromIndex)
Возвращает индекс первого вхождения указанного символа в данной строке, начиная поиск с указанного индекса.
18 int indexOf(String str)
Возвращает индекс первого вхождения указанной подстроки в данной строке.
19 int indexOf(String str, int fromIndex)
Возвращает индекс первого вхождения указанной подстроки в данной строке, начиная с указанного индекса.
20 String intern()
Возвращает каноническое представление для строкового объекта.
21 int lastIndexOf(int ch)
Возвращает индекс последнего вхождения указанного символа в этой строке.
22 int lastIndexOf(int ch, int fromIndex)
Возвращает индекс последнего вхождения указанного символа в этой строке, начиная обратный поиск с указанного индекса.
23 int lastIndexOf(String str)
Возвращает индекс последнего вхождения указанной подстроки в данной строке.
24 int lastIndexOf(String str, int fromIndex)
Возвращает индекс последнего вхождения указанной подстроки в этой строке, начиная обратный поиск с указанного индекса.
25 int length()
Возвращает длину строки.
26 boolean matches(String regex)
Сообщает, соответствует ли или нет эта строка заданному регулярному выражению.
27 boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
Проверяет равны ли две области строки.
28 boolean regionMatches(int toffset, String other, int ooffset, int len)
Проверяет равны ли две области строки.
29 String replace(char oldChar, char newChar)
Возвращает новую строку, в результате, заменив все вхождения oldChar в этой строке на newChar.
30 String replaceAll(String regex, String replacement)
Заменяет каждую подстроку строки, соответствующей заданному регулярному выражению с данной заменой.
31 String replaceFirst(String regex, String replacement)
Заменяет первые подстроки данной строки, которая соответствует заданному регулярному выражению с данной заменой.
32 String[] split(String regex)
Разделяет эту строку, окружая данным регулярным выражением.
33 String[] split(String regex, int limit)
Разделяет эту строку, окружая данным регулярным выражением.
34 boolean startsWith(String prefix)
Проверяет, начинается ли эта строка с заданного префикса.
35 boolean startsWith(String prefix, int toffset)
Проверяет, начинается ли эта строка с указанного префикса, начиная с указанного индекса.
36 CharSequence subSequence(int beginIndex, int endIndex)
Возвращает новую последовательность символов, которая является подпоследовательностью этой последовательности.
37 String substring(int beginIndex)
Возвращает новую строку, которая является подстрокой данной строки.
38 String substring(int beginIndex, int endIndex)
Возвращает новую строку, которая является подстрокой данной строки.
39 char[] toCharArray()
Преобразует эту строку в новый массив символов.
40 String toLowerCase()
Преобразует все символы в данной строке в нижний регистр, используя правила данного языкового стандарта.
41 String toLowerCase(Locale locale)
Преобразует все знаки в данной строке в нижний регистр, используя правила данного языкового стандарта.
42 String toString()
Этот объект (который уже является строкой!) возвращает себя.
43 String toUpperCase()
Преобразует все символы в строке в верхний регистр, используя правила данного языкового стандарта.
44 String toUpperCase(Locale locale)
Преобразует все символы в строке в верхний регистр, используя правила данного языкового стандарта.
45 String trim()
Возвращает копию строки с пропущенными начальными и конечными пробелами.
46 static String valueOf(primitive data type x)
Возвращает строковое представление переданного типа данных аргумента.

Оглавление

  • 1. Java – Самоучитель для начинающих
  • 2. Java – Обзор языка
  • 3. Java – Установка и настройка
  • 4. Java – Синтаксис
  • 5. Java – Классы и объекты
  • 6. Java – Конструкторы
  • 7. Java – Типы данных и литералы
  • 8. Java – Типы переменных
  • 9. Java – Модификаторы
  • 10. Java – Операторы
  • 11. Java – Циклы и операторы цикла
  • 11.1. Java – Цикл while
  • 11.2. Java – Цикл for
  • 11.3. Java – Улучшенный цикл for
  • 11.4. Java – Цикл do..while
  • 11.5. Java – Оператор break
  • 11.6. Java – Оператор continue
  • 12. Java – Операторы принятия решений
  • 12.1. Java – Оператор if
  • 12.2. Java – Оператор if..else
  • 12.3. Java – Вложенный оператор if
  • 12.4. Java – Оператор switch..case
  • 12.5. Java – Условный оператор (? 🙂
  • 13. Java – Числа
  • 13.1. Java – Методы byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()
  • 13.2. Java – Метод compareTo()
  • 13.3. Java – Метод equals()
  • 13.4. Java – Метод valueOf()
  • 13.5. Java – Метод toString()
  • 13.6. Java – Метод parseInt()
  • 13.7. Java – Метод Math.abs()
  • 13.8. Java – Метод Math.ceil()
  • 13.9. Java – Метод Math.floor()
  • 13.10. Java – Метод Math.rint()
  • 13.11. Java – Метод Math.round()
  • 13.12. Java – Метод Math.min()
  • 13.13. Java – Метод Math.max()
  • 13.14. Java – Метод Math.exp()
  • 13.15. Java – Метод Math.log()
  • 13.16. Java – Метод Math.pow()
  • 13.17. Java – Метод Math.sqrt()
  • 13.18. Java – Метод Math.sin()
  • 13.19. Java – Метод Math.cos()
  • 13.20. Java – Метод Math.tan()
  • 13.21. Java – Метод Math.asin()
  • 13.22. Java – Метод Math.acos()
  • 13.23. Java – Метод Math.atan()
  • 13.24. Java – Метод Math.atan2()
  • 13.25. Java – Метод Math.toDegrees()
  • 13.26. Java – Метод Math.toRadians()
  • 13.27. Java – Метод Math.random()
  • 14. Java – Символы
  • 14.1. Java – Метод Character.isLetter()
  • 14.2. Java – Метод Character.isDigit()
  • 14.3. Java – Метод Character.isWhitespace()
  • 14.4. Java – Метод Character.isUpperCase()
  • 14.5. Java – Метод Character.isLowerCase()
  • 14.6. Java – Метод Character.toUpperCase()
  • 14.7. Java – Метод Character.toLowerCase()
  • 14.8. Java – Метод Character.toString()
  • 15. Java – Строки
  • 15.1. Java – Метод charAt()
  • 15.2. Java – Метод compareTo()
  • 15.3. Java – Метод compareToIgnoreCase()
  • 15.4. Java – Метод concat()
  • 15.5. Java – Метод contentEquals()
  • 15.6. Java – Метод copyValueOf()
  • 15.7. Java – Метод endsWith()
  • 15.8. Java – Метод equals()
  • 15.9. Java – Метод equalsIgnoreCase()
  • 15.10. Java – Метод getBytes()
  • 15.11. Java – Метод getChars()
  • 15.12. Java – Метод hashCode()
  • 15.13. Java – Метод indexOf()
  • 15.14. Java – Метод intern()
  • 15.15. Java – Метод lastIndexOf()
  • 15.16. Java – Метод length()
  • 15.17. Java – Метод matches()
  • 15.18. Java – Метод regionMatches()
  • 15.19. Java – Метод replace()
  • 15.20. Java – Метод replaceAll()
  • 15.21. Java – Метод replaceFirst()
  • 15.22. Java – Метод split()
  • 15.23. Java – Метод startsWith()
  • 15.24. Java – Метод subSequence()
  • 15.25. Java – Метод substring()
  • 15.26. Java – Метод toCharArray()
  • 15.27. Java – Метод toLowerCase()
  • 15.28. Java – Метод toString()
  • 15.29. Java – Метод toUpperCase()
  • 15.30. Java – Метод trim()
  • 15.31. Java – Метод valueOf()
  • 15.32. Java – Классы StringBuilder и StringBuffer
  • 15.32.1. Java – Метод append()
  • 15.32.2. Java – Метод reverse()
  • 15.32.3. Java – Метод delete()
  • 15.32.4. Java – Метод insert()
  • 15.32.5. Java – Метод replace()
  • 16. Java – Массивы
  • 17. Java – Дата и время
  • 18. Java – Регулярные выражения
  • 19. Java – Методы
  • 20. Java – Потоки ввода/вывода, файлы и каталоги
  • 20.1. Java – Класс ByteArrayInputStream
  • 20.2. Java – Класс DataInputStream
  • 20.3. Java – Класс ByteArrayOutputStream
  • 20.4. Java – Класс DataOutputStream
  • 20.5. Java – Класс File
  • 20.6. Java – Класс FileReader
  • 20.7. Java – Класс FileWriter
  • 21. Java – Исключения
  • 21.1. Java – Встроенные исключения
  • 22. Java – Вложенные и внутренние классы
  • 23. Java – Наследование
  • 24. Java – Переопределение
  • 25. Java – Полиморфизм
  • 26. Java – Абстракция
  • 27. Java – Инкапсуляция
  • 28. Java – Интерфейсы
  • 29. Java – Пакеты
  • 30. Java – Структуры данных
  • 30.1. Java – Интерфейс Enumeration
  • 30.2. Java – Класс BitSet
  • 30.3. Java – Класс Vector
  • 30.4. Java – Класс Stack
  • 30.5. Java – Класс Dictionary
  • 30.6. Java – Класс Hashtable
  • 30.7. Java – Класс Properties
  • 31. Java – Коллекции
  • 31.1. Java – Интерфейс Collection
  • 31.2. Java – Интерфейс List
  • 31.3. Java – Интерфейс Set
  • 31.4. Java – Интерфейс SortedSet
  • 31.5. Java – Интерфейс Map
  • 31.6. Java – Интерфейс Map.Entry
  • 31.7. Java – Интерфейс SortedMap
  • 31.8. Java – Класс LinkedList
  • 31.9. Java – Класс ArrayList
  • 31.10. Java – Класс HashSet
  • 31.11. Java – Класс LinkedHashSet
  • 31.12. Java – Класс TreeSet
  • 31.13. Java – Класс HashMap
  • 31.14. Java – Класс TreeMap
  • 31.15. Java – Класс WeakHashMap
  • 31.16. Java – Класс LinkedHashMap
  • 31.17. Java – Класс IdentityHashMap
  • 31.18. Java – Алгоритмы Collection
  • 31.19. Java – Iterator и ListIterator
  • 31.20. Java – Comparator
  • 32. Java – Дженерики
  • 33. Java – Сериализация
  • 34. Java – Сеть
  • 34.1. Java – Обработка URL
  • 35. Java – Отправка Email
  • 36. Java – Многопоточность
  • 36.1. Java – Синхронизация потоков
  • 36.2. Java – Межпоточная связь
  • 36.3. Java – Взаимная блокировка потоков
  • 36.4. Java – Управление потоками
  • 37. Java – Основы работы с апплетами
  • 38. Java – Javadoc

Java. String: способы, примеры

Java. String: методы, примеры

Java String или строки в Java являются основными носителями текстовой информации, поэтому этот класс популярен и часто используется. В пакете Java.lang есть несколько классов для работы со строками — это StringBuffer и StringBuilder. Они объявлены как final — это говорит о том, что от этих классов невозможно наследоваться. Для того чтобы проверить это, откроем редактор и напишем слово string, а затем перейдем в сам класс. Здесь мы увидим, что он является final — это и означает отсутствие наследования.

Способы создания объектов

Объект класса Java String можно создать несколькими способами. Один из них — при помощи ключевого слова new и конструктора класса. Если нажать CTRL + P, то можно увидеть все эти конструкторы. Java String принимает строку, массив char, int, byte, а также объекты классов StringBuffer и StringBuilder. Второй способ для создания объекта — это прямое присвоение ссылки, заключенной в двойные кавычки.

java string сравнение строк

Классы StringBuilder, StringBuffer и их методы

Классы StringBuilder, StringBuffer очень похожи друг на друга и по предназначению близки к классу String. С помощью методов и конструкторов объекты этих классов можно преобразовывать друг в друга и в строку. Также у StringBuilder есть конструкторы, которые принимают строку и последовательность символов, поэтому строку можно преобразовывать в объекты. В обоих случаях есть метод ToString. Он не относится к классам StringBuilder и StringBuffer, а класса Object, с помощью которого их и можно привести к строке. Посмотреть все методы можно, если нажать CTRL + P. Основное отличие этих двух классов друг от друга заключается в том, что StringBuilder работает быстрее, но он не является потокобезопасным, в отличие от StringBuffer. Потокобезопасность — это способность кода функционировать сразу в нескольких потоках без блокировки.

java строка string

Особенности создания объекта у классов StringBuilder или StringBuffer

При создании объекта StringBuilder или StringBuffer конструктор по умолчанию автоматически резервирует некоторый объем памяти под 16 символов. Это можно проверить, используя один из них, метод Capacity и вывод в консоль. В результате будет выведен размер буфера — 16 символов. Можно нажать еще раз CTRL + P, и выбрать метод Int Capacity. То есть, в конструкторе мы может задать какой-то размер буфера. Также существует способ задать его позже. Для этого в StringBuilder выбираем метод Ensure Capacity. При помощи него мы можем задать минимальный гарантированный размер буфера. Если изменить его, например, на 20, а затем снова запустить консоль, мы получим 34. Все дело в том, что задать можно именно минимальный гарантированный размер, то есть, в любом случае, он не будет меньше 20. Но, если в этом классе есть в каком-то методе или конструкторе формула, по которой рассчитывается допустимая величина.

Присвоение значения строки объекту

Для того чтобы присвоить определенному объекту какое-то значение строки, необходимо это значение записать в конструктор или использовать один из методов Append. Их очень много, некоторые из этих методов могут принимать boolean, а затем преобразовывать его в строку и складывать, некоторые принимают char, массив, последовательности и т.д. В отличие от String, StringBuilder и StringBuffer, когда их методы используются, то мы продолжаем работать с этим же объектом, а не создаем новый.

java string длин

Отличия методов String и StringBuilder

При работе со строкой, если использовать какие-то методы, например, конкатенации или склеивания объектов, то в этом случае в результате создается новая строка. В этом можно убедиться при выводе в консоль. Как правило, классы StringBuilder и StringBuffer используются, когда очень часто идет сложение строк. Например, в цикле, где присутствует большой объем информации и постоянно происходит сложение строк, лучше использовать именно их. Это ускорит процесс работы, так как StringBuilder делает все быстрее, здесь не происходит постоянное создание нового объекта.

Метод SetLength

При сложении строк (при каждом сложении) будет создаваться новый объект. Если их более тысячи, то будет тратиться множество лишних ресурсов, а сам процесс займет много времени. Также у StringBuilder есть метод SetLength, где можно установить размер буфера. Например, если задать 15 и вывести результат в консоль, то получим число 20. Этот объект при достижении необходимого размера буфера автоматически увеличивается согласно заданной в этом методе формуле. Увеличение может происходить практически до определенного предела. Например, в методе Capacity максимальное число символов в объекте будет равно числу int.

Методы Insert и Delete

Следующий метод, наиболее часто используемый у StringBuilder, — это Insert. Он позволяет вставить символ в указанную позицию. У него также существует множество параметров. Еще один популярный метод — удаление символа из строки. Для выполнения этой операции нужно обратиться к Delete и выбрать какой-то его вариант из списка. Например, можно обратиться к подстроке от начального индекса до конечного или удалить символ, используя его индекс.

java сравнение string

Последний метод StringBuilder, который мы будем разбирать, — это Recerse или реверс. Его используют для переворота строки. Символы в ней будут выстраиваться в обратном порядке. Если выполнить его и вывести в консоль объект, то получим ее зеркальное отражение. В этом случае мы продолжаем работать с тем же объектом, новый при этом не создается. Просто в нем теперь хранится другая информация. У StringBuilder очень много методов, которые аналогичны тем, что есть у String. Работают они точно так же. Разницы между StringBuffer и StringBuilder по методам практически никакой, за исключением потокобезопасности StringBuffer. Из-за этой особенности он работает немного медленнее.

Методы класса String

Поговорим о методах класса Java String. Сначала рассмотрим их для объекта srt1 и str2, а затем — статические методы непосредственно самого класса String. Первый метод, который мы будем разбирать, — CharAt. Он принимает индекс и возвращает символ. В Java строки являются индексированными, то есть под каждым индексом лежит какой-то символ. Например, если создать объект Java, то “j” будет лежать под индексом “0”, “a” под индексом “1”, “v” — “2”, “a” — “3”. То есть, если записать в методе “0”, то он вернет символ, находящийся под нулевым индексом в этой строке. Проверить работу этого метода можно выводом в консоль и запуском приложения. В первом случае, мы увидим символ “j”. Если поменять “0” на “1”, то увидим символ “a”.

java string перенос строки

Метод CodepointAt

Следующий метод Java String, с которым мы познакомимся, — CodepointAt. Он возвращает int и принимает int-индекс. CodepointAt возвращает символ в кодировке Юникод по заданному индексу. То есть, если мы напишем индекс “1”, опять обращаясь к индексу строки и символу “a”, этот метод вернет нам число в кодировке Юникод соответствующее символу “a”. Если запустить приложение, мы увидим число 97. Например, если мы знаем, что индекс “A” соответствует числу 65 в кодировке Юникода. Тогда, при запуске, где в методе прописано такое значение, мы получим 65.

Сравнение строк в Java String

Еще один метод — compareTo. Он возвращает int, а принимает другую строку. В Java String сравнение строк между собой происходит при помощи этого метода. Он берет str1 и сравнивает ее с принимаемой строкой, лексически или лексикографически, с учетом регистра букв, то есть с учетом прописных и строчных букв. Если содержимое строк одинаковое, то мы должны получить при запуске приложения “0”, так как в процессе происходит вычитание символов. Поэтому, если содержимое разное, в ответе придет какое-то число, равное разности индексов.

string java примеры

Методы compareToIgnoreCase и Concat

Следующий метод, который мы будем разбирать, — это compareToIgnoreCase. Он похож на предыдущий, только здесь не учитывается регистр букв, то есть неважно, заглавная буква или прописная. В редакторе кода пишем str со значением Java и последнюю букву сделаем заглавной. И в результате мы все равно получаем 0. Мы получим другое значение, если будет какой-то другой символ. Теперь рассмотрим метод для строки Java String — Concat. Он предназначен для сложения, слияния или объединения двух строк. Concat аналогичен обычному сложению строк при помощи знака “+”.

Методы Equals и EqualsIgnoreCase

Метод Equals принимает другой объект типа Object. Но так как все наследуемые классы у нас имеют тип Object, значит, мы можем передать и строку. Возвращаемый тип у метода Equals — boolean, то есть наша строка сравнивается с другим объектом на равенство. Сравнивается содержимое двух объектов. То есть, если мы передадим строку str2, то, если ее содержимое не равно с объектом, мы получим ответ false, а если оно равно — то true. Есть также метод сравнения строк без учета регистра. Он называется — EqualsIgnoreCase. Он похож на compareTo и работает похожим образом. Возвращаемый тип здесь — boolean. В случае с compareTo в результате мы получаем разницу символов либо 0, если содержимое совпадает.

java string

Методы HashCode и IndexOf

Следующий метод — HashCode. Он возвращает хэш-код нашего объекта. Он есть у каждого объекта, и представляет собой число, точнее, битовую строку фиксированной длины. Получить его можно при помощи этого метода. Рассмотрим метод IndexOf. На самом деле их несколько, но мы будет рассматривать только один. Он принимает переменную ch — переменная в кодировке Юникод. То есть, если эта переменная совпадает с символом в строке, то возвращается индекс этого символа, если нет, то “-1”. Если наше число в кодировке Юникод есть в этой строке, то возвращается индекс этого символа. Если же нет такого символа, то возвращается “-1”.

Методы IsEmpty, Length, Split, Substring

Теперь разберем метод IsEmpty. Он возвращает true, если длина строки равна 0, то есть она является пустой. Следующий метод — Length. Он отвечает за число символов в строке, то есть возвращает длину Java String. Пробелы тоже являются символами. Метод Split принимает строку-разделитель и возвращает массив строк. Мы можем использовать литерал, помещенный в двойные кавычки, или строку. Когда метод встречает пробел, он делит строку и части распределяет в массив. В результате мы получим массив строк. Мы можем поместить в строку запятую, Split тоже разделит ее на части. Обратимся к методу Substring. Он извлекает из строки подстроку, длиной endindex-beginindex, начиная с последней позиции. Один из примеров Java String для этого метода: написать строку и задать для нее два индекса, тогда будет вырезана строка, и ее началом будет первый индекс, а окончанием — второй. В консоли будет выводиться определенная часть str1. Для переноса строки в Java String добавляется «\n».

Методы ToCharArray, ToLowerCase, ToUpperCase, Trim

Метод ToCharArray возвращает массив символов, то есть строка разбирается посимвольно. Если объявить какой-то char, а затем в метод поместить определенный элемент, то каждый символ окажется в массиве char. Затем каждый элемент массива выводится в консоль. Еще один метод — ToLowerCase. Он переводит строку в нижний регистр. Противоположным образом срабатывает ToUpperCase — он делает все буквы в строке заглавными. Очень часто используемый метод — Trim. Он обрезает пробелы в начале и в конце строки. Статических методов непосредственно самого класса очень много, потому что они принимают различные типы и массивы. Наиболее часто используемый — это ValueOf. Он преобразует переменную заданного типа в строку.

Маленькие тонкости java.lang.String

перебирая накопленный материал по java.lang.String решил сделать небольшую подборку примеров из эффективного (и не очень) использования.

Любое преобразование строки порождает новую строку

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

var str = "str";

Теперь этот код

jshell> var str = "str"; jshell> System.out.println(str.toLowerCase() == str);
true

Иными словами, здесь вызов toLowerCase() вернул строку, на которой он был вызван. И хотя это поведение не описано в документации, код StringLatin1.toLowerCase() не оставляет сомнений (здесь и далее приведён код из https://hg.openjdk.java.net/jdk/jdk/):

public static String toLowerCase(String str, byte[] value, Locale locale) < if (locale == null) < throw new NullPointerException(); >int first; final int len = value.length; // Now check if there are any characters that need to be changed for (first = 0 ; first < len; first++) < int cp = value[first] & 0xff; // no need to check Character.ERROR if (cp != CharacterDataLatin1.instance.toLowerCase(cp)) < break; >> if (first == len) return str; // 

В целом это поведение логично: зачем городить новую строку, если в исходной не произошло никаких изменений. Это же справедливо для прочих методов, меняющих строку лишь частично, например, String.trim() и String.strip() :

// обратите внимание: в отличии от strip() // для trim() явно прописан возврат this /** * * @return a string whose value is this string, with all leading * and trailing space removed, or this string if it * has no leading or trailing space. */ public String trim() < String ret = isLatin1() ? StringLatin1.trim(value) : StringUTF16.trim(value); return ret == null ? this : ret; >/** * @return a string whose value is this string, with all leading * and trailing white space removed * * @see Character#isWhitespace(int) * * @since 11 */ public String strip()

В данной связи иногда возникают разные нехорошие соблазны:

boolean isUpperCase = name.toUpperCase().equals(name);

По-хорошему это нужно переписать с использованием всяких StringUtils , которые познаково перебирают строку и проверяют регистр (соответствующая проверка есть в «Сонаре»). Но зачем тащить лишнюю зависимость/импорт в проект/класс, если мы уже знаем, что name.toUpperCase() вернёт name , когда вся строка в верхнем регистре? Вместо этого мы можем написать

boolean isUpperCase = name.toUpperCase() == name; //вредный совет

Однако, может получится так, что в следующей реализации String.toUpperCase() будет всегда возвращать новую строку и наш код поломается. Также этот код будет работать медленнее (иногда сильно, иногда не очень) чем o.a.c.l.StringUtils.isAllUpperCase() .

В общем же случае

boolean eq = aString.toUpperCase().equals(anotherString);
boolean eq = aString.equalsIgnoreCase(anotherString);

Возможно, что уже скоро «Идея» научится предупреждать нас об этом, а пока это делает «Сонар».

Ещё про String.toLowerCase()

Вообще String.toLowerCase() / String.toUpperCase() довольно интересный метод, а его поведение может быть весьма неожиданным. Возьмём этот код:

boolean isEmpty = someStr.toLowerCase().isEmpty();

он несколько искусственный, но имеет право на жизнь. Присмотревшись к нему становится понятно, что преобразование регистра избыточно для определения пустой/непустой строки. Если строка пуста, то мы получим её же на выходе и isEmpty() вернёт true . В противном случае вернётся false , т. к. для этого достаточно 1 знака в строке, а его регистр не важен.
Получается, что вместо кода выше можно написать:

boolean isEmpty = someStr.isEmpty();

и смысл выражения не изменится. Посмотрев же внутрь String.isEmpty() найдём там незамысловатую реализацию:

public boolean isEmpty()

Держа в уме описанное ранее преобразование может возникнуть соблазн превратить

int len = someStr.toLowerCase().length();
int len = someStr.length();

Не, ну а чё? Была у нас строка

String s = "Ку!";
String s = "ку!";

Длина вроде не изменилась, а значит преобразование хорошее, годное. Но это только на первый взгляд. На второй — не очень. Дело в том, что методы toLowerCase() / toUpperCase() можно вызывать как с явным указанием локали, так и без оной. Во втором случае берётся локаль по умолчанию, с некоторыми из которых возможны нюансы. Например, вот этот тест проходит:

@Test void toLowerCase() < String str = "\u00cc"; // Ì assert str.length() == 1; String strLowerCase = str.toLowerCase(new Locale("lt")); assert strLowerCase.length() == 3; // i̇̀ >

Когда запускаешь его впервые, то встаёт вопрос: «Это вообще как?» Была строка из 1 заглавной буквы, потом мы из неё сделали строчную букву и её размер утроился (в байтах — вырос вообще в 6 (!) раз). Но и это прописано в документации:

/** * Converts all of the characters in this to lower * case using the rules of the given . Case mapping is based * on the Unicode Standard version specified by the * class. Since case mappings are not always 1:1 char mappings, the resulting * may be a different length than the original . */ public String toLowerCase(Locale locale) < //. >

И реализовано в коде:

//StringLatin1 public static String toLowerCase(String str, byte[] value, Locale locale) < // . String lang = locale.getLanguage(); if (lang == "tr" || lang == "az" || lang == "lt") < // . return toLowerCaseEx(str, value, first, locale, true); >//. >

Так что утверждение о том, что длина строки зависит от регистра знаков не столь бредовое, каким кажется 🙂

Подстроки

В некоторых случаях взятие подстроки размером 1 — String.substring(n, n+1) — является бессмысленным, например, при сравнении с литералом, длина которого также равна 1. Иными словами код:

boolean startsWithUnderline = message.substring(0, 1).equals("_");

можно упростить до

boolean startsWithUnderline = message.charAt(0) == '_';

Второй вариант не только короче и проще для понимания, но ещё и позволяет обойтись без создания лишнего объекта. Это же упрощение справедливо для склеивания:

String s = "xxx" + name.substring(n, n + 1);

можно превратить в

String s = "xxx" + name.charAt(n);

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

Ещё один интересный случай — это выделение подстроки фиксированной длины и сравнение её с постоянной:

boolean startsWithUrl = content.substring(index, index + 4).equals("url(");

Это выражение можно превратить в

boolean startsWithUrl = content.startsWith("url(", index);

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

private String findPerClause(String str)

Данный метод более громоздкий и требует чуть больше времени, чтобы в него вчитаться, но логика в нём довольно простая:

из строки(остаётся только то, что в скобках) --> остаётся только то, что в скобках

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

private String findPerClause(String str)

Помните, что далеко не всякое выделение подстроки можно выбросить из кода:

int idx = path.substring(2).indexOf('/');

Может показаться, что раз существует перегруженный метод String.indexOf(int ch, int fromIndex) , то можно превратить код выше в такой:

int idx = path.indexOf('/', 2);

избавившись от выделения подстроки. На деле такое преобразование верно только тогда, когда ‘/’ точно найден в строке и от индекса мы отняли 2, т. к. отсчёт теперь ведётся не с начала строки:

int idx = name.indexOf('/', 2); if (pos != -1)

В итоге код получается более громоздким, что делает замену целесообразной только в очень горячих местах.

Закончим раздел небольшим улучшением в JDK. Дело в том, что

someStr.substring(n, n);

возвращает всегда пустую строку при условии, что n не выходит за границы допустимого:

// String public String substring(int beginIndex, int endIndex) < int length = length(); checkBoundsBeginEnd(beginIndex, endIndex, length); int subLen = endIndex - beginIndex; if (beginIndex == 0 && endIndex == length) < return this; >return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen) : StringUTF16.newString(value, beginIndex, subLen); > // StringLatin1 public static String newString(byte[] val, int index, int len)

При равных значениях beginIndex и endIndex переменная subLen будет равна 0, а метод StringLatin1.newString() вернёт пустую строку. Получается, что код можно переписать вот так:

// StringLatin1 public static String newString(byte[] val, int index, int len) < if (len == 0) < return ""; >return new String(Arrays.copyOfRange(val, index, index + len), LATIN1); >

Это позволит не выделять доппамять и одновременно упростить методы StringLatin1.stripLeading() / stripTrailing() и их двойников в StringUTF16 . Все изменения по ссылке.

С последними методами есть нюанс, а именно изменение поведения для пустого массива:

// в StringLatin1 сейчас так public static String stripLeading(byte[] value) < int left = indexOfNonWhitespace(value); if (left == value.length) < return ""; >return (left != 0) ? newString(value, left, value.length - left) : null; >

При value.length == 0 этот код вернёт пустую строку. Так как проверка left == value.length переезжает в newString , то теперь для описанного случая изменённый код

public static String stripLeading(byte[] value)

будет возвращать null ! Проследив исполнение до String.stripLeading() вроде как можно выдохнуть, ведь в этом случае вернётся this , что в нашем случае пустая строка. Повезло, пользователь не заметит разницы. Но пришла беда откуда не ждали:

// до boolean b= new String("").stripLeading() == ""; // true // после boolean b= new String("").stripLeading() == ""; // false !

Чёрт, неужели всё пропало?

Не спешите, подумайте 🙂

From a compatibility point of view I think this should be fine, as
the identity of the returned empty string isn’t specified.

Хорошо курочить стандартную библиотеку!

Проверяем, есть ли толк от изменений:

@Warmup(iterations = 10, time = 1) @Measurement(iterations = 10, time = 1) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Fork(value = 3, jvmArgsAppend = ) public class SubstringBenchmark < private static final String str = "Tolstoy"; @Benchmark public String substring() < return str.substring(1, 1); >>

Что даёт следующие цифры:

до Mode Score Error Units substring avgt 5.8 ± 0.066 ns/op substring:·gc.alloc.rate avgt 4325.9 ± 47.259 MB/sec substring:·gc.alloc.rate.norm avgt 40.0 ± 0.001 B/op substring:·gc.churn.G1_Eden_Space avgt 4338.8 ± 86.555 MB/sec substring:·gc.churn.G1_Eden_Space.norm avgt 40.1 ± 0.647 B/op substring:·gc.churn.G1_Survivor_Space avgt 0.0 ± 0.003 MB/sec substring:·gc.churn.G1_Survivor_Space.norm avgt ≈ 10⁻⁴ B/op substring:·gc.count avgt 557.0 counts substring:·gc.time avgt 387.0 ms после substring avgt 2.4 ± 0.172 ns/op substring:·gc.alloc.rate avgt 0.0 ± 0.001 MB/sec substring:·gc.alloc.rate.norm avgt ≈ 10⁻⁵ B/op substring:·gc.count avgt ≈ 0 counts

Конечно, String.substring(n, n) будет выполнятся нечасто, но прирост есть и для такого копеечного изменения он неплох.

Когда нужно помнить про основное правило

Несмотря на то, что заметку я начал с развенчания мифа о строках, о цене их преобразования нужно помнить, особенно в циклах и особенно тогда, когда раз за разом воспроизводится одна и та же строка. Например, это код раньше жил в спринговом AnnotationMetadataReadingVisitor-е:

MultiValueMap getAllAnnotationAttributes(String annotationName, boolean classValAsStr) < // . String annotatedElement = "class '" + getClassName() + "'"; for (AnnotationAttributes raw : attributes) < for (Map.Entryentry : convertClassValues( "class '" + getClassName() + "'", classLoader, raw, classValAsStr).entrySet()) < allAttributes.add(entry.getKey(), entry.getValue()); >> return allAttributes; >

Выражение «class ‘» + getClassName() + «‘» будет одним и тем же и нам совсем не хочется в двойном цикле создавать одну и ту же строку, поэтому её лучше создать 1 раз за пределами цикла. Раньше отлов таких примеров был делом случая: этот я нашел удачно провалившись внутрь исходников во время отладки своего приложения. Теперь благодаря IDEA-230889 это можно автоматизировать. Разумеется, далеко не всегда создание новой строки в цикле независимо от прохода, но даже в этих случаях можно выделить те, в которых есть некая выносимая постоянная часть:

// org.springframework.beans.factory.support.BeanDefinitionReaderUtils public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) < String int counter = -1; // Increase counter until the id is unique. while (counter == -1 || registry.containsBeanDefinition(id)) < counter++; + GENERATED_BEAN_NAME_SEPARATOR + counter; >return id; >

Тут префикс beanName + GENERATED_BEAN_NAME_SEPARATOR всегда один и тот же, поэтому может быть вынесен наружу.

На этом всё, пишите свои примеры в комментариях — обмозгуем.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *