Самый простой способ распечатать `IntStream` как` String`
С Java-8 я легко могу рассматривать String
(или любой CharSequence
) как IntStream
с помощью метода chars
или codePoints
.
IntStream chars = "Hello world.".codePoints();
Затем я могу манипулировать содержимым потока
IntStream stars = chars.map(c -> c == ' ' ? ' ': '*');
Я охотился за аккуратным способом распечатать результаты, и я не могу найти простой способ. Как поместить этот поток int
обратно в форму, которая может быть напечатана, как я могу String
.
Из вышеприведенного stars
я надеюсь напечатать
***** ******
Ответы
Ответ 1
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("[^ ]", "*")
проще. Не все выгоды от лямбда.
Ответ 2
Немного менее эффективное, но более сжатое решение для Хольгера:
String result = "Hello world."
.codePoints()
.mapToObj(c -> c == ' ' ? " ": "*")
.collect(Collectors.joining());
Collectors.joining()
внутренне использует StringBuilder
, по крайней мере, в источниках OpenJDK.
Ответ 3
Другие ответы показывают, как собирать поток строк в одну строку и как собирать символы из IntStream
. Этот ответ показывает, как использовать пользовательский коллекционер в потоке символов.
Если вы хотите собрать поток ints в строку, я думаю, что самым чистым и наиболее общим решением является создание статического утилитарного метода, который
возвращает коллекционер. Затем вы можете использовать метод 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
уже выполнено.
Ответ 4
Если нужно, мы можем сделать однострочный обход очень уродливым:
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
, конечно.
Ответ 5
То, как я это делаю, - это использование метода Reduce Чтобы получить * для каждого символа и пробел для каждого пробела, он будет выглядеть следующим образом
String hello = "hello world";
String result = hello.chars()
.map(val -> (val == ' ') ? ' ' : '*')
.mapToObj(val -> String.valueOf((char) val))
.reduce("",(s1, s2) -> s1+s2);
Суть в том, чтобы делать с целыми числами все, что угодно, чем приводить их к символам, затем сопоставлять их со строками, затем объединять, вы можете использовать Redu или Collectors.joining().
Ответ 6
Вы можете сделать это непосредственно со следующим кодом: -
"Hello world".codePoints().forEach(n -> System.out.print(n == ' ' ? ' ':'*'));
Ответ 7
Существует простой ответ, который немного менее склонен делать все с потоковой передачей. Следовательно, это не однострочный, но, вероятно, он более эффективен и очень легко читается:
public static String stars(String t) {
StringBuilder sb = new StringBuilder(t.length());
t.codePoints().map(c -> c == ' ' ? ' ' : '*').forEach(sb::appendCodePoint);
return sb.toString();
}
Иногда короткий - это не то же самое, что и краткий, я не думаю, что кто-то должен задаться вопросом, как работает вышеприведенная функция.
Это решение гарантирует, что кодовые точки никогда не будут преобразованы обратно в символы. Поэтому он несколько более общий, чем некоторые другие решения, перечисленные здесь.
Ответ 8
Как насчет этого?
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);
Ответ 9
Вы можете сделать:
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()));