原始流与对象流和发生的实际装箱

Tra*_*ity 4 java primitive autoboxing java-stream

所以,我明白,你可以有对象流,即Stream<T>与专家原始流,如IntStream,DoubleStream等,其中后者的好处是避免自动装箱.

另外,如果我们以IntStream一个例子为例,它有专门的操作,例如接受的过滤器IntPredicate.

我想知道我是否有一个IntStreamvs a Stream<Integer>,此时你正在节省拳击,例如

intstream.filter(x -> x >= 50).forEach(x -> System.out.println(x));
Run Code Online (Sandbox Code Playgroud)

VS

stream.filter(x -> x >= 50).forEach(x -> System.out.println(x));
Run Code Online (Sandbox Code Playgroud)

在第一个例子中,我没有看到拳击或拆箱.在第二个例子中,拳击/拆箱发生在哪里?因为如果stream是a Stream<Integer>并且过滤器接受了a Predicate<Integer>肯定那么就不需要box/unbox,对于IntConsumervs也是如此Consumer<T>

Lou*_*man 6

拆箱发生在谓词内:in stream.filter(x -> x >= 50),Predicate基本上成为(Integer x) -> x.intValue() >= 50,并且intValue()是拆箱步骤.另外,System.out.println一些拆箱本身,在执行中Integer.toString最终被调用.


Tag*_*eev 5

有了Stream<Integer>您的流已经装箱。因此,根据您创建它的方式,有几种可能性:

  • 您最初具有装箱值。例如,你有List<Integer> list作为输入并写道:

    stream = list.stream();
    
    Run Code Online (Sandbox Code Playgroud)
  • 您在创建流时将值装箱。例如,您像这样创建它:

    stream = Stream.iterate(1, x -> x+1);
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,第一个参数被装箱,Integer.valueOf(1)并且在每个 lambda(即UnaryOperator<Integer>)调用中也会发生拆箱/装箱。所以有效地你有:

    stream = Stream.iterate(Integer.valueOf(1), x -> Integer.valueOf(x.intValue()+1));
    
    Run Code Online (Sandbox Code Playgroud)
  • 您通过上游中间操作显式装箱了源。例如:

    stream = IntStream.range(0, 1000).boxed();
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,在.boxed()操作内部执行装箱(这是 的快捷方式.mapToObj(Integer::valueOf))。

  • @Tranquility,你不应该关心*拆箱*:它绝对便宜(只是单个解引用)。昂贵的是“装箱”(最坏情况下的实际对象分配)。另请注意,每个使用“Integer”的数值运算(加法、比较等)都需要拆箱。 (2认同)