如何使用Java 8流(Streams)替换方法?

8

这可能是一个显而易见的问题,但我在思考如何使用Java 8流来替换以下方法。

private String assembleString(int numberOfCharacters, char character) {
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < numberOfCharacters; i++) {
        stringBuilder.append(character);
    }
    return stringBuilder.toString();
}

我是Java新手,所以对于Java 8来说,它就像一个未被探索的世界。

谢谢!


3
为什么你想在这么简单的事情上使用流呢?请不要只是为了使用流而使用它。 - Thomas Timbul
1
@ThomasTimbul,总是先用最简单的方法学习某些东西更容易,他似乎正在尝试学习某些东西。 - Al-Mothafar
1
请记住,流并不是默认情况下更快/更好的。不要仅仅因为它是“时髦的Java 8”而使用它们... - LenglBoy
@Al-Mothafar 我会从简单的List/Map/Collection操作开始,就像所有教程中展示的那样,而不是填充String,因为创建与Stream相关的对象过于繁琐,并且并不能导致更好或更易读的代码。为了清理发布的代码,我会使用像Commons StringUtils这样的库,而不是仅仅因为我能用Streams。 - Thomas Timbul
6个回答

6

您只需要使用Collections.nCopies方法即可实现此操作。

private static String assembleString(int numberOfCharacters, char character) {
    return String.join("",
            Collections.nCopies(numberOfCharacters, String.valueOf(character))
    );
}

2
你可以使用 Stream.generate
return Stream.generate(() -> String.valueOf(character))
              .limit(numberOfCharacters)
              .collect(Collectors.joining());

或者使用 IntStream.rangeClosed

return IntStream.rangeClosed(1, numberOfCharacters)
                .mapToObj(n -> String.valueOf(character))
                .collect(Collectors.joining());

2
这应该足够了。
IntStream.range(0, numberOfCharacters)  
  .mapToObj(value -> character)
  .forEach(stringBuilder::append);

编辑:

根据Holger的建议,这样做会更加实用和简洁。

IntStream.range(0, numberOfCharacters) 
  .map(value -> character) .collect(StringBuilder::new, 
     StringBuilder::appendCodePoint, StringBuilder::append);

在这个页面上,对于基于流的最干净的实现加1——它是唯一一个不会在过程中创建多余字符串的实现。 - Thomas Timbul
@ThomasTimbul,更加简洁的写法是.map(value -> character) .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append),而不是.mapToObj(value -> character) .forEach(stringBuilder::append),这样可以直接将结果添加到现有的StringBuilder中,同时避免了装箱成Character对象。 - Holger
应该是 forEachOrdered 吧? - Anton Balaniuc
2
@AntonBalaniuc 当我们只是重复添加相同的字符n次时,它是否有序并不重要,对吧。 - pvpkiran

1
使用 IntStream:

private String assembleString(int numberOfCharacters, char character) {
        return IntStream.range(0, numberOfCharacters)
               .mapToObj(i -> String.valueOf(character)).collect(Collectors.joining());
    }

1

使用 Java 11+,您还可以使用String::repeat

return String.repeat(Character.toString(character), numberOfCharacters);

或者你可以“偷”他们的实现:

char[] repeated = new char[numberOfCharacters];
Arrays.fill(repeated, character);
return new String(repeated);

1
Arrays.fill(...)也是我想到的第一件事。当然,String本身内部实现的repeat方法避免了数组的防御性复制。 - Holger

1

仅为“完整性”,没有明显的循环或流:

private String assembleString(int numberOfCharacters, char character) {
    return new String(new char[numberOfCharacters]).replace('\0', character);
}

如何:创建一个大小为“numberOfCharacters”的新字符数组,该数组将用“null”字符初始化。从该数组构造一个字符串,然后将所有出现的null字符替换为所需字符。

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