在办公室周围向人们讲述这一点让我意识到,如果没有我如何到达这里的背景,他们的反应始终是"你做错了#34;所以这里有#s背景:
我必须处理由另一个团队使用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;
}
}
这个容器以2D数组的形式交付给我,所以我想要一个float [] []。让我们从1维开始
FloatWrapper[] wrappers = new FloatWrapper[] {
new FloatWrapper(1.0f),
new FloatWrapper(2.0f)
};
Float[] asFloats = Arrays.stream(wrappers)
.map(f -> f.FloatValue)
.toArray(Float[]::new);
这很容易。让我们试一下2D数组。
// 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)'但不是#Array(float [] :: 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 };
所以,我半教育的猜测是,当你有一个2d数组而不是1d数组时,IntFunction会发生一些类型推断。但是,&#39;可以&#39;它有用吗?
答案 0 :(得分:2)
为什么我可以使用'toArray(float [] [] :: new)'而不是 'toArray(float [] :: new)'?
正如您所说,Arrays.stream(wrappers).map(f -> f.FloatValue)
是Stream<Float>
,因此toArray(float[]::new)
不起作用,因为您需要提供IntFunction<Float[]>
,而不是IntFunction<float[]>
。< / p>
另一方面,Arrays.stream(wrappers).map(f -> convert1DprimitiveArray(f))
是Stream<float[]>
,因此toArray(IntFunction<A[]>)
需要IntFunction<float[][]>
,这是float[][]::new
的用途。
.toArray(float[]::new)
,那么 Stream<float>
会有效,这是不可能的,因为你不能将原始类型作为通用参数。
答案 1 :(得分:1)
发生该错误,因为float
没有包装流。因此,您无法使用FloatStream
或类似内容。
因此,当你分析Stream.toArray()
实际上是什么时,你会得到这样的东西:
返回一个数组
T[]
,它在此流中保存T
类型的每个对象
问题来自于T
,因为您有一个包含floats
的流,存储在WrapperClass Float
中(因为基元不能与泛型一起使用)。
现在,当您尝试将Float
转换为float
时,java会使用auto-unboxing
为您执行此操作。不好的是,它对于数组来说并不相同。
在java中,一个基元数组可以不直接转换为它的特定包装类型。
所以Float[] floats = new float[10];
给出了编译错误。
现在你问自己:为什么float[][]
会起作用?。好吧,如果您查看它,那么您会看到float[]
是Object
和float
流 - 数组是有效的,因为它们可以作为对象引用。这就是为什么float[][]::new
有效的原因。它与之前的描述相匹配:返回一个数组T [],它包含此流中类型为T的每个对象,因为float[]
实际上是T
类型和{{ 1}}也是有效的。
答案 2 :(得分:0)
为什么我可以使用'toArray(float [] [] :: new)'而不是'toArray(float [] :: new)
因为在map
调用之后你有一个数组流,并且要创建一个数组流,你需要创建一个数组数组,而不是float
s。
要获取基元类型,您必须首先转换为DoubleStream
。
Arrays.stream(wrappers).mapToDouble(FloatWrapper::getFloat)
它为您提供原始流;那些你应该能够通过一些额外的魔法制作浮点阵列。