Блок 1. Раздел 2. Тема 5

Класс String
чтение строк с клавиатуры

Класс String хранит текст. Научимся объявлять строки, запускать некоторые полезные функции для работы с текстом, вводить строчки с клавиатуры и сравнивать их между собой.
Сразу посмотрим работу со строками в коде:
// У строк свой формат объявления объектов:
String name = "Ivan"; // создать Строку name, равную "Ivan"

System.out.println ("Меня зовут "); 
System.out.println (name); // распечатать строку name
Как видно из примера, всегда можно задать строчку непосредственно как текст в двойных кавычках "..."

Объекты класса String, то есть строки, очень удобно склеивать друг с другом оператором плюс. Эта возможность введена специально для облегчения работы именно со строками, и для большинства других классов оператор плюс не определен.
String first_name = "Ivan";
String second_name = "Kuznetzov";

// С помощью оператора + можно склеивать строки - получится снова строка.
// Эту строку можно сохранить в переменной, например, так:
String full_name = first_name + " " + second_name; 

// Можно делать склейку прямо при распечатке
System.out.println (first_name + " " + second_name);

// Если написать строка плюс число, то число тоже приклеится к строке:
int house_number = 204;
String address = "Mayakovskaya street, " + house_number;

System.out.println  (address); // Распечатается: Mayakovskaya street, 204

// Можно использовать + и непосредственно при распечатке:
double pi = 3.1415;
System.out.println ("Число Пи примерно равно " + pi); 

// Также + хорош для перевода числа в строку:
int number = 10;
String str = number + ""; // приклеим 10 к пустой строке, получим строку '1', '0'
Ещё в классе String есть множество полезных функций. Например, уже знакомая нам charAt возвращает код символа, стоящего в строке под заданным номером. Нумерация как всегда в Java идет с нуля, а не с привычной единицы.
String name = "Ivan";

// charAt возвращает код символа под заданным номером.
// Это именно код, поэтому charAt возвращает int, но его можно явно привести к char,
// чтобы пользоваться уже как символом, в том числе распечатывать
char c0 = (char) name.charAt (0); // с0 теперь равно 'I' - нулевой символ строки Ivan
char c1 = (char) name.charAt (1); // с1 будет равно 'v'
char c2 = (char) name.charAt (2); // с2 будет равно 'a'
char c3 = (char) name.charAt (3); // с3 будет равно 'n'

// в строке Ivan всего 4 символа, от нулевого до третьего,
// поэтому обращение к четвертому повлечет ошибку:
char c4 = (char) name.charAt (4); // исключение out of bounds, 
// то есть символ с индексом 4 вне границ строки.
// На экране вы увидите красную надпись:
"java.lang.StringIndexOutOfBoundsException: String index out of range: 4"
// Не пугайтесь экрана с кучей непонятного текста - ищите ключевые знакомые куски
// Например, IndexOutOfBounds точно означает выход за границу, а остальное уже детали
Строчки удобно считывать с клавиатуры с помощью уже знакомого класса Scanner:
Scanner myscan = new Scanner (System.in);
// функция сканера next() возвращает очередное слово, 
// которое пользователь вводит с клавиатуры:
String word = myscan.next ();  // считать строчку до ближайшего пробела или enter

// функция сканера next() считает целую строку до ближайшего enter: 
String line = myscan.nextLine ();
Для сравнения строк друг с другом в классе String есть функция equals. Она возвращает true, когда две строчки совпадают по буквам, и false, если хоть как-то отличаются. Обычный оператор сравнения == следует использовать только для переменных примитивных типов, таких как int, double, char, boolean. Для строк и вообще для объектов любых классов оператор == обычно будет работать неверно, но об этом в следующем блоке, где речь пойдёт о классах и объектах. Пока что лучше просто использовать equals вот так:
Scanner myscan = new Scanner (System.in);

String line1 = myscan.nextLine (); // считать первую строчку с клавиатуры
String line2 = myscan.nextLine (); // считать вторую строчку с клавиатуры

if (line1.equals (line2) == true)
 System.out.println ("Были введены одинаковые строчки");
else
 System.out.println ("Были введены разные строчки");

// если в операторе if не указывать никакое сравнение, то
// автоматически будет подразумеваться проверка выражения на истинность,
// то есть == true допишется по умолчанию, даже если его не писать.
// Так что следующие строчки делают то же самое, но запись чуть-чуть короче:

if (line1.equals (line2)) // "если line1 равна line2, то" - код читается легче
 System.out.println ("Были введены одинаковые строчки");
else
 System.out.println ("Были введены разные строчки");

// Функция equals вызывается для какой-то заданной строчки:  line1.equals () ,
// То есть вызов можно прочесть как "равна ли строка line 1?" 
// Сразу напрашивается - равна ли, а чему именно? Конечно другой строчке - 
// она указывается параметром функции equals.
Общий принцип работы с функциями строк.

Сначала вам нужно создать первую строчку String line1 = ... явно указать её в двойных кавычках или прочесть её с клавиатуры через Scanner. Для этой строчки можно вызывать любые функции класса String через точку line1.имя_функции () . Если нужно, в скобках указываем параметры - числа, или другую строку. Как и раньше, чтобы использовать возвращаемое значение, его нужно объявить как переменную. Например, int res = line1.length (); позволит сохранить длину строки line1 в переменную res .

Чтобы описать, как устроена та или иная функция обычно приводят её прототип, то есть краткое описание. В прототипе слева указывается, каков тип возвращаемого значения функции, то есть она возвращает int, boolean, String или что-то ещё. Если же функция не возвращает ничего, то указывается английское слово "пустота" - void. После этого пишут имя функции, а затем в скобках её параметры.

Несколько прототипов функций класса String:

Функция boolean contains (String str) проверяет, содержится ли строчка-параметр в исходной строке и возвращает true, если содержится, и false иначе.

Функция int indexOf (String str) также ищет одну строчку или отдельную букву в другой строке и возвращает позицию, где именно вторая строчка встретилась в первой. Возвращает -1, если не встретилась совсем. Незаменимая вещь для любых текстовых редакторов и вообще работы с текстом.

Ещё вариант той же функции int indexOf (String str, int start_from) - делает то же самое, но ищет вхождение str только начиная с символа под номером start_from.

Функция int compareTo (String str) сравнивает одну строку с другой по принципу "как в словаре". То есть, для полностью равных строк возвращает ноль, если исходная строка шла бы в словаре раньше параметра, то функция вернет отрицательное число, а если позже - положительное.

Функция int length () возвращает длину строки, то есть количество символов в строке.

Функция String substring (int begin, int end) возвращает подстроку в заданных пределах. То есть, например, вы хотите работать не со всей строкой, а только с её частью, начиная с символа номер 5 и заканчивая символом номер 10, тогда пишем String res = line1.substring (5, 10);

В дополнение к уже описанной функции boolean equals (String str), сравнивающей строки на посимвольное равенство, есть ещё похожая функция boolean equalsIgnoreCase (String str), которая вернёт true, если строки одинаковые, но некоторые буквы указаны в одной строке заглавными, а в другой прописными.

Класс String специально сделан, чтобы хранить неизменяемые строки. Все функции от contains до substring не меняют содержимое данной строки, но могут генерировать новые строчки. Для изменения строк есть класс StringBuilder, но о нём пока рано вести речь.

Посмотрим пример на все эти функции сразу в коде:
// Мы могли бы считать строки с клавиатуры
// Scanner myscan = new Scanner (System.in);
// String line1 = myscan.nextLine (); 
// String line2 = myscan.nextLine (); 

System.out.println ("Введите адрес");

// Но сейчас для наглядности зададим конкретные значения:
String address = "город Москва, улица Маяковская, дом 10";
       
// если в адресе есть слово "Москва", то ...
if ( address.contains ("Москва"))
    System.out.println ( "Совершите покупку всего за 100$" );
else
    System.out.println ( "Совершите покупку всего за 10$ " ); // шутка конечно :)
       
// вычислим длину строки:
int len = address.length (); 
       
System.out.println ("Вы ввели следующее количество символов: " + len);
       
int begin = address.indexOf(","); // найдём первую запятую - с неё начинается улица в адресе
System.out.println ("Первая запятая в тексте встречается на позиции " + begin);
int end = address.indexOf(",", begin + 1); // искать вторую запятую после первой запятой
       
String street = address.substring (begin+1, end); // выделим часть строчки с описанием улицы
       
System.out.println ("Введенная улица: " + street); // распечатает "улица Маяковская"
В классе String есть одна функция, которую можно вызывать не для какой-то конкретной строки line1 или address, как было выше, а просто по имени класса String. Речь идёт о функции valueOf. Она принимает на вход число и возвращает его же, но в виде строки. Очень удобно, когда вам нужно перевести число в строку. Используется она так:
String number_str = String.valueOf (4.5); 
// было число double 4.5, а стала строка String number_str из трёх символов '4', '.', '5'

// Java допускает и вызов через конкретный объект, как мы делали раньше:
String line1 = "something"; 
String number_str2 = line1.valueOf (4.5); // так можно, но не обязательно

// можно вызвать valueOf и для исходной строки line1, но смысла в этом мало -
// всё равно line1 никак не используется. 
// Для таких функций можно просто указывать имя класса, в данном случае String

//Можно вызывать valueIOf и для целых чисел и для других типов:
String integer_str = String.valueOf (10); // вызывали прямо по имени класса String.valueOf

// Функции, которые можно вызывать по имени класса называются статическими - static.
По логике вещей для valueOf нужен параметр - число, из которого потом будет получена строка, но никак не нужна сама исходная строка, ведь её ещё только предстоит сделать.

Фразу "строка класса String" формальнее можно пересказать как "объект класса String". Точно также и для всех остальных классов можно создавать их объекты. Например, объектом класса File будет очередной файл на компьютере. То есть класс описывает целое понятие файлов в принципе, а объект класса - один конкретный файл в заданной папке. В будущих блоках мы научимся создавать свои собственные классы.

Функции, которым не нужно ничего знать о конкретном объекте называют статическими и обозначают ключевым словом static. Например, функции valueOf нужно знать число, из которого при вызове будет сделана новая строка, а вот исходная строчка просто не нужна и не уместна. Поэтому прототип этой функции будет выглядеть так:

static String valueOf (double number);

Слово static означает "статичный", то есть не меняющий. Например, в случае строк - никакая исходная строка не будет изменена, ведь она никак не участвует в вызове valueOf. Также не нужно вообще эту строку знать, поэтому её можно не указывать при вызове - вместо неё пишется просто имя класса String.
Самое главное мы уже освоили. Теперь время решать задачи. Ответьте на несколько вопросов, чтобы лучше усвоился новый материал:
Вопрос 1. Как объявляются строки в Java?
С помощью двойных кавычек.
String str = "something";

Также с помощью класса Scanner строку можно считать с клавиатуры
Scanner myscan = new Scanner (System.in);
String str2 = myscan.nextLine ();
Вопрос 2. Можно ли изменить какую-либо букву в уже объявленной строке String?
Нет, класс String специально сделан, чтобы хранить неизменяемые строки. Все функции от contains до substring не меняют содержимое данной строки, но могут генерировать новые строчки.
Задача 1. Как будет работать и что будет выдавать данная программа на экране?
package javaapplication5;
import java.util.Scanner;
public class JavaApplication5 {
    public static void main(String[] args) {
        Scanner myscan = new Scanner (System.in);
        
        String answer = myscan.nextLine ();

        if (answer.contains ("yes") )
            System.out.println ("Вы сказали да");
        
        if (answer.contains ("no") )
            System.out.println ("Вы сказали нет");
  
        if (answer.contains ("yes") && answer.contains ("no") )
            System.out.println ("Сам хоть понял, что сказал?"); // программисткий юмор :)
    }             
}
Решение
Пользователь вводит строчку с клавиатуры. Если в его строке содержится yes, то программа отвечает "вы сказали да". Если в ней содержится no, программа отвечает "вы сказали нет". Если же в этой строке одновременно yes и no, то программа переспрашивает "Сам хоть понял, что сказал?" :)
Решайте больше задач по этому разделу здесь.
В следующей теме расскажем про оператор switch-case, аналогичный if else, но помогающий писать код короче