This quote explains the considerations behind having primitive streams. I'm assuming the same applied to primitive Optionals. In short, primitive streams (and probably Optionals as well) were created for performance reasons. They didn't create them for all 8 primitive types to reduce code duplication and interface pollution.
Quoting the words of Brian Goetz in the lambda mailing list:
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.)
And I should mention that I found that quote in the answer to this question.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…