Когда только начинал с Android, не мог понять — почему так много возни со строками? TextView, Toast, каждый диалог, логи... везде String. Причём постоянно приходилось гуглить то один метод, то другой. В итоге решил сделать себе такую шпаргалку, чтобы всё было под рукой. Может, и тебе пригодится.![Класс String - 1]()

Первое и главное про String
String в Java (и в Android соответственно) — штука неизменяемая. То есть immutable, как говорят умные люди. Что это значит на практике? А вот что:String name = "Барсик";
name = name + " рыжий"; // создается новая строка, старая уходит в мусор
То есть каждый раз, когда ты что-то делаешь со строкой, создается новый объект. Старый просто выбрасывается. Это важно понимать, потому что если ты начнёшь в цикле складывать строки через плюс, у тебя приложение начнёт тормозить. Особенно на слабых устройствах это заметно.
Для таких случаев придумали StringBuilder (есть ещё StringBuffer, но он для многопоточности, в обычных случаях не нужен). Вот пример - допустим, мне надо собрать список имён котов:
// так делать не надо!
String result = "";
for(int i = 0; i < catNames.length; i++) {
result = result + catNames[i] + ", ";
}
// а вот так нормально
StringBuilder sb = new StringBuilder();
for(int i = 0; i < catNames.length; i++) {
sb.append(catNames[i]);
sb.append(", ");
}
String result = sb.toString();
Кстати, все эти классы (String, StringBuilder, StringBuffer) в пакете java.lang, так что импортить не надо. И все они реализуют CharSequence — помнишь, когда в TextView метод setText принимает CharSequence? Вот поэтому туда можно и String передать, и StringBuilder.Как создавать строки
Ну тут всё просто, самый обычный способ:String aboutCat = "Кот - это звучит гордо, а если наступить на хвост, то громко";
Массив строк — тоже без проблем:
String[] cats = {"Васька", "Барсик", "Мурзик"};
Можно и через конструктор, хотя честно — зачем?
String str = new String(); // пустая строка, но обычно просто "" проще
Иногда нужно создать строку из массива символов (да, бывает и такое):
char[] chars = {'c', 'a', 't'};
String str = new String(chars);
А вот это уже интереснее — можно взять только часть массива:
char[] chars = {'c', 'a', 't', 'a', 'm', 'a', 'r', 'a', 'n'};
String str = new String(chars, 0, 3);
// берём 3 символа начиная с позиции 0, получается "cat"
Строковые ресурсы в Android
Это важная штука. В Android не принято писать строки прямо в коде (ну можно, конечно, но потом замучаешься всё искать). Правильно — держать тексты в файле strings.xml. Во-первых, удобно всё в одном месте, во-вторых, если захочешь сделать приложение на разных языках, не придётся весь код перелопачивать. Достать строку из ресурсов можно так:String catName = getResources().getString(R.string.cat_name);
Если работаешь во фрагменте, немного по-другому:
String catName = requireContext().getResources().getString(R.string.cat_name);
Хотя если честно, я обычно просто пишу:
String catName = getString(R.string.cat_name); // работает и в Activity, и во Fragment
Для массива строк:
Resources res = getResources();
String[] cats = res.getStringArray(R.array.cats_array);
Форматирование — вещь!
Вот это реально удобно. Представь — у тебя приложение про котов (почему бы нет?). Надо выводить информацию о каждом. Можно было бы для каждого кота отдельную строку в ресурсах делать... но это же глупо. Делаешь в strings.xml шаблон:<string name="cat_info">Кот по имени %1$s, у него %2$s лапы, %3$s хвост. Ему %4$d лет</string>
Эти штуки с процентами — позиции для параметров. %s это для строк, %d для чисел.
А дальше в коде:
String catName = "Барсик";
String paws = "четыре";
String tail = "один";
int age = 5;
String catInfo = getResources().getString(R.string.cat_info);
String result = String.format(catInfo, catName, paws, tail, age);
TextView tvInfo = findViewById(R.id.tvCatInfo);
tvInfo.setText(result);
И всё! Появился кот Васька, ему 6 лет? Просто меняешь переменные, а текст остаётся тем же.
Кстати, есть способ ещё короче — getString() умеет сразу подставлять параметры:
String result = getString(R.string.cat_info, catName, paws, tail, age);
tvInfo.setText(result);
Намного лаконичнее же.Склеивание строк
В Java для строк работает оператор +. Просто складываешь их:String cat = "Кот";
String name = "Васька";
String fullname = cat + " " + name; // "Кот Васька"
Обрати внимание на пробел — без него слипнется в "КотВаська".
Java умная, сама приводит разные типы к строке:
int pawsCount = 4;
String paws = " лапы";
String catInfo = pawsCount + paws; // станет "4 лапы"
Но тут есть нюанс. Если ты начнёшь складывать строки в цикле, будет беда. Помнишь, я говорил что String неизменяемый? Вот смотри что происходит:
// так делать нельзя!
String result = "";
for(String name : catNames) {
result += name + ", "; // каждый раз новый объект создаётся!
}
Если у тебя там 100 имён котов, то в памяти создастся 100 объектов, которые тут же станут мусором. GC (сборщик мусора) начнёт работать, приложение потормаживать будет. Особенно на слабых телефонах заметно.
Правильно делать через StringBuilder:
StringBuilder sb = new StringBuilder();
for(String name : catNames) {
sb.append(name).append(", ");
}
String result = sb.toString();
Или можно даже так:
StringBuilder sb = new StringBuilder();
for(int i = 0; i < catNames.length; i++) {
sb.append(catNames[i]);
if(i < catNames.length - 1) {
sb.append(", ");
}
}
String result = sb.toString();
Второй вариант не добавит лишнюю запятую в конце. Хотя если честно, я обычно просто потом trim() делаю, если что :)Методы String: то, что реально нужно
Ладно, хватит теории. Давай по методам, которые постоянно используются в реальных проектах. Я тут собрал те, с которыми сам сталкиваюсь почти каждый день.charAt(int index)
Возвращает символ по индексу. Индексы с нуля, как обычно.String catName = "Котёнок";
char symbol = catName.charAt(2); // вернёт 'т'
TextView tv = findViewById(R.id.textView);
tv.setText(String.valueOf(symbol)); // выведет т
Кстати, тут такая штука — если написать просто tv.setText(symbol), то упадёт с ошибкой. Потому что Android думает что ты передаёшь resource ID, а не символ. Поэтому нужен String.valueOf(). Я раз пять на это попадался, пока не запомнил.length()
Возвращает длину строки. Проще некуда, но используется везде:String input = editText.getText().toString();
if(input.length() < 3) {
Toast.makeText(this, "Минимум 3 символа!", Toast.LENGTH_SHORT).show();
}
substring(int start) и substring(int start, int end)
Вырезает кусок строки. Вторая версия берёт символы от start до end - 1 (да, именно минус один, без последнего символа — это частая ошибка).String word = "скотина";
String cat = word.substring(1, 4); // получим "кот"
TextView tv = findViewById(R.id.textView);
tv.setText(cat);
Или реальный пример — достать имя файла из пути:
String filePath = "/storage/emulated/0/Pictures/cat.jpg";
int lastSlash = filePath.lastIndexOf('/');
String fileName = filePath.substring(lastSlash + 1);
// fileName будет "cat.jpg"
toLowerCase() и toUpperCase()
Переводят в нижний или верхний регистр:String cat = "Кот";
String lower = cat.toLowerCase(); // кот
String upper = cat.toUpperCase(); // КОТ
TextView tv = findViewById(R.id.textView);
tv.setText(upper);
trim()
Убирает пробелы с краёв. Незаменимая вещь при работе с пользовательским вводом:String input = editText.getText().toString().trim();
if(input.isEmpty()) {
// пользователь просто пробелов понатыкал
}
Вообще, связка .getText().toString().trim() встречается в Android-коде настолько часто, что я её уже на автомате пишу. Как заклинание какое-то)replace(CharSequence target, CharSequence replacement)
Заменяет одну подстроку на другую. Все вхождения сразу меняет:String text = "кит";
String result = text.replace("и", "о");
// получится "кот"
TextView tv = findViewById(R.id.textView);
tv.setText(result);
split(String regex)
Разбивает строку на массив. Очень полезная штука, часто использую для парсинга:String catNames = "Васька Рыжик Мурзик Барсик";
String[] cats = catNames.split(" ");
// выведем в лог каждое имя
for(int i = 0; i < cats.length; i++) {
Log.d("CatApp", "Кот #" + i + ": " + cats[i]);
}
В реальности часто нужно парсить CSV или что-то типа того. Например:
String data = "Васька,5,рыжий";
String[] parts = data.split(",");
String name = parts[0]; // Васька
String age = parts[1]; // 5
String color = parts[2]; // рыжий
contains(CharSequence s)
Проверяет, есть ли подстрока в строке:String word = "котёнок";
if(word.contains("кот")) {
Toast.makeText(this, "Нашли кота!", Toast.LENGTH_SHORT).show();
}
startsWith() и endsWith()
Проверяют начало и конец строки:String filename = "photo_cat.jpg";
if(filename.endsWith(".jpg")) {
// это картинка
} else if(filename.endsWith(".mp4")) {
// это видео
}
Ещё есть вариант startsWith с указанием позиции:
String word = "Суккот";
if(word.startsWith("кот", 3)) {
// ищем "кот" начиная с 3 позиции
Toast.makeText(this, "Есть кот!", Toast.LENGTH_SHORT).show();
}
equals() и equalsIgnoreCase()
Сравнение строк — больная тема для новичков. Я сам когда-то потратил пару часов на баг, который оказался из-за ==. Запомни навсегда: строки сравниваются через equals(), а не через ==!String input = editText.getText().toString();
// так НЕЛЬЗЯ!
if(input == "admin") {
// может сработать, а может нет, это рулетка
}
// а вот так ПРАВИЛЬНО
if(input.equals("admin")) {
// вход разрешён
}
Ещё лучше писать так (на случай если input окажется null):
if("admin".equals(input)) {
// так безопаснее
}
Если регистр не важен:
if("admin".equalsIgnoreCase(input)) {
// "Admin", "ADMIN", "aDmIn" - всё пройдёт
}
indexOf() и lastIndexOf()
Возвращают позицию подстроки. Если не нашли — вернут -1.String email = "user@example.com";
int atPos = email.indexOf('@');
if(atPos > 0) {
String username = email.substring(0, atPos); // user
String domain = email.substring(atPos + 1); // example.com
}
Или достать расширение файла:
String filename = "my_cat.jpg";
int dotIndex = filename.lastIndexOf('.');
if(dotIndex != -1) {
String ext = filename.substring(dotIndex + 1); // jpg
}
isEmpty() и проверка на пустоту
isEmpty() просто проверяет длину:String str1 = "";
String str2 = " ";
str1.isEmpty(); // true
str2.isEmpty(); // false, там же пробелы!
В Android есть ещё удобная штука — TextUtils:
if(TextUtils.isEmpty(str)) {
// строка пустая или вообще null
}
Я обычно так и делаю, чтобы не проверять на null отдельно.valueOf()
Конвертирует всё подряд в строку:int catAge = 7;
TextView tv = findViewById(R.id.textView);
tv.setText(String.valueOf(catAge));
Это важно! Если напишешь просто tv.setText(catAge), то Android решит что 7 это resource ID и попытается найти строковый ресурс с таким номером. Упадёт с ошибкой типа "Resource not found". Я на это раз пять попадался, если честно.compareTo() и compareToIgnoreCase()
Лексикографическое сравнение. Возвращает 0 если строки равны, отрицательное число если первая "меньше", положительное если "больше". Используется обычно для сортировки:String[] cats = {"Мурзик", "Барсик", "Васька", "Рыжик"};
Arrays.sort(cats, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
// теперь массив отсортирован
Если поддерживаешь Android API 24+, можно короче через лямбду:
Arrays.sort(cats, String::compareTo);
format()
Форматирование строк в стиле printf из C. Очень удобная штука:String name = "Барсик";
int age = 5;
String msg = String.format("Коту %s уже %d лет", name, age);
TextView tv = findViewById(R.id.textView);
tv.setText(msg); // Коту Барсик уже 5 лет
Основные спецификаторы:
- %s для строк
- %d для целых чисел
- %f для дробных чисел
- %.2f для чисел с 2 знаками после запятой
Пример с ценой:
double price = 123.456;
String priceStr = String.format("Цена: %.2f usd.", price);
// Цена: 123.46 usd.
concat()
Соединяет строки. Работает так же как +, но название метода лучше — concat же содержит слово "кот"!String part1 = "Сук";
String result = part1.concat("кот"); // Суккот
TextView tv = findViewById(R.id.textView);
tv.setText(result);
Да, я специально примеры с котами делаю. Настоящие кошатники оценят :)Генерация случайной строки
Иногда нужно сгенерировать случайную строку — например, для временного ID или какого-нибудь токена. Вот как я обычно это делаю:public class MainActivity extends AppCompatActivity {
private static final String ALLOWED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
private Random random = new Random();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.button);
TextView tv = findViewById(R.id.textView);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String randomStr = generateRandomString(10);
tv.setText(randomStr);
}
});
}
private String generateRandomString(int length) {
StringBuilder result = new StringBuilder();
for(int i = 0; i < length; i++) {
int index = random.nextInt(ALLOWED_CHARS.length());
char randomChar = ALLOWED_CHARS.charAt(index);
result.append(randomChar);
}
return result.toString();
}
}
При каждом нажатии на кнопку генерируется новая строка типа "A7K9M2X5Q1".Почему == не работает для сравнения строк
Это классика. Все на это натыкаются. Я когда-то потратил целый вечер на поиск бага, а оказалось — ==.String cat1 = "Мурзик";
String cat2 = new String("Мурзик");
if(cat1 == cat2) {
Log.d("Test", "Строки равны");
} else {
Log.d("Test", "Строки НЕ равны"); // выполнится ЭТО!
}
Хотя обе переменные содержат "Мурзик", == вернёт false. Почему? Потому что == сравнивает ссылки на объекты, а не их содержимое. А когда мы пишем new String("Мурзик"), создаётся новый объект в памяти, даже если такая строка уже есть.
Правильно так:
if(cat1.equals(cat2)) {
Log.d("Test", "Строки равны"); // вот это сработает!
}
Метод equals() сравнивает содержимое строк.
Вот ещё примеры для полного понимания:
String s1 = "hello";
String s2 = "hello";
String s3 = s1;
String s4 = "h" + "e" + "l" + "l" + "o";
String s5 = new String("hello");
String s6 = new String(new char[]{'h', 'e', 'l', 'l', 'o'});
Log.d("Test", "s1 == s2: " + (s1 == s2)); // true (компилятор оптимизирует)
Log.d("Test", "s1 equals s2: " + s1.equals(s2)); // true
Log.d("Test", "s1 == s3: " + (s1 == s3)); // true (одна ссылка)
Log.d("Test", "s1 equals s3: " + s1.equals(s3)); // true
Log.d("Test", "s1 == s4: " + (s1 == s4)); // true (компилятор склеил литералы)
Log.d("Test", "s1 equals s4: " + s1.equals(s4)); // true
Log.d("Test", "s1 == s5: " + (s1 == s5)); // FALSE (новый объект!)
Log.d("Test", "s1 equals s5: " + s1.equals(s5)); // true
Log.d("Test", "s1 == s6: " + (s1 == s6)); // FALSE (новый объект!)
Log.d("Test", "s1 equals s6: " + s1.equals(s6)); // true
Простое правило: всегда используй equals() для строк. Оператор == оставь для примитивов (int, boolean и прочее) и для проверки на null.Полезные штуки для Android
Напоследок пару советов, которые реально выручают в работе: 1. Строки держи в ресурсах Серьёзно, не пиши тексты прямо в коде. Потом сам замучаешься искать где что написано. Держи всё в strings.xml:// так не надо
textView.setText("Привет, мир!");
// а вот так правильно
textView.setText(R.string.hello_world);
Если потом захочешь сделать приложение на английском или ещё на каком языке — просто добавишь новый strings.xml и всё.
2. TextUtils — полезная штука
Android даёт класс TextUtils с удобными методами:
// проверка на пустоту, работает даже если str == null
if(TextUtils.isEmpty(str)) {
// строка пустая
}
// склеить массив строк с разделителем
String result = TextUtils.join(", ", arrayOfStrings);
Я обычно всегда через TextUtils.isEmpty проверяю — не надо отдельно на null смотреть.
3. SpannableString для красоты
Если нужен текст с разными стилями в одном TextView:
SpannableString spannable = new SpannableString("Этот текст жирный");
spannable.setSpan(new StyleSpan(Typeface.BOLD), 5, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannable);
Да, выглядит страшновато, но работает отлично. Можно цвет менять, размер, стиль — что угодно.
4. Форматирование через ресурсы
Помнишь я про String.format рассказывал? В Android можно ещё проще:
// В strings.xml пишешь:
// <string name="welcome">Привет, %1$s! Тебе %2$d лет.</string>
// а в коде просто:
String message = getString(R.string.welcome, "Вася", 25);
textView.setText(message);
Удобно же.
5. Html.fromHtml() если нужен простой HTML
Иногда нужно вставить жирный текст или курсив:
String html = "Текст с <b>жирным</b> словом";
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textView.setText(Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY));
} else {
textView.setText(Html.fromHtml(html));
}
Правда, тут надо проверять версию Android, потому что метод изменился.
---
Ну вот и всё. Конечно, у String методов там ещё штук сто наверное, но эти — самые нужные. Я реально использую их чуть ли не в каждом проекте. Сохрани себе эту статью куда-нибудь, пригодится. Я вот у себя в закладках держу подобные справочники — всё равно не запомнишь все методы наизусть, иногда надо подсмотреть синтаксис.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ