Reverse string в java: учимся реверсировать строки разными способами

Преобразования данных

Последнее обновление: 1.11.2015

Нередко возникает необходимость преобразовать одни данные в другие. Например:


var number1 = "46";
var number2 = "4";
var result = number1 + number2;
console.log(result); //464

Обе переменных представляют строки, а точнее строковые представления чисел. И в итоге мы получим не число 50, а строку 464. Но было бы неплохо, если бы их тоже можно было бы складывать, вычитать, в общем работать как с обычными числами.

В этом случае мы можем использовать операции преобразования. Для преобразования строки в число применяется функция parseInt():

var number1 = "46";
var number2 = "4";
var result = parseInt(number1) + parseInt(number2);
console.log(result); // 50

Для преобразования строк в дробные числа применяется функция parseFloat():

var number1 = "46.07";
var number2 = "4.98";
var result = parseFloat(number1) + parseFloat(number2);
console.log(result); //51.05

При этом строка может иметь смешанное содержимое, например, «123hello», то есть в данном случае есть цифры, но есть и обычные символы. Но метод все равно попытается выполнить преобразование:

var num1 = "123hello";
var num2 = parseInt(num1);
console.log(num2); // 123

Если методу не удастся выполнить преобразование, то он возвращает значение NaN (Not a Number), которое говорит о том, что строка не представляет число и не может быть преобразована.

С помощью специальной функции isNaN() можно проверить, представляет ли строка число. Если строка не является числом, то функция возвращает true, если это число — то false:

var num1 = "javascript";
var num2 = "22";
var result = isNaN(num1);
console.log(result); // true - num1 не является числом
	
result = isNaN(num2);
console.log(result); //  false - num2 - это число

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

var num1 = "110";
var num2 = parseInt(num1, 2);
console.log(num2); // 6

Результатом будет 6, так как 110 в двоичной системе — это число 6 в десятичной.

Теперь напишем небольшую программу, в которой используем операции с переменными:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<title>JavaScript</title>
</head>
<body>
<script>
	var strSum = prompt("Введите сумму вклада", 1000);
	var strPercent = prompt("Введите процентную ставку", 10);
	var sum = parseInt(strSum);
	var procent = parseInt(strPercent);
	sum = sum + sum * procent / 100;
	alert("После начисления процентов сумма вклада составит: " + sum);
</script>
</body>
</html>

С помощью функции prompt() в браузере выводится диалоговое окно с предложением ввести некоторое значение. Второй аргумент в этой функции указывает на значение, которое будет использоваться по умолчанию.

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

После открытия страницы в браузере мы увидим приглашение к вводу суммы вклада:

Затем подобное сообщение отобразится и для ввода процента. И в конце программа получит данные, преобразует их в числа и выполнит подсчет:

НазадВперед

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

Все объекты наследуют два метода преобразования: и .

Метод возвращает строковое представление объекта. По умолчанию он ничего интересного не возвращает:

alert({x: 1}.toString());   // ""

Некоторые типы имеют более специализированные версии метода . Например, метод у массива преобразует все его элементы в строки и затем объединяет их в одну строку, вставляя запятые между ними:

alert(.toString());   // "1,2,3"

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

alert(typeof {x:2}.valueOf());   // "object"

При преобразовании объекта в строку интерпретатор JavaScript выполняет следующие действия:

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

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

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

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

var obj = {};
obj.toString = function() { return "объект"; };
alert("Это " + obj);   // "Это объект"

С этой темой смотрят:

  • Типы данных
  • Числа
  • Infinity и NaN
  • Строки
  • Boolean

Численное преобразование

Численное преобразование происходит в математических функциях и выражениях.

Например, когда операция деления применяется не к числу:

Мы можем использовать функцию , чтобы явно преобразовать к числу:

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

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

Правила численного преобразования:

Значение Преобразуется в…
Пробельные символы по краям обрезаются. Далее, если остаётся пустая строка, то , иначе из непустой строки «считывается» число. При ошибке результат .

Примеры:


Учтите, что и ведут себя по-разному. Так, становится нулём, тогда как приводится к .

Сложение „+“ объединяет строки

Почти все математические операторы выполняют численное преобразование. Исключение составляет . Если одно из слагаемых является строкой, тогда и все остальные приводятся к строкам.

Тогда они конкатенируются (присоединяются) друг к другу:

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

2.3 Класс Character

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

Примеры

Методы Описание
Проверяет, является ли символ символом алфавита
Является ли символ буквой
Является ли символ цифрой
Является ли символ пробелом, символом переноса строки или смены параграфа (коды: 12, 13, 14)
Является ли символ разделителем: пробел, tab, и т.д.
Символ в нижнем регистре — строчные буквы?
Символ в верхнем регистре — заглавные буквы?
Преобразует символ в нижний регистр
Преобразует символ в верхний регистр

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

StartWith() и EndWith()

Методы StartWith() и EndWith() проверяют, начинается ли String с определенной подстроки:

String one = "This is a good day to code";

System.out.println( one.startsWith("This")    );
System.out.println( one.startsWith("This", 5) );

System.out.println( one.endsWith("code")    );
System.out.println( one.endsWith("shower")  );

В этом примере создается строка и проверяется, начинается ли она и заканчивается ли она различными подстроками.

  • Первая строка (после объявления String) проверяет, начинается ли String с подстроки «This». Поскольку это происходит, метод startWith() возвращает true.
  • Вторая строка проверяет, начинается ли строка с подстроки «This» при запуске сравнения с символа с индексом 5. Результат равен false, поскольку символ с индексом 5 равен «i».
  • Третья строка проверяет, заканчивается ли String подстрокой «code». Поскольку это происходит, метод endWith() возвращает true.
  • Четвертая строка проверяет, заканчивается ли String подстрокой “shower”. Так как это не так, метод endWith() возвращает false.

6.1 Предыстория появления enum

Сегодня мы изучим еще одну разновидность типов данный в Java — . Название происходит от слова Enumeration — перечисление. Что же это за тип данных и с чем его едят?

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

Например, тип «ДеньНедели» может принимать только значения ПОНЕДЕЛЬНИК, ВТОРНИК, СРЕДА, … Всего 7 значений. Или тип «Месяц» может принимать только значения ЯНВАРЬ, ФЕВРАЛЬ, МАРТ, … Всего 12 значений.

Можно, конечно, использовать числа (тип int): 1 — понедельник, 2 — вторник и т.д. Но кто-то случайно может присвоить такой переменной значение 8, или, например, значение 0.

Легко может возникнуть ситуация, когда один программист думает, что дни недели (или месяцы) нумеруются с нуля, другой — что с единицы и т.д.

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

6.4 Преобразование в класс

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

Код, упрощенная версия Примечание
Класс

Список статических констант-значений

Массив со всеми значениями типа

Переменная со значением конкретного объекта

конструктор класса — объекты класса можно создавать только внутри класса .

Метод нужно вызвать у объекта . Он возвращает значение объекта — .

Метод возвращает статический массив со всеми значениями класса


Если убрать из класса , все статические методы и переменные, получим мы такую картину:

Код Примечание
Переменная хранит значение объекта

Объекты можно создавать только внутри класса — конструктор .

Метод возвращает значение объекта .

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

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

— это просто статическое поле (константа) класса . А при обращении к статическим методам и полям извне класса перед именем поля или метода нужно указывать имя класса.

Integer.valueOf()

Another option would be to use the static Integer.valueOf() method, which returns an Integer instance:

Similarly, the valueOf() method also accepts a custom radix as the second argument:

3.1. Integer Cache

At first glance, it may seem that the valueOf() and parseInt() methods are exactly the same. For the most part, this is true — even the valueOf() method delegates to the parseInt method internally.

However, there is one subtle difference between these two methods: the valueOf() method is using an integer cache internally. This cache would return the same Integer instance for numbers between -128 and 127:

Therefore, it’s highly recommended to use valueOf() instead of parseInt() to extract boxed integers as it may lead to a better overall footprint for our application.

5.3 Метод equals()

Унаследованный от класса метод содержит самый простой алгоритм сравнивания текущего и переданного объектов — он просто сравнивает их ссылки.

Тот же эффект вы получите, если просто сравните переменные класса Person вместо вызова метода Пример:

Код Вывод на экран

Метод просто сравнивает у себя внутри ссылки и .

Однако у класса сравнение работает по-другому. Почему?

Потому что разработчики класса написали собственную реализацию метода .

Реализация метода equals()

Давайте и мы напишем свою реализацию метода equals в классе . Разберем 4 основных случая.

Важно: вне зависимости от того, для какого класса переопределять метод equals, он всегда принимает параметр типа Object

Сценарий 1: в метод equals передали тот же самый объект, у которого вызвали метод . Если ссылки у текущего и переданного объектов равны, нужно вернуть . Объект совпадает сам с собой.

В коде это будет выглядеть так:

Код Описание
Сравниваем ссылки

Сценарий 2: в метод передали ссылку — сравнивать не с чем. Объект, у которого вызвали метод , точно не null, значит, в этом случае нужно вернуть .

В коде это будет выглядеть так:

Код Описание
Сравниваем ссылки

Переданный объект — ?

Сценарий 3: в метод передали ссылку на объект вообще не класса Person. Равен ли объект класса объекту класса не-Person? Тут уже решает сам разработчик класса Person — как хочет, так и сделает.


Но обычно все же объекты считаются равными, если это объекты одного класса. Поэтому если в наш метод equals передали объект не класса Person, мы будем всегда возвращать . А как проверить, какого типа объект? Правильно: с помощью оператора .

Вот как будет выглядеть наш новый код:

Код Описание
Сравниваем ссылки

Переданный объект — ?

Если переданный объект не типа

6.5 Еще методы enum’а

Еще у всех -классов есть несколько интересных особенностей.

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

Чтобы преобразовать объект типа enum в строку, у него нужно вызвать метод .

Для обратного преобразования (строки в объект ) можно воспользоваться статическим методом :

Очень удобно и полезно во многих случаях.

Преобразование в число и обратно

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

Для обратного преобразования (числа в объект ) нужно воспользоваться конструкцией подлиннее:

Примеры:

Код Примечание
Понедельник Получаем индекс понедельника (0) День недели на 2 дня позже понедельника

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

Производительность конкатенации

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

String one = "Hello";
String two = " World";

String three = new StringBuilder(one).append(two).toString();

Создается новый StringBuilder, который передает первую строку в свой конструктор, а вторую – в свой метод append(), прежде чем вызвать метод toString(). Этот код фактически создает два объекта: экземпляр StringBuilder и новый экземпляр String, возвращенный методом toString().

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

Вот цикл, содержащий вышеуказанный тип конкатенации строк:

String[] strings = new String[]{"one", "two", "three", "four", "five" };

String result = null;
for(String string : strings) {
    result = result + string;
}

Этот код будет скомпилирован в нечто похожее на это:

String[] strings = new String[]{"one", "two", "three", "four", "five" };

String result = null;
for(String string : strings) {
    result = new StringBuilder(result).append(string).toString();
}

Теперь для каждой итерации в этом цикле создается новый StringBuilder. Кроме того, объект String создается методом toString(). Это приводит к небольшим расходам на создание экземпляров за одну итерацию: один объект StringBuilder и один объект String. Само по себе не является настоящим убийцей производительности, хотя.

Каждый раз, когда выполняется новый код StringBuilder(result), конструктор StringBuilder копирует все символы из результирующего String в StringBuilder. Чем больше итераций цикла, тем больше будет результат String. Чем больше растет результат String, тем больше времени требуется для копирования символов из него в новый StringBuilder и повторного копирования символов из StringBuilder во временную строку, созданную методом toString(). Другими словами, чем больше итераций, тем медленнее становится каждая итерация.

Самый быстрый способ объединения строк – создать StringBuilder один раз и повторно использовать один и тот же экземпляр внутри цикла. Вот как это выглядит:

String[] strings = new String[]{"one", "two", "three", "four", "five" };

StringBuilder temp  = new StringBuilder();
for(String string : strings) {
    temp.append(string);
}
String result = temp.toString();

Этот код избегает как экземпляров объектов StringBuilder и String внутри цикла, так и, следовательно, позволяет избежать двухкратного копирования символов, сначала в StringBuilder, а затем снова в String.


С этим читают