Primitive collections support breaks existing code

Brian Goetz brian.goetz at oracle.com
Mon Nov 19 08:36:49 PST 2012


More generally: the philosophy behind having specialized primitive 
streams (e.g., IntStream) is fraught with nasty tradeoffs.  On the one 
hand, it's lots of ugly code duplication, interface pollution, etc.  On 
the other hand, any kind of arithmetic on boxed ops sucks, and having no 
story for reducing over ints would be terrible.  So we're in a tough 
corner, and we're trying to not make it worse.

Trick #1 for not making it worse is: we're not doing all eight primitive 
types.  We're doing int, long, and double; all the others could be 
simulated by these.  Arguably we could get rid of int too, but we don't 
think most Java developers are ready for that.  Yes, there will be calls 
for Character, and the answer is "stick it in an int."  (Each 
specialization is projected to ~100K to the JRE footprint.)

Trick #2 is: we're using primitive streams to expose things that are 
best done in the primitive domain (sorting, reduction) but not trying to 
duplicate everything you can do in the boxed domain.  For example, 
there's no IntStream.into(), as Aleksey points out.  (If there were, the 
next question(s) would be "Where is IntCollection?  IntArrayList? 
IntConcurrentSkipListMap?)  The intention is many streams may start as 
reference streams and end up as primitive streams, but not vice versa. 
That's OK, and that reduces the number of conversions needed (e.g., no 
overload of map for int -> T, no specialization of Function for int -> 
T, etc.)

On 11/19/2012 11:23 AM, Aleksey Shipilev wrote:
> On 11/19/2012 08:02 PM, Brian Goetz wrote:
>> it will prefer IntFunction.  Probably best to update tests that
>> currently map to a primitive but are intended to test reference streams
>> cast to references.
>
> In most of our tests, there is not provisioning yet on the
> reference-vs-primitive. Some day we will have to split those up.
>
>>>    1. Is there a timeline for skeleton implementations for IntStream? If
>>> that would take longer than, say, a week, I would work that around in
>>> the tests.
>>
>> Depends what you mean by skeleton!  We've got filter/map/reduce already :)
>
> Hmmm, nope? This fails:
>
>      @Test
>      public void test4() {
>          Assert.assertEquals(
>                  Integer.valueOf(9),
>                  Arrays.asList("Foo", "BarBar", "BazBazBaz")
>                          .stream()
>                          .map(s -> s.length())
>                          .reduce((l, r) -> (l > r ? l : r))
>                          .get()
>          );
>      }
>
> with:
>
> java.lang.UnsupportedOperationException
>    at java.util.stream.primitive.IntPipeline.reduce(IntPipeline.java:137)
>    at net.openjdk.streams.StreamAPITest.test4(StreamAPITest.java:54)
>
>
>> Yes, because you'd have to box anyway.  The idea is that primitive
>> streams are primarily there for supporting reduction on primitives (sum,
>> min, max, etc.)  There is a "boxed" op that gets you back to
>> Stream<Integer>:
>>
>>                    Arrays.asList("Foo", "Bar", "Baz")
>>                            .stream()
>>                            .map(String::length)
>>                            .boxed()
>>                            .into(new ArrayList<Integer>())
>
> Yes, boxed() is nice and enough.
>
> Thanks,
> -Aleksey.
>


More information about the lambda-dev mailing list