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