创建一个包含n个字符的字符串。

186

在Java中是否有一种方法可以创建一个具有特定数量特定字符的字符串? 在我的情况下,我需要创建一个包含十个空格的字符串。 我当前的代码是:

final StringBuffer outputBuffer = new StringBuffer(length);
for (int i = 0; i < length; i++){
   outputBuffer.append(" ");
}
return outputBuffer.toString();

有没有更好的方法实现同样的事情?特别是,我想要一个执行速度快的解决方案。


1
如果你发现自己经常这样做,那就写一个函数:String characterRepeat(Char c, int Length){ ... },它可以针对任何字符和任何长度执行你所做的操作。然后在需要时只需调用它即可。 - Austin Fitzpatrick
12
建议使用 StringBuilder 而不是 StringBuffer。 - user177800
在缓冲区的开头添加大小,容易计算并简化内存管理!StringBuilder outputBuffer = new StringBuilder(repeat * base.length()); - Victor
1
参见:https://dev59.com/U3M_5IYBdhLWcg3ww2Ob - Dave Jarvis
如果您想添加一个空格,请使用append(' '),这样可以减少一些计算量。 - Erk
Java 8:Stream和nCopies - https://dev59.com/5XE85IYBdhLWcg3wYSZk#51925748 - akhil_mittal
27个回答

192

使用String API 可能是最短的代码:

String space10 = new String(new char[10]).replace('\0', ' ');

System.out.println("[" + space10 + "]");
// prints "[          ]"
作为一种方法,不直接实例化char
import java.nio.CharBuffer;

/**
 * Creates a string of spaces that is 'spaces' spaces long.
 *
 * @param spaces The number of spaces to add to the string.
 */
public String spaces( int spaces ) {
  return CharBuffer.allocate( spaces ).toString().replace( '\0', ' ' );
}

使用以下方式调用:

System.out.printf( "[%s]%n", spaces( 10 ) );

4
虽然我喜欢这个一行代码的解决方案,但在执行时,我认为FrustratedWithFormsDes的解决方案更好,因为它避免了检查每个字符是否为\0,而是直接赋值空格。 - Bouncner
1
经过测试,这种方法总是比循环更快,通常快50000-100000纳秒,这可能相当显著(0.1毫秒)。虽然循环的速度随着迭代次数的增加而加快,但总时间仍然很长。这对于创建不同大小的空格字符串也适用。 - kmecpp
点赞这个相当不错的解决方案,我已经在我的答案中使用了它:https://dev59.com/7XRA5IYBdhLWcg3wuAUo#43381186 - Maytham Fahmi

95

我强烈建议不要手动编写循环。在你的编程生涯中,你将一遍又一遍地这样做。阅读你的代码-包括你自己-总是需要投入时间,即使只是几秒钟,来消化循环的含义。

相反,重复使用其中一个提供相同功能的可用库,例如Apache Commons Lang中的StringUtils.repeat

StringUtils.repeat(' ', length);

这样,您也不必担心性能问题,因此所有关于StringBuilder、编译器优化等的细节都被隐藏了起来。如果函数执行缓慢,那么这将是库的一个错误。

使用Java 11甚至更容易:

" ".repeat(length);

8
另一方面,如果项目中尚未使用StringUtils,为了完成这样一个简单的任务而添加另一个依赖可能有些过度。 - Erich Kitzmueller
1
如果函数运行缓慢,您可以提交自己的修复程序。 - will

77

想了一下,也许可以使用Arrays.fill

char[] charArray = new char[length];
Arrays.fill(charArray, ' ');
String str = new String(charArray);

当然,我假设fill方法和你的代码实现了相同的功能,所以它们的性能可能差不多,但至少这个方法更加简洁。


2
在检查源代码后,似乎这确实做到了OP发布的内容:http://www.docjar.com/html/api/java/util/Arrays.java.html的第806行。 - Pops
2
@Lord Torgamus,OP的问题被编辑过吗?因为在我看到的版本中,他正在循环使用StringBuffer.append(),而Frustrated的版本正在执行填充操作(当然是通过对数组进行字符赋值来循环)。这完全不同。 - CPerkins
@CPerkins,说得对,我表达不够清楚。我的意思是他们两个都在for循环内逐个字符进行插入操作。 - Pops
3
@Lord Torgamus - 同意这一点。可惜JVM不能直接进行memset操作。这是我们为了宽字符所付出的代价。 - CPerkins
有人知道是否可以将值为0的64位长值写入char字符串中吗?(假设我们想将字符串长度固定为64/65)? - Bouncner
2
@Pops 值得注意的是,如果在代码以及(标准和外部)库代码中一致地使用Arrays.fill()函数来完成这个任务,那么它就成为了热点编译的良好候选,并有更大的可能被CPU缓存发现。未来的JVM可能会将其分配为内部函数。自己编写代码会使你失去所有这些性能优化的好处... - SusanW

63

自Java 11版本以来:

" ".repeat(10);

自Java 8起:


generate(() -> " ").limit(10).collect(joining());

其中:

import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.generate;

1
希望Java能够从Python这里学习。就像System.out.println("="*10);这样的东西。 - JGFMK
3
我觉得在这里使用"=".repeat(10)"=" * 10几乎是一样的。使用"=".repeat(10)更加明确、更少出错(例如,在Python中,'=' * 10'==========',但在Java中为610),而且长度相差不大。 - cdgraham

42

for循环将被编译器优化。在像你这样的情况下,你不需要自己关注优化。相信编译器。

顺便说一句,如果有一种方法可以创建包含n个空格字符的字符串,那么它的编码方式与你刚才做的方式相同。


1
即使这没有被优化 - 在你的程序中创建了多少次 - 如果经常创建,可以保存在静态变量或其他缓存中。 - mmmmmm
顺便提一下,Array.fill() 只是循环遍历数组。我需要更多的积分才能评论别人的帖子 :) - kalkin
@Mark 长度是可变的,因此保存它似乎很愚蠢。我该怎么做,使用 static Dictionary<int, String> 吗? - C. Ross
1
存储您将要使用的最长字符串,然后使用以下类似的代码:" ".substring(0, 10); - mjaggard

31
在Java 8中,您可以使用String.join
String.join("", Collections.nCopies(n, s));

14
自 Java 11,您可以简单地使用 String.repeat(count) 方法来解决您的问题。
返回一个字符串,其值是将此字符串重复 count 次的连接。如果此字符串为空或 count 为零,则返回空字符串。
因此,您的代码不需要循环,只需要像这样编写:
" ".repeat(length);

14

如果你只想要空格,可以尝试以下代码:

String spaces = (n==0)?"":String.format("%"+n+"s", "");

这将导致 abs(n) 个空格;


7
速度如何?我印象中格式化相对较慢。毕竟它必须在创建之前解析字符串。 - C. Ross

8
您可以使用标准的String.format函数生成N个空格。例如:
String.format("%5c", ' ');

生成一个包含5个空格的字符串。

或者

int count = 15;
String fifteenSpacebars = String.format("%" + count + "c", ' ');

生成一个由15个空格组成的字符串。

如果你想重复另一个符号,你必须用你想要的符号替换空格:

int count = 7;
char mySymbol = '#';
System.out.println(String.format("%" + count + "c", ' ').replaceAll("\\ ", "\\" + mySymbol));

输出:

#######

8

1
最短的代码行,但仅为了完成这个简单的任务而添加一个大型库是没有意义的。我可以自己创建一个更小的JAR,其中只有一个方法pubic String n(int n) { ... },这将允许使用更少的代码:n(10),但同样也没有任何意义。 - isapir
@isapir 这是一个非常好的答案,适用于已经在使用Guava的人们。 - nasch
2
@nasch Guava不是问题的一部分。但无论如何,在2018年,当您可以使用Java 8中添加的String.join()时,没有理由使用Guava的Joiner。请参见https://dev59.com/5XE85IYBdhLWcg3wYSZk#43011939 - isapir
@isapir 不是的,Guava 是一个答案。在 StackOverflow 上的回答面向的受众不仅仅是提问者本人,因此如果某些答案对于提问者来说并不是最好的,也没有关系。而关于 String.join() 的评论是非常好的,尽管我不确定它是否在所有版本的 Android 上都可用,因为 Android 是 Java 的一个重要应用领域。 - nasch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接