«1. Обзор

В этом уроке мы познакомимся с различными вариантами создания строки из N повторяющихся символов. Это удобно, когда нам нужно добавить отступы, создать ASCII-графику и т. д.

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

2. Пример

Давайте определим константы, которые мы будем использовать во всех решениях для проверки сгенерированной строки:

private static final String EXPECTED_STRING = "aaaaaaa";
private static final int N = 7;

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

Теперь давайте рассмотрим варианты генерации строки из N повторяющихся символов a.

3. Функция JDK11 String.repeat

В Java есть функция repeat для создания копий исходной строки:

String newString = "a".repeat(N);
assertEquals(EXPECTED_STRING, newString);

Это позволяет нам повторять отдельные символы или строки, состоящие из нескольких символов:

String newString = "-->".repeat(5);
assertEquals("-->-->-->-->-->", newString);

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

Если у нас нет JDK11, то нам придется создать алгоритм самостоятельно или использовать его из сторонней библиотеки. Лучшие из этих ИС вряд ли будут намного быстрее или проще в использовании, чем собственное решение JDK11.

4. Общие способы построения строки

4.1. StringBuilder с циклом for

Начнем с класса StringBuilder. Мы будем повторять цикл for N раз, добавляя повторяющийся символ:

StringBuilder builder = new StringBuilder(N);
for (int i = 0; i < N; i++) {
    builder.append("a");
}
String newString = builder.toString();
assertEquals(EXPECTED_STRING, newString);

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

4.2. Массив символов с циклом for

Мы можем заполнить массив символов фиксированного размера желаемым символом и преобразовать его в строку:

char[] charArray = new char[N];
for (int i = 0; i < N; i++) {
    charArray[i] = 'a';
}
String newString = new String(charArray);
assertEquals(EXPECTED_STRING, newString);

Это должно быть быстрее, так как не требует структуры с динамическим размером для хранить нашу строку по мере ее создания, а Java может эффективно преобразовывать массив символов в строку.

4.3. Метод заполнения массивов

Вместо использования цикла мы можем использовать библиотечную функцию для заполнения нашего массива:

char charToAppend = 'a';
char[] charArray = new char[N];
Arrays.fill(charArray, charToAppend);
String newString = new String(charArray);
assertEquals(EXPECTED_STRING, newString);

Это короче и так же эффективно во время выполнения, как и предыдущее решение.

5. Генерация строки методом повтора

5.1. Метод повторения Apache

Это решение требует добавления новой зависимости для библиотеки Apache Commons:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

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

char charToAppend = 'a';
String newString = StringUtils.repeat(charToAppend, N);
assertEquals(EXPECTED_STRING, newString);

5.2. Метод повторения Guava

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

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

Кроме того факта, что это исходит из другой библиотеки, это решение идентично решению Apache Commons. :

String charToAppend = "a";
String newString = Strings.repeat(charToAppend, N);
assertEquals(EXPECTED_STRING, newString);

6. Генерация строки с помощью метода nCopies

Если мы представим нашу целевую строку как набор повторяющихся подстрок, то мы могли бы использовать утилиту List для создания списка, а затем преобразовать полученный список в нашу последнюю строку. Для этого мы можем использовать метод nCopies из класса Collections в пакете java.util:

public static <T> List<T> nCopies(int n, T o);

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

6.1. Соединение строк и методы nCopies

Давайте создадим список односимвольных строк с помощью метода nCopies и воспользуемся String.join для преобразования его в наш результат:

String charToAppend = "a";
String newString = String.join("", Collections.nCopies(N, charToAppend));
assertEquals(EXPECTED_STRING, newString);

Методу String.join нужен разделитель, т.к. который мы используем пустую строку.

6.2. Guava Joiner и метод nCopies

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

String charToAppend = "a";
String newString = Joiner.on("").join(Collections.nCopies(N, charToAppend));
assertEquals(EXPECTED_STRING, newString);

7. Генерация строки с помощью метода Stream generate

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

«Однако, начиная с Java 8, мы можем использовать метод generate из Stream API. В сочетании с методом limit (для определения длины) и методом collect мы можем сгенерировать строку из N повторяющихся символов:

String charToAppend = "a";
String newString = generate(() -> charToAppend)
  .limit(length)
  .collect(Collectors.joining());
assertEquals(exampleString, newString);

8. Генерация строки с помощью Apache RandomStringUtils

Класс RandomStringUtils из Apache Библиотека Commons позволяет генерировать строку из N повторяющихся символов случайным образом. Нам нужно определить символ и количество повторений:

String charToAppend = "a";
String newString = RandomStringUtils.random(N, charToAppend);
assertEquals(EXPECTED_STRING, newString);

9. Заключение

В этой статье мы видели различные решения для генерации строки из N повторяющихся символов. Самый простой из них — String.repeat, доступный начиная с JDK 11.

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

Как всегда, код этих примеров доступен на GitHub.