Если вы добавите статический импорт для Stream.concat и Stream.of , первый пример может быть записан следующим образом:
Stream<Foo> stream = concat(stream1, concat(stream2, of(element)));
Импорт статических методов с родовыми именами может привести к тому, что код станет трудным для чтения и обслуживания ( загрязнение пространства имен ). Поэтому может быть лучше создать свои собственные статические методы с более значимыми именами. Однако для демонстрации я буду придерживаться этого имени.
public static <T> Stream<T> concat(Stream<? extends T> lhs, Stream<? extends T> rhs) {
return Stream.concat(lhs, rhs);
}
public static <T> Stream<T> concat(Stream<? extends T> lhs, T rhs) {
return Stream.concat(lhs, Stream.of(rhs));
}
С помощью этих двух статических методов (возможно, в сочетании со статическим импортом) эти два примера можно записать следующим образом:
Stream<Foo> stream = concat(stream1, concat(stream2, element));
Stream<Foo> stream = concat(
concat(stream1.filter(x -> x!=0), stream2).filter(x -> x!=1),
element)
.filter(x -> x!=2);
Код теперь значительно короче. Тем не менее, я согласен, что читаемость не улучшилась. Так что у меня есть другое решение.
Во многих ситуациях коллекторы могут использоваться для расширения функциональности потоков. С двумя коллекторами внизу два примера можно записать следующим образом:
Stream<Foo> stream = stream1.collect(concat(stream2)).collect(concat(element));
Stream<Foo> stream = stream1
.filter(x -> x!=0)
.collect(concat(stream2))
.filter(x -> x!=1)
.collect(concat(element))
.filter(x -> x!=2);
Единственная разница между вашим желаемым синтаксисом и приведенным выше синтаксисом заключается в том, что вы должны заменить concat (...) на collect (concat (...)) . Два статических метода могут быть реализованы следующим образом (необязательно используется в сочетании со статическим импортом):
private static <T,A,R,S> Collector<T,?,S> combine(Collector<T,A,R> collector, Function<? super R, ? extends S> function) {
return Collector.of(
collector.supplier(),
collector.accumulator(),
collector.combiner(),
collector.finisher().andThen(function));
}
public static <T> Collector<T,?,Stream<T>> concat(Stream<? extends T> other) {
return combine(Collectors.toList(),
list -> Stream.concat(list.stream(), other));
}
public static <T> Collector<T,?,Stream<T>> concat(T element) {
return concat(Stream.of(element));
}
Конечно, у этого решения есть недостаток, о котором следует упомянуть. collect - это последняя операция, которая потребляет все элементы потока. Кроме того, concat сборщика создает промежуточный ArrayList каждый раз, когда он используется в цепочке. Обе операции могут оказать существенное влияние на поведение вашей программы. Однако, если удобочитаемость важнее производительности , это может быть очень полезным подходом.