Wenn Sie statische Importe für Stream.concat und Stream.of hinzufügen , könnte das erste Beispiel wie folgt geschrieben werden:
Stream<Foo> stream = concat(stream1, concat(stream2, of(element)));
Das Importieren statischer Methoden mit generischen Namen kann zu Code führen, der schwer zu lesen und zu warten ist ( Namespace-Verschmutzung ). Daher ist es möglicherweise besser, eigene statische Methoden mit aussagekräftigeren Namen zu erstellen . Zur Demonstration werde ich mich jedoch an diesen Namen halten.
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));
}
Mit diesen beiden statischen Methoden (optional in Kombination mit statischen Importen) könnten die beiden Beispiele wie folgt geschrieben werden:
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);
Der Code ist jetzt deutlich kürzer. Ich stimme jedoch zu, dass sich die Lesbarkeit nicht verbessert hat. Ich habe also eine andere Lösung.
In vielen Situationen können Collectors verwendet werden, um die Funktionalität von Streams zu erweitern. Mit den beiden Sammlern unten könnten die beiden Beispiele wie folgt geschrieben werden:
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);
Der einzige Unterschied zwischen Ihrer gewünschten Syntax und der obigen Syntax besteht darin, dass Sie concat (...) durch collect (concat (...)) ersetzen müssen . Die beiden statischen Methoden können wie folgt implementiert werden (optional in Kombination mit statischen Importen verwendet):
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));
}
Natürlich gibt es bei dieser Lösung einen Nachteil, der erwähnt werden sollte. Das Sammeln ist eine letzte Operation, die alle Elemente des Streams verbraucht. Darüber hinaus erstellt der Collector Concat bei jeder Verwendung in der Kette eine Zwischen- ArrayList . Beide Vorgänge können erhebliche Auswirkungen auf das Verhalten Ihres Programms haben. Wenn jedoch die Lesbarkeit wichtiger ist als die Leistung , ist dies möglicherweise immer noch ein sehr hilfreicher Ansatz.