java 流 return 参数化数组 class
java stream return array of parameterized class
情况:
public class P {
public static Predicate<Double> isEqual(double value) {
return p -> (Math.abs(p - value) <= 0.000001);
}
}
public class Entity {
private double[] values;
public double getValue(int index) {
return values[index];
}
}
未经检查的转换代码:
public Attribute split(Entity[] examples) {
@SuppressWarnings("unchecked")
Predicate<Double>[] pa = Arrays.stream(examples).map(e -> P.isEqual(e.getValue(a.index))).toArray(Predicate[]::new);
return ...;
}
如何在没有未经检查的转换的情况下解决这个问题?
我不能这样用:
public Attribute split(Entity[] examples) {
Predicate<Double>[] pa = Arrays.stream(examples).map(e -> P.isEqual(e.getValue(a.index))).toArray(Predicate<Double>[]::new);
return ...;
}
实际上,我打算将我的评论作为答案,因为我发现这对研究很有趣,而且我现在非常有信心。答案取决于创建通用数组 必须 具有未经检查的转换这一事实(正如@azurefrog 指出的那样)。
参见:How to create a generic array in Java?
Predicate<Double>[]::new
等同于
IntFunction<Predicate<Double> []> predicateArrayMaker = (int size) -> new Predicate<Double>[size];
但是,如果没有未经检查的转换,您将无法创建通用数组。例如,
Predicate<Double>[] predicateArray = new Predicate<Double>[10];
也会有同样的问题
因此,未经检查的转换必须如链接答案中所述发生。
没有未经检查的转换就无法创建泛型数组,因为创建泛型数组本身是不安全的操作。由于不允许创建,所以只能创建一个非泛型数组并进行未经检查的转换。
简单地说,每个可能在没有任何警告的情况下启用后续堆污染的操作,都必须被视为不安全的操作,它本身会产生警告,甚至会产生错误。这个问题很容易证明:
Predicate<Double>[] p=/* someway to get the array*/;
Object[] array=p;
array[0]=(Predicate<Integer>)i -> i==0;
这种情况下,一个数组的元素声明为Predicate<Double>
类型,但其中一个元素实际上是Predicate<Integer>
,称为堆污染.因为将 p
赋值给类型 Object[]
的变量和将 Predicate<Integer>
赋值给类型为 Object[]
的数组的元素,都是合法的构造,不' 生成警告,数组本身的创建必须被视为不安全的操作,必须生成警告或错误,以防止随后的静默堆污染。否则,泛型不能声称提供编译时安全,即没有 unchecked/unsafe 操作的代码保证没有堆污染。
接受通用数组创建的唯一例外是在 varargs 的上下文中,但要有无警告代码,即使用 @SafeVarargs
,您必须接受基本限制,例如您不能将数组分配给任何其他变量,也不能从方法中 return 分配数组,以避免偷偷摸摸地引入上述问题。
所以最重要的是,要么你接受有一个未经检查的操作,要么你使用 List
并且“使用 List
” 意味着 使用 a List
,而不是尝试通过 a List
创建数组。 List
和数组之间的根本区别在于您不能将 List<Predicate<Double>>
分配给 List<Predicate>
也不能将 List<Object>
分配给 List<Object>
(没有未经检查的操作),因此它提供了泛型承诺的安全性。
情况:
public class P {
public static Predicate<Double> isEqual(double value) {
return p -> (Math.abs(p - value) <= 0.000001);
}
}
public class Entity {
private double[] values;
public double getValue(int index) {
return values[index];
}
}
未经检查的转换代码:
public Attribute split(Entity[] examples) {
@SuppressWarnings("unchecked")
Predicate<Double>[] pa = Arrays.stream(examples).map(e -> P.isEqual(e.getValue(a.index))).toArray(Predicate[]::new);
return ...;
}
如何在没有未经检查的转换的情况下解决这个问题?
我不能这样用:
public Attribute split(Entity[] examples) {
Predicate<Double>[] pa = Arrays.stream(examples).map(e -> P.isEqual(e.getValue(a.index))).toArray(Predicate<Double>[]::new);
return ...;
}
实际上,我打算将我的评论作为答案,因为我发现这对研究很有趣,而且我现在非常有信心。答案取决于创建通用数组 必须 具有未经检查的转换这一事实(正如@azurefrog 指出的那样)。
参见:How to create a generic array in Java?
Predicate<Double>[]::new
等同于
IntFunction<Predicate<Double> []> predicateArrayMaker = (int size) -> new Predicate<Double>[size];
但是,如果没有未经检查的转换,您将无法创建通用数组。例如,
Predicate<Double>[] predicateArray = new Predicate<Double>[10];
也会有同样的问题
因此,未经检查的转换必须如链接答案中所述发生。
没有未经检查的转换就无法创建泛型数组,因为创建泛型数组本身是不安全的操作。由于不允许创建,所以只能创建一个非泛型数组并进行未经检查的转换。
简单地说,每个可能在没有任何警告的情况下启用后续堆污染的操作,都必须被视为不安全的操作,它本身会产生警告,甚至会产生错误。这个问题很容易证明:
Predicate<Double>[] p=/* someway to get the array*/;
Object[] array=p;
array[0]=(Predicate<Integer>)i -> i==0;
这种情况下,一个数组的元素声明为Predicate<Double>
类型,但其中一个元素实际上是Predicate<Integer>
,称为堆污染.因为将 p
赋值给类型 Object[]
的变量和将 Predicate<Integer>
赋值给类型为 Object[]
的数组的元素,都是合法的构造,不' 生成警告,数组本身的创建必须被视为不安全的操作,必须生成警告或错误,以防止随后的静默堆污染。否则,泛型不能声称提供编译时安全,即没有 unchecked/unsafe 操作的代码保证没有堆污染。
接受通用数组创建的唯一例外是在 varargs 的上下文中,但要有无警告代码,即使用 @SafeVarargs
,您必须接受基本限制,例如您不能将数组分配给任何其他变量,也不能从方法中 return 分配数组,以避免偷偷摸摸地引入上述问题。
所以最重要的是,要么你接受有一个未经检查的操作,要么你使用 List
并且“使用 List
” 意味着 使用 a List
,而不是尝试通过 a List
创建数组。 List
和数组之间的根本区别在于您不能将 List<Predicate<Double>>
分配给 List<Predicate>
也不能将 List<Object>
分配给 List<Object>
(没有未经检查的操作),因此它提供了泛型承诺的安全性。