1

Is there a general best approach for var-arg method signatures with respect to the Java 8 Lambda/Closure?

In a situation where a method is used either with a single object as a parameter or a collection of objects I see three options to realize this:

 private void optionOneVararg(String... params) { ... }
 private void optionTwoCollection(Collection<String> params) { ... }
 private void optionThreeStream(Stream<String> params) { ... }

The String class is obviously used as an example.

Is there a general valid "best practise" approach to this? The vararg approach produced the slickest code up to Java 7. With streams it feels clumsy.

I would like to be able to use the convenience of lambdas both inside the method and outside where I call it. Also I would like to keep wrapping/gluecode (e.g. Collections.singletonList(element) or Arrays.asList(element)) to a minimum and avoid using Collection myCollection = stream.collect(...) followed by a myCollection.stream().

M A
  • 71,713
  • 13
  • 134
  • 174
SebastianH
  • 2,172
  • 1
  • 18
  • 29
  • What don't you like about the vararg option? – assylias Jan 02 '17 at 14:16
  • On the var-args topic you might want to have a look at [this question](http://stackoverflow.com/questions/766559/when-do-you-use-varargs-in-java). –  Jan 02 '17 at 14:18
  • @assylias When I use operations on a stream (e.g. filter), then pass the result to my function and then use more stream operations on that parameter, the vararg array requires a collect of the first stream before it can be handed to the function. – SebastianH Jan 02 '17 at 14:34
  • Why don't you just overload the method with different argument options? Just like what many methods in the Java API already do? – Klitos Kyriacou Jan 05 '17 at 18:09

2 Answers2

2

You can still use the Stream API and lambdas in the method by invoking Stream.of(String...). In this case you can keep the signature with the varargs:

private void optionVarArgs(String... params) {
   Stream.of(params)...
   ...
}
M A
  • 71,713
  • 13
  • 134
  • 174
0

Thanks to AR.3s answer I realized that keeping the Stream as a parameter is superior in both the performance and the esthetic aspect:

private void callOptionThreeFromStream() {
    List<String> foo = Arrays.asList(new String[] { "a", "b", "c" });
    Stream<String> stream = foo.stream();
    // use stream here
    optionThreeStream(stream);
}
private void callOptionThreeFromObject() {
    String bar = "a";
    optionThreeStream(Stream.of(bar)); //very simple conversion
}
private void optionThreeStream(Stream<String> params) {
    // use the same stream (and possibly profit from optimization)
}

Using a vararg parameter causes more overhead (at least esthetically):

private void callOptionOneFromStream() {
    List<String> foo = Arrays.asList(new String[] { "a", "b", "c" });
    Stream<String> stream = foo.stream();
    // use stream here
    optionOneVararg(stream.toArray(String[]::new)); //still clumsy
}
private void callOptionOneFromObject() {
    String bar = "a";
    optionOneVararg(bar); //but optimal here
}
private void optionOneVararg(String... params) {
    Stream<String> stream = Stream.of(params);
    // use the new stream on the newly created array
}

And for the sake of completeness:

private void callOptionTwoFromStream() {
    List<String> foo = Arrays.asList(new String[] { "a", "b", "c" });
    Stream<String> stream = foo.stream();
    // use stream here
    optionTwoCollection(stream.collect(Collectors.toList())); //clumsy
}
private void callOptionTwoFromObject() {
    String bar = "a";
    optionTwoCollection(Collections.singletonList(bar)); //clumsy
}
private void optionTwoCollection(Collection<String> params) {
    Stream<String> stream = params.stream();
    // use the new stream on the newly created collection
}

My personal conclusion: Use Stream for private methods. Keeping var-arg or Collections in public API methods might be better suited though to hide internal technical details.

It's a nice detail that Stream.of uses a var-arg parameter to cover arrays and single objects at once.

SebastianH
  • 2,172
  • 1
  • 18
  • 29
  • `Stream.of()` does not use varargs to cover single objects. The `of()` method is overloaded. See: http://stackoverflow.com/questions/35802272/why-overload-the-varargs-method-of-in-java-stream-interface – jaco0646 Jan 05 '17 at 20:12
  • Very good catch! Thanks. It's not that I care about that kind of micro optimization in my code, but your question was a good read. It also gives another argument to hand over the stream to the inner function when available. – SebastianH Jan 07 '17 at 18:39