Here's the non-stream code that I want to reproduce using only the streaming api if possible:
List<String> list = Arrays.asList("one", "two", "three", "four");
list.removeIf(s -> s.length() <= 3);
if (!list.isEmpty()) {
System.out.println("before");
for (String elem : list) {
System.out.println(elem);
}
System.out.println("after");
}
Of course simple iteration is easy with a stream:
List<String> list = Arrays.asList("one", "two", "three", "four");
list.stream()
.filter(s -> s.length() > 3)
.forEach(System.out::println);
But I need to add the "before" and "after" lines only if the stream is not empty after filtering. Is this possible in one statement or do I need to collect
?
This hardly seems like a better solution...
List<String> list = Arrays.asList("one", "two", "three", "four");
List<String> filtered = list.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
if (!filtered.isEmpty()) {
System.out.println("before");
filtered.stream().forEach(System.out::println);
System.out.println("after");
}
Update: The examples above with Strings are too simple. I actually need to write a json array if the filtered list is not empty. I cannot write an empty array.
private void writeJsonArray(JsonGenerator g, List<String> list) {
list.removeIf(s -> s.length() <= 3);
if (!list.isEmpty()) {
g.writeArrayFieldStart("arr");
for (String elem : list) {
g.writeString(elem);
}
g.writeEndArray();
}
}
CodePudding user response:
You can use anyMatch()
and Collectors.joining()
with prefix and suffix:
private static String NEW_LINE = System.lineSeparator();
public static void print(List<String> list) {
String str = list.stream().anyMatch(s -> s.length() > 3)
? list.stream().filter(s -> s.length() > 3)
.collect(Collectors.joining(NEW_LINE,
"before" NEW_LINE, NEW_LINE "after"))
: "";
System.out.println(str);
}
As an alternative approach, you can reduce the stream
using StringBuilder
as identity. Then, if the StringBuilder
isn't empty, you can insert "before"
and append "after"
. This approach performs only one terminal operation.
public static void print(List<String> list) {
StringBuilder sb = list.stream()
.filter(str -> str.length() > 3)
.reduce(new StringBuilder(),
(s, str) -> s.append(str).append(NEW_LINE),
StringBuilder::append);
if (!sb.isEmpty()) {
sb.insert(0, NEW_LINE).insert(0, "before")
.append("after");
}
System.out.println(sb.toString());
}
Test:
List<String> list = Arrays.asList("one", "two", "three", "four");
print(list);
Output:
before
three
four
after
CodePudding user response:
I would use Stream.concat for this:
Stream.concat(
Stream.of("before"),
Stream.concat(
list.stream().filter(s -> s.length() > 3),
Stream.of("after")))
.forEach(System.out::println);
You might find it more readable split the logic into separate statements:
Stream<String> stream = list.stream().filter(s -> s.length() > 3);
stream = Stream.concat(Stream.of("before"), stream);
stream = Stream.concat(stream, Stream.of("after"));
stream.forEach(System.out::println);