【问题标题】:Java Streams toArray with primitivesJava Streams toArray 与原语
【发布时间】:2018-04-15 03:41:52
【问题描述】:

与办公室周围的人谈论这件事让我意识到,如果没有我如何到达这里的背景,他们的回答总是“你做错了”,所以这里是背景:

我必须处理另一个团队使用 ICE (https://doc.zeroc.com/display/Ice37/Ice+Overview) 创建的糟糕对象,并且想为我一直在编写的样板代码编写一个实用程序。

我必须处理的对象之一是浮点数和字符串的容器。我只想要浮点值。

public class FloatWrapper {
    public String   StringValue;
    public float    FloatValue;

    public FloatWrapper(float f) {
        this.FloatValue = f;
    }

    public FloatWrapper(String s) {
        this.StringValue = s;
    }

    public FloatWrapper(float f, String s) {
        this.FloatValue = f;
        this.StringValue = s;
    }
}

这个容器以二维数组的形式交付给我,所以我想要一个 float[][]。让我们从一维开始

FloatWrapper[] wrappers = new FloatWrapper[] { 
    new FloatWrapper(1.0f), 
    new FloatWrapper(2.0f) 
};

Float[] asFloats = Arrays.stream(wrappers)
    .map(f -> f.FloatValue)
    .toArray(Float[]::new);

这很容易。让我们尝试一个二维数组。

// Make a lovely method for what I have above
public Float[] convert1Darray(FloatWrapper[] wrappers) {
    return Arrays.stream(wrappers)
            .map(f -> f.FloatValue)
            .toArray(Float[]::new);
}

public static Float[][] convert2Darray(FloatWrapper[][] wrappers) {
    return Arrays.stream(wrappers)
            .map(f -> convert1Darray(f))
            .toArray(Float[][]::new);
}

...

// Create a 2D array
FloatWrapper[][] wrappers2d = new FloatWrapper[][] { 
    { new FloatWrapper(1.0f), new FloatWrapper(2.0f) }, 
    { new FloatWrapper(3.0f), new FloatWrapper(4.0f) }
};

Float[][] floats2d = convert2Darray(wrappers2d);

轰隆隆!

如果有原始的花车就好了(它只是,好吧!)你们中间的干瘪的人可以看到我要去哪里......

原来你不能在“toArray”调用中很容易地使用原始浮点数。 Apache commons 会对其进行排序

public static float[] convert1DprimitiveArray(FloatWrapper[] wrappers) {
    return ArrayUtils.toPrimitive(
            Arrays.stream(wrappers)
                    .map(f -> f.FloatValue)
                    .toArray(Float[]::new));
}

public static float[][] convert2DprimitiveArray(FloatWrapper[][] wrappers) {
    return Arrays.stream(wrappers)
            .map(f -> convert1DprimitiveArray(f))
            .toArray(float[][]::new);
}

....等一下。为什么我可以使用 'toArray(float[][]::new)' 而不是 'toArray(float[]::new)' ?

现在在办公室里流传的论点是“float[]::new”调用是非法的,因为您不能在原语上调用“new”。

但这不是它正在做的事情。这只是 IntFunction 的简写

让我们分解一下

这个:

Arrays.stream(wrappers1d).map(f -> f.FloatValue).toArray(Float[]::new);

相当于这个:

Arrays.stream(wrappers1d).map(f -> f.FloatValue).toArray(new IntFunction<Float[]>() {
    @Override
    public Float[] apply(int size) {
        return new Float[size];
    }
});

那么,是不是你不能创建 IntFuntion 类型的东西??

不。完全允许:

IntFunction<float[]> happyToCompile = new IntFunction<float[]>() {
    @Override
    public float[] apply(int size) {
        return new float[size];
    }
};

执行该功能会给您带来等价的

new float[]{ 0.0f, 0.0f };

所以,我半知半解的猜测是,当你有一个二维数组而不是一维数组时,IntFunction 会进行一些类型推断。但是,“可以”吗?

【问题讨论】:

    标签: java arrays generics lambda


    【解决方案1】:

    为什么我可以使用 'toArray(float[][]::new)' 而不是 'toArray(float[]::new)

    因为在map 调用之后你有一个数组流,并且要创建一个流数组,你需要创建一个数组数组,而不是floats。

    要获得原始类型,您必须先转换为DoubleStream

    Arrays.stream(wrappers).mapToDouble(FloatWrapper::getFloat)
    

    它为您提供原始流;那些你应该能够用一些额外的魔法制作浮点数组。

    【讨论】:

      【解决方案2】:

      为什么我可以使用 'toArray(float[][]::new)' 但不能 'toArray(float[]::new)' ?

      正如您所说,Arrays.stream(wrappers).map(f -&gt; f.FloatValue)Stream&lt;Float&gt;,因此 toArray(float[]::new) 不起作用,因为您需要提供 IntFunction&lt;Float[]&gt;,而不是 IntFunction&lt;float[]&gt;

      另一方面,Arrays.stream(wrappers).map(f -&gt; convert1DprimitiveArray(f))Stream&lt;float[]&gt;,所以toArray(IntFunction&lt;A[]&gt;) 需要IntFunction&lt;float[][]&gt;,这就是float[][]::new 的用途。

      如果您有Stream&lt;float&gt;.toArray(float[]::new) 会起作用,这是不可能的,因为您不能将原始类型作为泛型参数。

      【讨论】:

      • 我想很多人同时回答了这个问题,但这个对于我的原始(明白吗?)大脑来说是最容易理解的。谢谢:)
      【解决方案3】:

      出现该错误,因为不存在 float 的包装流。所以你不能使用FloatStream 或类似的东西。

      因此,当您分析 Stream.toArray() 的真正含义时,您会得到如下结果:

      返回一个数组T[],该数组包含此流中T 类型的每个对象

      问题与T 有关,因为您有一个包含floats 的流,存储在它们的WrapperClass Float 中(因为原语不能与泛型一起使用)。

      现在,当您尝试将 Float 转换为 float 时,java 会为您使用 auto-unboxing。不好的是,数组就不一样了。

      在 java 中,原语数组不能直接转换为其特定的 Wrapper 类型。

      所以Float[] floats = new float[10]; 给出了编译错误。

      现在你问自己:那为什么float[][] 有效?。好吧,如果你看一下,你会发现float[] 是一个Object 并且float-arrays 的流是有效的,因为它们可以作为对象引用。这就是float[][]::new 起作用的原因。它与前面的描述相匹配:返回一个数组 T[],该数组包含此流中 T 类型的每个对象,因为 float[]实际上是 T 类型,然后 T[] 是有效的也是。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-16
        • 1970-01-01
        • 1970-01-01
        • 2014-04-29
        • 2013-08-03
        • 1970-01-01
        • 1970-01-01
        • 2015-08-01
        相关资源
        最近更新 更多