Якщо ви додасте статичний імпорт для 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 (...) на collection (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));
}
Звичайно, є недолік у цьому рішенні, який слід зазначити. збирати - це заключна операція, яка споживає всі елементи потоку. Крім того, колектор CONCAT створює проміжний ArrayList кожен раз , коли він використовується в ланцюзі. Обидві операції можуть мати істотний вплив на поведінку вашої програми. Однак, якщо читабельність важливіша за ефективність , це все ще може бути дуже корисним підходом.