概述

在这个教程中,我们将探讨生成包含N个重复字符的字符串的不同方法。当需要添加填充空格、创建ASCII艺术等时,这些技巧非常有用。

在JDK11及以上版本中,这个问题很容易解决,但对于早期版本,还有许多其他解决方案可供选择。我们将从最常见的开始,并介绍一些库中提供的其他方法。

2. 示例

让我们定义所有解决方案中将使用的常量:

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

其中,EXPECTED_STRING常量表示我们需要生成的字符串,而N常量用于定义字符重复次数。

现在,我们来看看如何生成重复字符a的N个字符字符串。

3. JDK11 String.repeat函数

Java提供了repeat函数来构建源字符串的副本:

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

这使得我们可以重复单个字符或多字符字符串:

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

这个功能背后的算法使用循环高效地填充字符数组。

如果我们没有JDK11,就需要自己编写算法,或者使用第三方库的解决方案。但这些通常不会比JDK11原生的解决方案更快或更易于使用。

4. 构建String的常见方式

4.1. 使用StringBuilderfor循环

首先,我们从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. 使用char数组的for循环

我们可以用我们想要的字符填充一个固定大小的char数组,然后将其转换为字符串:

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可以高效地将char数组转换为String

4.3. 使用Arrays.fill方法

我们可以不用循环,而是使用库函数填充数组:

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

这种方法更短,与前一个解决方案一样在运行时效率高。

5. 使用repeat方法生成字符串

5.1. Apache的repeat方法

这个解决方案需要添加一个依赖于Apache Commons库的新依赖:

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

添加此依赖后,我们可以使用StringUtils类中的repeat方法。它接受一个要重复的字符以及该字符应重复的次数作为参数

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

5.2. Guava的repeat方法

与前一个方法类似,这个也需要添加对Guava库的依赖:

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

除了来自不同的库之外,这个解决方案与Apache Commons的相同:

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

6. 使用nCopies方法生成字符串

如果我们将目标字符串视为重复子字符串的集合,那么我们可以使用List工具来构造列表,然后将结果转换为最终的String。为此,我们可以使用java.util包中的Collections类中的nCopies方法:

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

虽然使用子字符串列表构建不如使用固定字符数组有效,但它对于重复字符模式而不是单个字符很有帮助。

6.1. String.joinnCopies方法

让我们使用nCopies方法创建一个单字符字符串列表,然后使用String.join将其转换为结果:

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

String.join方法需要一个分隔符,这里我们使用空字符串。

6.2. Guava的JoinernCopies方法

Guava提供了另一种字符串连接器,也可以使用:

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

7. 使用Stream.generate方法生成字符串

创建子字符串列表的缺点是我们会在构造最终字符串之前创建一个可能很大的临时列表对象。

然而,从Java 8开始,我们可以使用Stream API的generate方法。结合limit方法(定义长度)和collect方法,我们可以生成包含N个重复字符的字符串

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

8. 使用Apache的RandomStringUtils生成字符串

Apache Commons库中的RandomStringUtils类提供了使用random方法生成包含N个重复字符的字符串的功能。我们需要定义一个字符和重复次数:

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

9. 结论

在这篇文章中,我们了解了生成包含N个重复字符字符串的各种方法。其中最简单的是JDK 11及以后版本的String.repeat

对于早期的Java版本,还有许多其他可能的选择。最好的选择将取决于我们的需求,包括运行时效率、编码简洁性和可用库。如往常一样,这些示例的代码可以在GitHub上找到。