54

使用 Java-8,我可以轻松地将 a String(或 any CharSequence)视为IntStream使用 thecharscodePoints方法。

IntStream chars = "Hello world.".codePoints();

然后我可以操纵流的内容

IntStream stars = chars.map(c -> c == ' ' ? ' ': '*');

我一直在寻找一种整洁的方法来打印结果,但我什至找不到简单的方法。我如何将这个ints 流放回一个可以像我一样打印的表单中String

从上面stars我希望打印

***** ******
4

10 回答 10

50
String result = "Hello world."
  .codePoints()
//.parallel()  // uncomment this line for large strings
  .map(c -> c == ' ' ? ' ': '*')
  .collect(StringBuilder::new,
           StringBuilder::appendCodePoint, StringBuilder::append)
  .toString();

不过,"Hello world.".replaceAll("[^ ]", "*")还是比较简单的。并非一切都受益于 lambda。

于 2013-11-28T14:39:30.233 回答
25

Holger 的效率稍低但更简洁的解决方案:

String result = "Hello world."
    .codePoints()
    .mapToObj(c -> c == ' ' ? " ": "*")
    .collect(Collectors.joining());

Collectors.joining()内部使用StringBuilder,至少在OpenJDK 源代码中。

于 2014-05-09T12:15:24.023 回答
6

其他答案显示如何将字符串流收集到单个字符串中,以及如何从IntStream. 这个答案显示了如何在字符流上使用自定义收集器。

如果要将整数流收集到字符串中,我认为最干净和最通用的解决方案是创建一个返回收集器的静态实用程序方法。然后,您可以Stream.collect像往常一样使用该方法。

该实用程序可以像这样实现和使用:

public static void main(String[] args){
    String s = "abcacb".codePoints()
        .filter(ch -> ch != 'b')
        .boxed()
        .collect(charsToString());

    System.out.println("s: " + s); // Prints "s: acac"
}

public static Collector<Integer, ?, String> charsToString() {
    return Collector.of(
        StringBuilder::new,
        StringBuilder::appendCodePoint,
        StringBuilder::append,
        StringBuilder::toString);
}

标准库中没有这样的东西有点令人惊讶。

这种方法的一个缺点是它需要将字符装箱,因为该IntStream接口不适用于收集器。

一个未解决的难题是实用程序方法应该命名。收集器实用程序方法的约定是调用它们toXXX,但toString已经采用。

于 2015-02-07T13:48:59.253 回答
1

有一个简单的答案,它不太倾向于使用流媒体做所有事情。因此,它不是单行的,但它可能更高效且易于阅读:

public static String stars(String t) {
    StringBuilder sb = new StringBuilder(t.length());
    t.codePoints().map(c -> c == ' ' ? ' ' : '*').forEach(sb::appendCodePoint);
    return sb.toString();
}

有时简短不等于简洁,我认为没有人想知道上述功能是如何运作的。

此解决方案确保代码点永远不会转换回字符。因此,它比此处列出的其他一些解决方案更通用。

于 2016-11-21T23:21:45.640 回答
1

如果必须,我们可以用这种极其丑陋的方式制作单线:

public static String stars(String t) {
    return t.codePoints().map(c -> c == ' ' ? ' ': '*').mapToObj(i -> new String(new int[] { i }, 0, 1)).collect(Collectors.joining());
}

它执行与我的其他答案完全相同的版本,但它一直使用流媒体。显然需要一些将单个代码点转换为字符串的函数:

public static String stars(String t) {
    return t.codePoints().map(c -> c == ' ' ? ' ': '*').mapToObj(Stars::codePointToString).collect(Collectors.joining());
}

private static String codePointToString(int codePoint) {
    return new String(new int[] { codePoint }, 0, 1);
}

这当然将这些功能放在类Stars中。

于 2016-11-21T23:36:54.710 回答
1

我这样做的方法是使用reduce。要为每个字符获取*并为每个空格获取空格,它看起来像这样

    String hello = "hello world";
    String result = hello.chars()
        .map(val -> (val == ' ') ?  ' ' : '*')
        .mapToObj(val -> String.valueOf((char) val))
        .reduce("",(s1, s2) -> s1+s2);

关键是对整数做任何你想做的事情,而不是将其转换为字符,然后将其映射到字符串,然后将其连接起来,你可以使用reduceCollectors.joining()

于 2019-08-20T23:11:53.427 回答
0

这个怎么样。

  System.out.println(stars.mapToObj(c -> String.format("%c", c)).collect(
            Collectors.joining()));

  or

  String s = stars.mapToObj(c -> String.format("%c", c)).reduce("",
            (a, b) -> a + b);
于 2019-08-20T23:20:49.107 回答
0

您可以使用以下代码直接执行此操作:-

"Hello world".codePoints().forEach(n -> System.out.print(n == ' ' ? ' ':'*'));
于 2016-04-18T09:15:16.477 回答
0
  IntStream charStream = "hello".chars();
  charStream.mapToObj(c -> (char)c).forEach(System.out::println);

这对我有用。

于 2020-01-01T22:48:27.790 回答
-1

你可以做:

chars.mapToObj(c -> c == ' ' ?  " ": "*").collect(joining());

另一个例子:

以下示例返回原始字符串。但这些可以与其他中间操作相结合,例如filter().

chars.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.joining()));

"abc".chars().mapToObj(i -> "" + (char) i)).collect(Collectors.joining()));
于 2018-09-25T16:53:31.793 回答