a primitive type and the other a boxed type. Primitive types are built into the language and
runtime environment as fundamental building blocks; boxed types are just normal Java
classes that wrap up the primitives.
Because Java generics are based around erasing a generic parameter—in other words, pre-
tending it's an instance of Object —only the boxed types can be used as generic arguments.
This is why if you want a list of integer values in Java it will always be List<Integer> and
not List<int> .
Unfortunately, because boxed types are objects, there is a memory overhead to them. For ex-
ample, although an int takes 4 bytes of memory, an Integer takes 16 bytes. This gets even
worse when you start to look at arrays of numbers, as each element of a primitive array is
just the size of the primitive, while each element of a boxed array is actually an in-memory
pointer to another object on the Java heap. In the worst case, this might make an Integer
take up nearly six times more memory than an int of the same size.
There is also a computational overhead when converting from a primitive type to a boxed
type, called boxing , and vice versa, called unboxing . For algorithms that perform lots of nu-
merical operations, the cost of boxing and unboxing combined with the additional memory
bandwidth used by allocated boxed objects can make the code significantly slower.
As a consequence of these performance overheads, the streams library differentiates between
the primitive and boxed versions of some library functions. The mapToLong higher-order
function and ToLongFunction , shown in Figure 4-1 , are examples of this effort. Only the
int , long , and double types have been chosen as the focus of the primitive specialization
implementation in Java 8 because the impact is most noticeable in numerical algorithms.
Figure 4-1. ToLongFunction
The primitive specializations have a very clear-cut naming convention. If the return type is a
primitive, the interface is prefixed with To and the primitive type, as in ToLongFunction
(shown in Figure 4-1 ). If the argument type is a primitive type, the name prefix is just the