18

I have the following code:

Stream.of("1,2,3,4".split(",")).mapToDouble(Double::valueOf).collect(Collectors.toList());

I want to return List<Double>.

This code doesn't compile.

I see error:

Error:(57, 69) java: method collect in interface java.util.stream.DoubleStream cannot be applied to given types;
  required: java.util.function.Supplier<R>,java.util.function.ObjDoubleConsumer<R>,java.util.function.BiConsumer<R,R>
  found: java.util.stream.Collector<java.lang.Object,capture#1 of ?,java.util.List<java.lang.Object>>
  reason: cannot infer type-variable(s) R
    (actual and formal argument lists differ in length)

How to fix this issue?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • 2
    Why you use `mapToDouble` is you want to collect it into a list directly after ? Just use `map`. You want to do the conversion `String -> Double -> double -> Double` while `String -> Double` is sufficient. – Alexis C. Oct 07 '15 at 14:08
  • 1
    What is strange ? You're providing a function `String -> Double`, if you want to collect it into a `List`, it has to be a `Double`. – Alexis C. Oct 07 '15 at 14:12
  • Alexis C. Does DoubleStream primitive stream? – gstackoverflow Oct 07 '15 at 14:20
  • 1
    https://docs.oracle.com/javase/8/docs/api/java/util/stream/DoubleStream.html – Alexis C. Oct 07 '15 at 14:27

1 Answers1

38

You could use boxed(). This maps a DoubleStream (Stream of primitive doubles, as returned by mapToDouble) to a Stream<Double>.

Stream.of("1,2,3,4".split(",")).mapToDouble(Double::parseDouble).boxed().collect(Collectors.toList());

Note that I changed Double::valueOf to Double::parseDouble: this prevents the Double returned by Double.valueOf to be unboxed to the primitive double.

But why are you using mapToDouble to begin with? You could just use map like this:

Stream.of("1,2,3,4".split(",")).map(Double::valueOf).collect(Collectors.toList());
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 4
    …and for potentially larger streams, I’d recommend `Pattern.compile(",").splitAsStream("1,2,3,4,…")` as it doesn’t need to populate an array to create the stream. – Holger Oct 07 '15 at 14:50
  • 2
    @Holger, on the other hand `.split(",")` is a fast path which does not create a regexp object and `Matcher` at all. It's not very clear at which number of tokens the `splitAsStream` will outperform the `String.split`... – Tagir Valeev Oct 07 '15 at 15:59
  • 1
    @Tagir Valeev: that’s always the case that you don’t know the “large number” threshold exactly. But it’s clear that with a growing number of generated substrings you can ignore the overhead of a single pattern/matcher object. – Holger Oct 07 '15 at 16:23
  • 1
    Um, why wouldn't you use `Stream.of(1,2,3,4)` and skip the splitting entirely? – Louis Wasserman Oct 07 '15 at 17:12
  • @Louis Wasserman: since the result gets collected into a `List`, using `Arrays.asList(1,2,3,4)` would be even simpler, eliding the entire stream stuff. But then, it wouldn’t be useful example code for this stream question anymore. Besides that, `Stream.of(1,2,3,4)` isn’t as efficient as you might think. Since it’s a varargs method invocation, the resulting code creates and populates an array before `Stream.of` gets invoked. In contrast, `"1,2,3,4"` is a constant that gets loaded by a single instruction and the splitting happens in JRE library code… – Holger Oct 08 '15 at 08:21
  • @Holger the constant gets loaded by a single instruction, but it ends up still being parsed into one element at a time. I would be frankly quite surprised if it were physically possible for your approach to be faster than the varargs. – Louis Wasserman Oct 08 '15 at 16:26
  • @Louis Wasserman: not faster, but also not significantly slower. Unless we are talking about a really performance critical code (in which case there are better alternatives to both), the smaller code size might be the better goal. This is especially true, when you have multiple places where you use that. Each varargs invocation makes up a distinct array population code, whereas the JRE’s splitting code is shared and gets optimized when it becomes a hotspot. The results may indeed be counter-intuitive. – Holger Oct 08 '15 at 17:00