2016-04-05 18 views
6

Nach Effektive Java 2nd Ed, wenn Sie eine Methodensignatur schreiben möchten, die Varargs erlaubt, aber immer noch ein Element Minimum zur Kompilierzeit erzwingt, sollten Sie die Methodensignatur auf diese Weise schreiben :Java 8 streams und varargs

public void something(String required, String ... additional) { 
    //... do what you want to do 
} 

Wenn ich all diese Elemente streamen will, ich habe so etwas wie dies getan:

public void something(String required, String ... additional) { 
    Stream<String> allParams = 
     Stream.concat(Stream.of(required), Stream.of(additional)); 
    //... do what you want to do 
} 

Das fühlt sich wirklich unelegant und verschwenderisch, vor allem, weil ich einen Strom von 1 bin die Schaffung und concatena Ting es mit einem anderen. Gibt es einen saubereren Weg, dies zu tun?

+5

'Stream.concat' gut zu mir scheint .. .it ist kurz, prägnant, es erstellt keine Kopien der Daten. Sie erstellen ein paar zusätzliche Wrapper-Objekte, das ist alles. IMO ist wirklich nichts falsch daran. Programmieren Sie in Java, Sie müssen nur kleine Objekte für Dinge hier und da erstellen. 'Stream.concat' ist bereits Meilen vor dem Zusammenführen mit einer 'ArrayList' oder etwas ähnlichem. – Radiodef

+1

Ich stimme Radiodef zu, wenn Sie wirklich wollten, könnten Sie Ihre eigene Implementierung von 'Spliterator ' machen und sie mit 'StreamSupport.stream (spliterator, parallel) verwenden', aber ich fühle mich nicht so, das macht es lesbarer oder effizienter . –

Antwort

6

Hier ist ein Weg, es zu tun, ohne zwei Streams zu erstellen, obwohl Sie es vielleicht nicht mögen.

Stream.Builder<String> builder = Stream.<String>builder().add(required); 
for (String s : additional) { 
    builder.add(s); 
} 

Stream<String> allParams = builder.build(); 
+0

Sie können for-loop auch durch 'Stream.of (zusätzlich) ersetzen .forEach (builder);' –

+0

Beim erneuten Besuch und basierend auf den Kommentaren scheint mein ursprünglicher Weg in Ordnung zu sein. Diese Antwort scheint jedoch die beste Alternative zu meinen früheren Ansichten zu sein. Vielen Dank :) –

1

Wenn Sie bereit sind, Guava zu verwenden, können Sie Lists.asList(required, additional).stream(). Die Methode wurde entwickelt, um Varargs mit Mindestanforderungs-Idiom zu erleichtern.

Eine Randnotiz, halte ich die Bibliothek wirklich nützlich, aber es ist natürlich keine gute Idee, es nur deshalb hinzuzufügen. Überprüfen Sie die docs und sehen Sie, ob es für Sie von mehr Nutzen sein könnte.

2

Leider kann Java ziemlich ausführlich sein. Eine weitere Möglichkeit, dies zu erleichtern, besteht darin, einfach statische Importe zu verwenden. Meiner Meinung nach macht es Ihren Code nicht weniger klar, da jede Methode streambezogen ist.

Stream<String> allParams = 
    concat(of(required), of(additional)); 
1

Es ist nichts falsch mit den zusammengesetzten Streams. Diese Objekte sind leichtgewichtig, da sie sich nur auf die Quelldaten beziehen, aber keine Daten wie Arrayinhalte kopieren. Die Kosten für ein solches leichtgewichtiges Objekt sind möglicherweise nur relevant, wenn die tatsächliche Nutzlast ebenfalls sehr klein ist.

public void something(String required, String ... additional) { 
    somethingImpl(Stream.concat(Stream.of(required), Stream.of(additional))); 
} 
public void something(String required) { 
    somethingImpl(Stream.of(required)); 
} 
public void something(String required, String second) { 
    somethingImpl(Stream.of(required, second)); 
} 
private void somethingImpl(Stream<String> allParams) { 
    //... do what you want to do 
} 

so im Fall ein Argument nur Sie nicht nur Stream Instanzen, sondern auch die varargs Array (ähnlich Stream.of ‚s Überlastung) zu speichern: Solche Szenarien können mit spezialisierten, semantisch äquivalent Überlastungen gehandhabt werden. Dies ist ein übliches Muster, siehe zum Beispiel die Überladungen EnumSet.of. In vielen Fällen sind selbst diese einfachen Überladungen nicht notwendig und könnten als vorzeitige Optimierung angesehen werden (Bibliotheken wie JRE bieten sie an, da es für einen Anwendungsentwickler sonst unmöglich ist, sie hinzuzufügen, wenn sie jemals benötigt werden). Wenn something Teil einer Anwendung und nicht einer Bibliothek ist, sollten Sie sie nicht hinzufügen, es sei denn, ein Profiler teilt Ihnen mit, dass ein Flaschenhals durch diese Parameterverarbeitung verursacht wird.

1

Erweiterungen von Drittanbietern zum Streamen von API wie meine StreamEx oder jOOλ Methoden bieten wie append oder prepend, die es Ihnen ermöglichen, diese sauberen Art und Weise, mehr zu tun:

// Using StreamEx 
Stream<String> allParams = StreamEx.of(required).append(additional); 
// Using jOOL 
Stream<String> allParams = Seq.of(required).append(additional);