Se aggiungi importazioni statiche per Stream.concat e Stream.of , il primo esempio potrebbe essere scritto come segue:
Stream<Foo> stream = concat(stream1, concat(stream2, of(element)));
L'importazione di metodi statici con nomi generici può risultare in codice che diventa difficile da leggere e mantenere ( inquinamento dello spazio dei nomi ). Quindi, potrebbe essere meglio creare i tuoi metodi statici con nomi più significativi. Tuttavia, per dimostrazione, rimarrò con questo nome.
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));
}
Con questi due metodi statici (facoltativamente in combinazione con importazioni statiche), i due esempi potrebbero essere scritti come segue:
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);
Il codice ora è significativamente più breve. Tuttavia, sono d'accordo sul fatto che la leggibilità non è migliorata. Quindi ho un'altra soluzione.
In molte situazioni, i Collezionisti possono essere utilizzati per estendere la funzionalità dei flussi. Con i due Collezionisti in fondo, i due esempi potrebbero essere scritti come segue:
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);
L'unica differenza tra la sintassi desiderata e la sintassi sopra è che devi sostituire concat (...) con collect (concat (...)) . I due metodi statici possono essere implementati come segue (facoltativamente usato in combinazione con importazioni statiche):
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));
}
Ovviamente c'è un inconveniente con questa soluzione che dovrebbe essere menzionata. raccogliere è un'operazione finale che consuma tutti gli elementi del flusso. Inoltre, il collat concat crea un ArrayList intermedio ogni volta che viene utilizzato nella catena. Entrambe le operazioni possono avere un impatto significativo sul comportamento del programma. Tuttavia, se la leggibilità è più importante delle prestazioni , potrebbe essere comunque un approccio molto utile.