Avatar ·

Форматирование строк в Kotlin: как использовать String.format и шаблоны?

Всем привет! Я только начал изучать Kotlin после Java и столкнулся с проблемой форматирования строк. В Java я привык использовать `String.format("%s %d", str, num)` или `System.out.printf(...)`. Но в Kotlin я вижу, что часто используют шаблоны строк с долларом: `"Привет, $name"`. Это удобно для простых случаев, но как быть, когда нужно отформатировать число с определённым количеством знаков после запятой или выровнять текст по ширине? Например, у меня есть такой код: ```kotlin val price = 123.4567 val name = "Кофе" // хочу вывести: "Товар: Кофе, Цена: 123.46 руб." ``` Я пробовал писать `"Товар: $name, Цена: $price руб."`, но получаю `123.4567` без округления. Пробовал использовать `String.format("%.2f", price)`, но IDEA подчёркивает это как deprecated или предлагает заменить на что-то другое. В документации написано про `String.format`, но примеры какие-то старые. Ещё вопрос: есть ли в Kotlin аналоги Java-форматеров, например, для дополнения строк пробелами (`%10s`) или для форматирования дат? Или нужно использовать старый Java-метод, который работает, но считается неидиоматичным? Буду благодарен за примеры кода и объяснение, как правильно делать в современном Kotlin. <<>>

Основные подходы к форматированию строк в Kotlin

В Kotlin есть два основных способа форматирования строк: шаблоны строк (string templates) и функция String.format(). Оба работают, но для разных сценариев. Давайте разберём их на примерах.

1. Шаблоны строк (рекомендуемый способ для простых случаев)

Шаблоны с $ — это встроенная возможность Kotlin, которая транслируется в конкатенацию строк на байткоде. Они идеальны для подстановки переменных и вызова методов:

val name = "Кофе"
val price = 123.4567
// Простая подстановка
println("Товар: $name, Цена: $price") 
// Вызов метода внутри шаблона
println("Цена с округлением: ${"%.2f".format(price)} руб.")

Обратите внимание: "%.2f".format(price) — это не статический метод Java, а функция-расширение для String, добавленная в Kotlin. Она использует тот же java.util.Formatter под капотом, но синтаксис более идиоматичный. Для округления до двух знаков это работает отлично.

2. Классический String.format() (для сложного форматирования)

Если вам нужно выравнивание, заполнители, работа с датами или локалью, используйте String.format() — он доступен без deprecated и является частью стандартной библиотеки Kotlin (на самом деле это Java-метод, но Kotlin предоставляет для него синтаксический сахар):

val price = 123.4567
val name = "Кофе"
val result = String.format("Товар: %-10s, Цена: %08.2f руб.", name, price)
println(result) // Выведет: "Товар: Кофе      , Цена: 00123.46 руб."

Здесь:

  • %-10s — строка, выровненная влево, шириной 10 символов;
  • %08.2f — число с двумя знаками после запятой, дополненное нулями до 8 символов.

Если вы работаете с датами, можно использовать String.format("%tF", date) или DateTimeFormatter из Java 8+. Kotlin не добавляет своих обёрток для дат, поэтому используйте стандартный Java API:

import java.time.LocalDate
import java.time.format.DateTimeFormatter

val date = LocalDate.now()
val formatted = date.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))
println("Сегодня: $formatted")

3. Использование kotlin.text.format (альтернатива)

В Kotlin есть функция-расширение format() для строк, которая принимает массив аргументов. Это более краткий аналог String.format():

val template = "Товар: %s, Цена: %.2f руб."
println(template.format(name, price))

Этот способ предпочтительнее, так как он читается естественнее и не требует статического импорта.

4. Форматирование чисел с помощью DecimalFormat

Для сложного форматирования чисел (например, разделители тысяч, валюта) используйте java.text.DecimalFormat:

val df = java.text.DecimalFormat("#,###.00")
println(df.format(1234567.89)) // "1,234,567.89"

Итог

  • Для простой подстановки переменных — используйте $variable.
  • Для форматирования с округлением/заполнением — "%10.2f".format(value).
  • Для сложных шаблонов (даты, локали) — String.format() или DecimalFormat.
  • Избегайте старого Java-стиля System.out.printf() — он работает, но не идиоматичен для Kotlin.

Ваш пример с ценой решается одной строкой:

println("Товар: $name, Цена: ${"%.2f".format(price)} руб.")

Это и кратко, и понятно.

<<>>

Альтернативный подход: многострочные строки и raw templates

Если вам нужно отформатировать сложный блок текста (например, SQL-запрос, JSON или отчёт), используйте многострочные строки (raw strings) с тройными кавычками """. Они сохраняют форматирование и позволяют встраивать шаблоны:

val name = "Кофе"
val price = 123.4567
val report = """
    Отчёт о товаре:
    -----------------
    Наименование: $name
    Цена: ${"%.2f".format(price)} руб.
    Дата: ${java.time.LocalDate.now()}
""".trimIndent()
println(report)

Метод trimIndent() удаляет лишние отступы, которые вы добавили для читаемости кода. Это удобно для шаблонов писем, логов или генерации кода.

Ещё один трюк — использовать buildString для построения строки с условиями и циклами:

val items = listOf("Кофе" to 120.0, "Чай" to 80.5)
val receipt = buildString {
    appendLine("Чек:")
    items.forEach { (name, price) ->
        appendLine("$name: ${"%.2f".format(price)} руб.")
    }
    appendLine("Итого: ${"%.2f".format(items.sumOf { it.second })} руб.")
}
println(receipt)

Этот подход заменяет StringBuilder из Java и более читаем за счёт лямбды с ресивером. Для сложного форматирования в реальных проектах (например, в Android) часто используют библиотеки вроде Anko или kotlinx.html, но для базовых задач описанных методов достаточно.