Java 8 primitive stream to collection mapping methods
Asked Answered
D

7

5

Is there any significant difference (in performance or best practices) between those two stream creation methods?

int[] arr2 = {1,2,3,4,5,6};

Arrays.stream(arr2)
      .map((in)->in*2)
      .mapToObj((in) -> new Integer(in))
      .collect(Collectors.toCollection(()-> new ArrayList<>()));

Arrays.stream(arr2)
      .map(in->in*2)
      .boxed()
      .collect(Collectors.toCollection(()-> new ArrayList<>()));

EDIT

Thanks to Stack Community answers I can add some addons to question completeness for new readers:

As many pointed out, .boxed() IntStream method is defined as:

@Override
    public final Stream<Integer> boxed() {
        return mapToObj(Integer::valueOf);
    }

What basically re-defines issue to which one of following is better:

.mapToObj(in -> new Integer(in))

or

.mapToObj(in -> Integer.valueOf(in))
Duester answered 31/12, 2018 at 9:19 Comment(3)
.mapToObj((in) -> Integer.valueOf(in*2))Brubeck
Never use new Integer, always Integer.valueOf. Beside, use Collectors.toList(). For the rest, write a benchmark.Certain
Besides all that new Integer(int x) is as well Deprecated since Java9. So just avoid using it.Tissue
A
7

Yes, boxed() uses Integer.valueOf which can retrieve some Integer instances from a cache.

So you should either use the version with boxed() (preferably), or use Integer.valueOf instead of new Integer(). Note that boxed() is in fact shorthand for mapToObj(Integer::valueOf).

Antoniaantonie answered 31/12, 2018 at 9:24 Comment(3)
Tomasz, I'm choosing your answer as accepted one because: it's most up-voted, your reputation in relatively small in number comparing to other users that provided feedback and covers all aspects. And we are both Poles ;) JK!Duester
@Duester " I'm choosing your answer as accepted one because..." then maybe you should accept answer to indicate so ;-)Hiphuggers
@Aomine Whoops, my bad :)Duester
W
5

The second is better as it creates no Integer objects in this example.

From the JLS 5.1.7

If the value p being boxed is ... an int ... between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

Generally speaking, you should not call new on wrapper types, but use their static factory methods - for example Integer.valueOf

Worldling answered 31/12, 2018 at 9:23 Comment(0)
H
4

In terms of best practice, the second approach is preferable because when you want to box a primitive value boxed is created exactly for that purpose and does so in the most optimised way possible whereas mapToObj, although can be used to achieve the same thing, is not the idiomatic approach.

Further, it's advised not to use the primitive wrapper type constructors anymore and instead favour the valueOf methods, this is because these constructors have been deprecated as well as the fact that by using the valueOf it reduces memory footprint compared to the constructors leading to better performance.

Hiphuggers answered 31/12, 2018 at 9:24 Comment(0)
R
4

IntStream.boxed() uses Integer.valueOf(int) which is an optimised version* of Integer(int).

Internally, boxed() is defined as mapToObj(Integer::valueOf).


*this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

The Javadoc of Integer.valueOf(int)

Rufinaruford answered 31/12, 2018 at 9:24 Comment(0)
S
3

The second one will effectively use the jvm's integer cache, thus it will be better both in performance, as well as a best practice (do not instantiate boxed types, rather let the vm do that for you).

You could imitate the same behavior if you changed the new Integer(in) with Integer.valueOf(in)

Sucker answered 31/12, 2018 at 9:23 Comment(0)
I
1

For both performance and best practices, we should choose boxed() over mapToObj((in) -> new Integer(in)).


Performance:

See below boxed() source code (in the abstract class IntPipeline<E_IN> which implements IntStream, in the package java.util.stream ):

@Override
    public final Stream<Integer> boxed() {
        return mapToObj(Integer::valueOf);
    }

So it is calling mapToObj() with Integer::valueOf. Note that by reusing cached values,Integer::valueOf is more efficient than new Integer() , so we should choose boxed().


Best practice:

Besides the performance difference, with boxed() we write less, and it is easier to read.

Igneous answered 31/12, 2018 at 12:21 Comment(0)
Y
0

The second one is better, and it can even be shortened without using boxed() as Java autoboxes to Integer using Integer.valueOf(int).

Arrays.stream(arr2)
   .mapToObj(in -> in * 2)
   .collect(Collectors.toCollection(() -> new ArrayList<>()));
Yamashita answered 26/5 at 4:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.