使用Java-8,我可以使用String
或CharSequence
方法轻松将IntStream
(或任何chars
)视为codePoints
。
IntStream chars = "Hello world.".codePoints();
然后我可以操纵流的内容
IntStream stars = chars.map(c -> c == ' ' ? ' ': '*');
我一直在寻找一种打印结果的整洁方式,我甚至找不到一个简单的方法。如何将此int
流回放到可以String
打印的表单中。
从上面stars
我希望打印
***** ******
答案 0 :(得分:32)
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("[^ ]", "*")
更简单。并非一切都受益于lambdas。
答案 1 :(得分:18)
对Holger的效率稍低但更简洁的解决方案:
String result = "Hello world."
.codePoints()
.mapToObj(c -> c == ' ' ? " ": "*")
.collect(Collectors.joining());
Collectors.joining()
内部使用StringBuilder
,至少在OpenJDK sources。{/ p>
答案 2 :(得分:6)
其他答案显示如何将字符串流收集到单个字符串中以及如何从IntStream
收集字符。此答案显示如何在字符流上使用自定义收集器。
如果你想将一个int流收集到一个字符串中,我认为最干净,最通用的解决方案是创建一个静态实用程序方法,
返回收藏家。然后您可以像往常一样使用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
已被占用。
答案 3 :(得分: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());
}
它执行与my other answer完全相同的版本,但它一直使用流式传输。显然需要一些将单个代码点转换为字符串的功能:
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
中。
答案 4 :(得分:1)
我这样做的方法是使用 reduce 。要为每个字符和每个空格获取 * ,它将看起来像这样
String hello = "hello world";
String result = hello.chars()
.map(val -> (val == ' ') ? ' ' : '*')
.mapToObj(val -> String.valueOf((char) val))
.reduce("",(s1, s2) -> s1+s2);
关键是要使用 integers 进行任何操作,而不是将其转换为 characters ,然后将其映射为 String ,然后 concatenate < / em>,您可以使用 reduce 或 Collectors.joining()
答案 5 :(得分:0)
您可以使用以下代码直接执行此操作: -
"Hello world".codePoints().forEach(n -> System.out.print(n == ' ' ? ' ':'*'));
答案 6 :(得分:0)
有一个简单的答案,不太倾向于使用流媒体做所有事情。因此,它不是一个单行,但它可能更有效,更容易阅读:
public static String stars(String t) {
StringBuilder sb = new StringBuilder(t.length());
t.codePoints().map(c -> c == ' ' ? ' ' : '*').forEach(sb::appendCodePoint);
return sb.toString();
}
有时简短与简洁不一样,我认为没有人会想知道上述功能是如何运作的。
此解决方案可确保代码点永远不会转换回字符。因此,它比这里列出的其他一些解决方案更通用。
答案 7 :(得分: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);
答案 8 :(得分:0)
IntStream charStream = "hello".chars();
charStream.mapToObj(c -> (char)c).forEach(System.out::println);
这对我有用。
答案 9 :(得分:-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()));