Общие строковые операции в Java

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

Вступление

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

Нить

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

Хотя, если вы хотите узнать больше о различных способах создания строк в Java, вам следует проверить String vs StringBuilder vs StringBuffer .

Здесь мы предполагаем, что вы знакомы с тем фактом, что String неизменяемы , так как это очень важно знать, прежде чем обрабатывать их. Если нет, обратитесь к ранее связанной статье, где это подробно объясняется.

Класс String имеет множество вспомогательных методов, которые помогают нам обрабатывать наши текстовые данные:

Конкатенация строк

Прежде чем мы начнем использовать какой-либо из этих методов для строк, мы должны взглянуть на конкатенацию строк, поскольку это довольно распространенная вещь. Начнем с оператора + Класс String перегружает этот оператор и используется для объединения двух строк:

 String aplusb = "a" + "b"; 
 
 // The operands can be String object reference variables as well 
 String a = "a"; 
 String b = "b"; 
 aplusb = a + b; 

Оператор + работает очень медленно. String неизменяемы, поэтому каждый раз, когда мы хотим объединить n строк, Java должна копировать символы из всех строк в новый объект String Это дает нам квадратичную (O (n ^ 2)) сложность.

Это не проблема с небольшими строками или когда мы объединяем сразу несколько строк ( String abcd = "a" + "b" + "c" + "d"; ). Java автоматически использует StringBuilder для объединения нескольких строк одновременно, поэтому причиной потери производительности является объединение в циклы. Обычно для чего-то подобного мы использовали вышеупомянутый класс StringBuilder

Он работает как изменяемый объект String Он обходит все копирование при конкатенации строк и дает нам линейную (O (n)) сложность.

 int n = 1000; 
 
 // Not a good idea! Gives the right result, but performs poorly. 
 String result = ""; 
 for (int i = 0; i < n; i++) { 
 result += Integer.valueOf(i); 
 } 
 
 // Better, performance-friendly version. 
 StringBuilder sb = new StringBuilder(""); 
 for (int i = 0; i < n; i++) { 
 sb.append(i); 
 } 

Мы также можем объединить с помощью метода concat()

 String str1 = "Hello"; 
 System.out.println(str1.concat("World")); 

Выход:

 Hello World 

Примечание . При использовании конкатенации строк с другими типами данных они неявно преобразуются в их строковое представление:

 System.out.println("2 = " + 2); 

Это дает ожидаемый результат «2 = 2».

 System.out.println("2 = " + 1 + 1); 

В обычных обстоятельствах 1+1 , поскольку Java обрабатывает операции справа налево. Однако на этот раз этого не произойдет - результат будет «2 = 11». Это происходит из-за того, что называется «приоритетом оператора».

По сути, когда встречаются два или более операторов «+» (без других операторов и скобок), Java начинается с самого левого оператора «+» и продолжается оттуда. Если мы хотим, чтобы результат снова был «2 = 2», нам нужно было бы добавить круглые скобки в соответствующее место.

 System.out.println("2 = " + (1 + 1)); 

С другой стороны, если мы попытаемся использовать метод concat() с другим типом данных:

 String str1 = "Hello"; 
 System.out.println(str1.concat(53)); 

Нас встретят с исключением:

 incompatible types: int cannot be converted to String 

При использовании + Java автоматически преобразует тип данных в String, тогда как при использовании метода concat() этого не происходит.

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

 // Instead of this... 
 String ourString = "this is just some string"; 
 System.out.println(ourString.substring(5,10)); 
 
 // ...we can do this: 
 System.out.println("this is just some string".substring(5,10)); 

На самом деле, любой способ хорош, но второй способ дает меньше кода.

Определить длину строки

length() возвращает общее количество символов в нашей String .

isEmpty() возвращает true или false зависимости от того String или нет. Это означает, что isEmpty() возвращает true для того же случая, когда length() возвращает 0.

Например:

 if (s.length() == 0) // or s.isEmpty() { 
 System.out.println("s is empty"); 
 } 
 else System.out.println("s isn't empty, it's: " + s + "\n"); 

Здесь мы покажем, как вы можете использовать эти методы для проверки наличия пустой строки. Условную проверку можно также заменить на s.isEmpty() и она будет работать точно так же.

Поиск символов и подстрок

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

charAt(int index) возвращает значение символа по заданному индексу.

indexOf() перегружен и поэтому имеет несколько применений:

  • indexOf(int ch) возвращает первую позицию индекса, которая соответствует заданному значению символа
  • indexOf(int ch, int fromIndex) возвращает первый индекс, который соответствует заданному значению символа ПОСЛЕ fromIndex
  • indexOf(String substring) возвращает (первую) начальную позицию substring в String она была вызвана
  • indexOf(String substring, int fromIndex) же, что и в предыдущем методе, но поиск начинается с fromIndex вместо 0

Все перегруженные indexOf() возвращают -1, если индекс не был найден.

lastIndexOf() также перегружен и имеет эквивалентные сигнатуры метода indexOf() , а также возвращает -1, если соответствующий индекс не был найден. Он ищет String обратном направлении, если не указан fromIndex

Индекс, переданный методу, должен быть в пределах диапазона [0, example.length() - 1] чтобы быть действительным. В противном случае создается StringIndexOutOfBoundsException .

 String example = "This should be complicated enough to show some things we should show"; 
 
 // Find the characters at the indexes given 
 System.out.println(example.charAt(0)); 
 System.out.println(example.charAt(5)); 
 
 // An StringIndexOutOfBoundsException is thrown in both these cases: 
 // System.out.println(example.charAt(-1)); 
 // System.out.println(example.charAt(200)); 
 
 // Find the index of characters or substrings 
 System.out.println(example.indexOf('s')); // returns the first occurence of 's' 
 System.out.println(example.indexOf('s', 4)); // the first 's' after index 4 
 System.out.println(example.indexOf("should")); // the index of the first "should" in our string 
 System.out.println(example.indexOf("should", 15)); // the index of the first "should" in our 
 // string _after_ index 15 
 
 // Find the last index of characters or substrings 
 System.out.println(example.lastIndexOf('s')); // returns the first occurence of 's' when we look backwards from the end of the string 
 System.out.println(example.lastIndexOf('s', 45)); // searches for 's' backwards from the position 45 
 System.out.println(example.lastIndexOf("should")); // returns the position at which the substring 'should' appears, looking backwards from the end of the string 
 System.out.println(example.lastIndexOf("should", 20)); // finds substring 'should' from position 20 backwards, and returns the position at which it begins 

Это выведет следующее:

 T 
 s 
 3 
 5 
 5 
 57 
 64 
 42 
 57 
 5 

Примечание : indexOf(int ch, int fromIndex) часто используется в циклах, когда мы хотим что-то делать для каждого вхождения символа в String .

 int foundAt = -1; 
 String example = "This should be complicated enough to show some things we should show"; 
 while (true) { 
 foundAt = example.indexOf('s', foundAt + 1); 
 if (foundAt == -1) 
 break; 
 else { 
 // do something with that information 
 } 
 } 

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

Метод compareTo() лексикографически сравнивает нашу String с другой. Фактическое сравнение двух строк основано на значении Unicode каждого символа в строке. Метод возвращает либо положительное число, либо отрицательное число, либо 0.

Если бы все символы в нашей строке были полностью строчными (или полностью прописными) буквами, возвращаемое значение метода compareTo() можно интерпретировать как «если бы возвращаемое значение было отрицательным, моя строка была бы перед другой строкой в словаре» .

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

Метод compareTo() не перебирает все символы в наших строках, он возвращается, как только достигает конца любой из строк или как только он находит несовпадающий символ. В этом случае функция возвращает (значение Unicode несовпадающего символа в нашей строке) - (значение Unicode несовпадающего символа в данной строке) .

Для всех, кому интересно - ASCII является частью Unicode. Это означает, что az и AZ находятся в том же порядке, что и в кодировке ASCII, то есть все они идут один за другим в своих соответствующих случаях. А именно, az - это коды между 97-122 и AZ 65-90 . Таким образом, значение «a» - 97, значение «b» - 98 и так далее. Таким образом, когда мы вычитаем значение Unicode для «b» из «a», мы получаем -1. Это означает, что «а» - это одна буква перед «б», что и есть.

 System.out.println("a".compareTo("a")); 
 System.out.println("a".compareTo("b")); 
 System.out.println("1".compareTo("12345678")); 
 System.out.println("2".compareTo("12345678")); 
 System.out.println("abcd".compareTo("abgggggggggg")); 

 0 
 -1 
 -7 
 1 
 -4 

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

И в последней строке мы видим, что -4 печатается из-за 'c' - 'g' , поскольку это первое обнаруженное несоответствие, а все остальное не заботит.

Примечание . «Неожиданная» часть при использовании compareTo() происходит, когда мы сравниваем строки с разными регистрами.

 System.out.println("ORANGE".compareTo("apple")); 

Мы могли бы ожидать, что метод вернет положительное значение, поскольку «яблоко» должно стоять перед «ОРАНЖЕВЫМ». Однако значение Unicode для «O» меньше, чем значение Unicode для «a».

Иногда это может быть предпочтительным поведением, но если это не так, мы используем compareToIgnoreCase() . Этот метод, по сути, делает то же самое, что и compareTo() , он просто делает вид, что все в одном регистре, и дает нам «правильный» порядок словаря.

Примечание : compareTo() и compareToIgnoreCase() часто используются, когда мы создаем Comparator для настраиваемого класса.

Например, предположим, что у нас есть Person подобный следующему:

 class Person { 
 String firstName; 
 String lastName; 
 // ... 
 } 

Теперь предположим, что у нас есть список ArrayList называемый «people» из множества Person , без определенного порядка. Мы хотели бы отсортировать этот ArrayList так, чтобы они были упорядочены в лексикографическом порядке на основе их фамилий, и если у людей одинаковая фамилия, мы хотели бы отсортировать их на основе их имени.

 Comparator<Person> personComparator = new Comparator<Person>() { 
 @Override 
 public int compare(Person p1, Person p2) { 
 if (p1.firstName.compareTo(p2.firstName) != 0) { 
 return p1.firstName.compareTo(p2.firstName); 
 } 
 else return p1.lastName.compareTo(p2.lastName); 
 } 
 }; 
 Collections.sort(people, personComparator); 

Извлечение подстрок

«Подстрока» - это подмножество (или часть) другой строки. Метод substring() возвращает новую строку, которая является подстрокой строки, в которой мы используем метод.

Другими словами, если нам нужна новая строка, содержащая первые три символа нашей строки, мы должны использовать ourString.substring(0, 3) .

У substring() есть два варианта:

  • substring(int startIndex) возвращает String содержащую все символы от startIndex (включительно) до конца нашей String . Он ведет себя так же, как substring(int startIndex, ourString.length()) .
  • substring(int startIndex, int endIndex) возвращает String содержащую все символы от startIndex (включительно) до endIndex (исключая, т.е. символ в endIndex не возвращается)

Примечание . Указанные индексы должны по-прежнему находиться в интервале [0, ourString.length()-1] . Java, в отличие от некоторых других языков, НЕ поддерживает отрицательные индексы в методе substring() Java выдаст StringIndexOutOfBoundsException по любой из следующих причин:

  • startIndex отрицательный
  • endIndex больше, чем длина нашего объекта String
  • startIndex больше endIndex

Хотя в документации прямо не говорится, что «отрицательные значения вообще не допускаются» (у кого-то может быть привычка давать -1 в качестве endIndex из других языков программирования), это правило может быть выведено из того факта, что startIndex не может быть отрицательным, и этот endIndex должен быть больше startIndex .

Однако Java просто заставляет нас сделать дополнительный шаг и написать ourString.length() - someNumber как endIndex вместо просто - someNumber .

 String ourString = "abcdef"; 
 System.out.println(ourString.substring(0,3)); 
 System.out.println(ourString.substring(2)); 
 System.out.println(ourString.substring(1,3)); 
 
 // If we want the last few characters 
 System.out.println(ourString.substring(ourString.length()-3)); 

 abc 
 cdef 
 bc 
 def 

Изменение регистра строки

Эти два простых метода используются для изменения регистра символов в строке.

  • toLowerCase() : заменяет все символы верхнего регистра на нижний регистр (игнорирует все остальное)
  • toUpperCase() : заменяет все символы нижнего регистра на верхний регистр (игнорирует все остальное)
1
<!-- -->
 String ourString = "ThInK oF a ClEvEr StRiNg"; 
 
 System.out.println(ourString.toLowerCase()); 
 System.out.println(ourString.toUpperCase()); 
 System.out.println(ourString); 

Это выведет следующее:

 think of a clever string 
 THINK OF A CLEVER STRING 
 ThInK oF a ClEvEr StRiNg 

Обратите внимание, что сам исходный String не изменился.

Удаление пробелов

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

 String ourString = " Any non-leading and non-trailing whitespace is \n preserved "; 
 System.out.println(ourString.trim()); 

Выход:

 Any non-leading and non-trailing whitespace is 
 preserved 

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

Очень распространенное использование trim() с пользовательским вводом

  • проверка того, были ли введены вообще какие-либо непробельные символы:

    // Usually we check for empty inputs like this: if (userinput.isEmpty()) { … } // …or the equivalent if (userinput.length() != 0) { … }

    // But a better way to check would be this, which // handles cases where the user entered only // whitespace (ie " “) if (userinput.trim().isEmpty()) { … }

Форматирование строк

Метод format() возвращает отформатированную строку с заданным форматом и аргументами. Он используется, чтобы упростить жизнь при форматировании сложных строк в Java. Он работает аналогично printf в C:

 public static String format(String form, Object... args) 

Объявление этого метода может показаться сложным, но давайте рассмотрим его подробнее:

  • Для наших целей static часть означает, что этот метод вызывается через String , а не через объект класса String Это означает, что когда мы хотим использовать этот метод, мы должны писать String.format(...) а не ourString.format(...) . Мы можем вызвать метод вторым способом, но ourString случае не будет играть роль в методе.
  • Символ ... (три точки) после Object просто говорит о том, что здесь может быть передано переменное количество аргументов. Один, два или пятьдесят, все зависит от String form .

Начнем с простого примера.

 int a = 2; 
 int b = 3; 
 int c = 4; 
 int d = 1; 
 
 // %d indicates we want to print an integer 
 System.out.println(String.format("%d", a)); 

 2 

Метод format() просматривает form ищет специальные символы и заменяет их аргументами в args .

Специальные символы начинаются с % . В нашем примере мы использовали %d , что Java понимает как «Я попробую проанализировать предоставленный аргумент в args как целое число».

Чуть более информативный пример того, когда может быть полезен format()

 // Very messy, hard to read, and hard to maintain 
 System.out.println("a = " + a + "\n" + "b = " + b + "\n" + "c = " + c + "\n" + "d = " + d + "\n"); 
 
 // Much prettier 
 System.out.println(String.format("a = %d \nb = %d \nc = %d \nd = %d", a, b, c, d)); 

Как мы видим в этом примере, Java % с аргументами. Это означает, что когда он видит первый %d он сопоставляет его с a , второй %d с b и так далее.

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

  • %d : целые типы (byte, short, int, long, BigInteger)
  • %s : строки
  • %f : для числа с float в виде десятичного числа, %e отформатирован как десятичное число в компьютеризированной научной записи, а %g выводит то же самое, что и %f или %e зависимости от значения точности после округления.
  • %b : для Boolean значений. Если значение равно null , печатается "false".

Вообще говоря, метод format() имеет на вид сложный синтаксис:

 %[argument_index$][flags][width][.precision]conversion 

argument_index , flags , width и precision являются необязательными, как указано [] .

Точность может означать разные вещи для разных типов данных. Для чисел с плавающей запятой / двойным числом точность имеет очевидное значение: «сколько цифр я должен показать после десятичной точки». Помимо этого, точность определяет максимальное количество символов, которое будет записано на выходе.

 double ourDouble = 1123.9303; 
 System.out.println(String.format("%f", ourDouble)); 
 System.out.println(String.format("%.3f", ourDouble)); // specifies that we only want 3 digits after decimal point 
 System.out.println(String.format("%e", ourDouble)); 
 
 String ourString = "what does precision do with strings?"; 
 System.out.println(String.format("%.8s", ourString)); // prints the first 8 characters of our string 
 
 int ourInt = 123456789; 
 // System.out.println(String.format("%.4d", ourInt)); // precision can't be used on ints 

Это выведет:

 1123.930300 
 1123.930 
 1.123930e+03 
 what doe 

Необязательная width указывает минимальную ширину вывода.

 // If our number has less than 6 digits, this will 
 // add extra 0s to the beginning until it does 
 System.out.println(String.format("%06d", 12)); 
 
 // If our number has more than 6 digits, it will just print it out 
 System.out.println(String.format("%06d", 1234567)); 
 
 // We can specify output width, with the output being aligned 
 // to the right if it's shorter than the given space. If it's 
 // longer, everything gets printed. The || are added for 
 // demonstration purposes only 
 System.out.println(String.format("|%20d|", 12)); 
 // Or we can align the output to the left 
 System.out.println(String.format("|%-20d|", 12)); 
 
 // We can also easily print an octal/hexadecimal value of an integer 
 System.out.println(String.format("Octal: %o, Hex: %x", 10, 10)); 

Запуск этого кода приведет к следующему:

 000012 
 1234567 
 | 12| 
 |12 | 
 Octal: 12, Hex: a 

Регулярное выражение и проверка подстрок

contains(CharSequence s) возвращает true если s является частью нашего String объекта ( s может быть String сама или StringBuilder объект, или на самом деле все , что орудия CharSequence ), в противном случае она возвращает false .

startsWith(String prefix) возвращает true если наш String буквально начинается с данного prefix , в противном случае он возвращает false .

endsWith(String suffix) возвращает true если наш String буквально заканчивается заданным suffix , в противном случае он возвращает false .

matches(String regex) возвращает true если вся наша String соответствует заданному регулярному выражению .

Все эти методы довольно просты. Хотя matches() предполагает знание регулярных выражений.

 String ourString = "This string contains a contains."; 
 
 System.out.println(ourString.contains("contains")); 
 System.out.println(ourString.startsWith("T")); 
 System.out.println(ourString.endsWith(":)")); 
 System.out.println(ourString.matches(".*string.*")); 

Эти операции выводят следующее:

 true 
 true 
 false 
 true 

Замена символов и подстрок

replace(char oldChar, char newChar) заменяет все вхождения oldChar на newChar .

replace(CharSequence target, CharSequence replacement) заменяет все вхождения target строки replacement строкой (что означает, что мы можем заменять целые подстроки, а не только символы).

replaceAll(String regex, String replacement) заменяет все подстроки, которые соответствуют аргументу regex строкой replacement

replaceFirst(String regex, String replacement) заменяет только первую подстроку, которая соответствует аргументу regex строкой replacement

Чтобы избежать путаницы, replace() также заменяет ВСЕ вхождения последовательности символов, даже если существует метод с именем replaceAll() . Разница в том, что replaceAll() и replaceFirst() используют регулярное выражение для поиска последовательностей символов, которые необходимо заменить.

 String ourString = "We really don't like the letter e here"; 
 
 System.out.println(ourString.replace('e', 'a')); 
 System.out.println(ourString.replace("here", "there")); 
 System.out.println(ourString.replaceAll("e(r+)", "a")); 
 System.out.println(ourString.replaceFirst("e(r+)", "a")); 

 Wa raally don't lika tha lattar a hara 
 We really don't like the letter e there 
 We really don't like the letta e hae 
 We really don't like the letta e here, only the first occurrence was replaced 

Разделение и соединение строк

Методы split() и join() - две стороны одной медали.

split(String regex) разбивает эту строку с использованием заданного регулярного выражения и возвращает массив символов.

split(String regex, int limit) похож на предыдущий метод, но разбивает только limit количество раз.

join(CharSequence delimiter, CharSequence... elements) с другой стороны, возвращает String содержащую все перечисленные нами elements delimiter .

join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

  • это очень сложный способ сказать, что мы можем использовать join() для таких вещей, как списки, чтобы объединить все элементы в String с использованием заданного delimiter .

    String ourString = “apples, oranges, pears, pineapples”; String[] fruits = ourString.split(”,");

    System.out.println(Arrays.toString(fruits));

    // This is a great place to use the aforementioned trim() method // to remove the space at the beginning of some of the words for(int i = 0; i < fruits.length; i++) { fruits[i] = fruits[i].trim(); }

    System.out.println(Arrays.toString(fruits)); // Arrays.toString() formats the output array on its own

    [apples, oranges, pears, pineapples] [apples, oranges, pears, pineapples]

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

Поскольку эти символы являются общими (особая проблема - ".", Поскольку это означает "любой символ" в регулярном выражении), безопасный способ использования split() - с Pattern.quote(".") гарантирует, что ничто не понимается как специальный символ регулярного выражения.

 String ourString = "apples.oranges.pears.pineapples"; 
 
 // This returns then prints an empty array, since every 
 // character is interpreted as something to be split at 
 // and ignored 
 System.out.println(Arrays.toString(ourString.split("."))); 
 
 // The "regex safe" way of doing this would be 
 System.out.println(Arrays.toString(ourString.split(Pattern.quote(".")))); 
 
 // Splits our string to two substrings at most, 
 // completely ignoring all other occurrences of "." 
 System.out.println(Arrays.toString(ourString.split(Pattern.quote("."), 2))); 

 [] 
 [apples, oranges, pears, pineapples] 
 [apples, oranges.pears.pineapples] 

join() делает полную противоположность split() . Мы используем join() когда у нас есть массив / список / и т. Д. строк (или StringBuilders / StringBuffers ), которые мы хотим сформировать в одну новую String используя какой-либо (или не используя) разделитель.

 // A common use is to avoid repetitive concatenation, 
 // ie "1" + "," + "2" + "," + "3" + "," + "4" 
 System.out.println(String.join(",", "1", "2", "3", "4")); 
 
 // We can pass an array or any class that implements 
 // Iterable (containing character sequences) as the 
 // second parameter as well 
 String arrayOfStrings[] = {"1","2","3","4","5"}; 
 
 System.out.println(String.join("-", arrayOfStrings)); 
 System.out.println(String.join("-", Arrays.asList(arrayOfStrings))); // Works just fine with lists as well 
 
 // Join them with an empty string to convert an array 
 // of Strings to one single String without any extra data 
 System.out.println(String.join("", arrayOfStrings)); 

 1,2,3,4 
 1-2-3-4-5 
 1-2-3-4-5 
 12345 

Создание массивов символов

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

toCharArray() прямая подпись метода.

 String ourString = "These will all become separate characters"; 
 
 System.out.println(Arrays.toString(ourString.toCharArray())); 

Это распечатает следующее:

 [T, h, e, s, e, , w, i, l, l, , a, l, l, , b, e, c, o, m, e, , s, e, p, a, r, a, t, e, , c, h, a, r, a, c, t, e, r, s] 

Строковое равенство

equals(Object str) сравнивает две строки и возвращает true если строки содержат одинаковые символы в том же порядке, и false противном случае. При сравнении equalsIgnoreCase() для сравнения без учета регистра).

Важно понимать, что equals() и == выполняют две разные операции. equals() сравнивает символы внутри String , как упоминалось ранее, а == сравнивает равенство ссылок на объекты, чтобы увидеть, относятся ли они к одному и тому же экземпляру. В то время как такие операторы, как 1 == 1 , вернут истинную "string" == "string" возможно, нет.

Сложность здесь в том, что вывод == зависит от того, как мы инициализировали сравниваемые объекты String

 String s1 = "Just a String"; 
 String s2 = "Just a String"; 
 
 System.out.println(s1 == s2); 
 System.out.println(s1.equals(s2)); 
 
 s2 = new String("Just a String"); 
 System.out.println(s1 == s2); 
 System.out.println(s1.equals(s2)); 

 true 
 true 
 false 
 true 

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

Заключение

Важно понимать нюансы использования String и String методов в Java. Незаметные, трудно обнаруживаемые ошибки могут возникать с такими вещами, как split() и regex, или из-за ошибочного использования == когда мы хотели использовать equals() .

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

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus