java stream返回参数化类的数组

时间:2016-06-01 21:01:41

标签: java arrays java-stream parameterized-types

情况:

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 ...;
}

2 个答案:

答案 0 :(得分:1)

我实际上是要将我的评论作为答案,因为我发现这对研究很有意思,我现在非常自信。答案取决于事实(正如@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];

会遇到同样的问题。

因此,未经检查的转换必须按照链接答案中的说明进行。

答案 1 :(得分:1)

没有未经检查的转换就无法创建通用数组,因为创建通用数组本身就是一种不安全的操作。由于不允许创建,因此您只能创建非泛型数组并执行未经检查的转换。

简单地说,每个可以在没有任何警告的情况下实现后续堆污染的操作都必须被视为不安全的操作,要么自己生成警告,要么甚至会产生错误。问题很容易证明:

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[]的数组的元素,因此是合法的构造要生成警告,必须将数组本身的创建视为不安全的操作,必须生成警告或错误,以防止后续的静默堆污染。否则,泛型无法声称提供编译时安全性,即没有未经检查/不安全操作的代码可确保不存在堆污染。

接受通用数组创建的唯一例外是在varargs的上下文中,但要使用免费警告代码,即使用@SafeVarargs,您必须接受基本限制,例如:你不能将数组分配给任何其他变量,也不能从方法中返回它,以避免偷偷摸摸地引入上述问题。

所以最重要的是,您接受有未经检查的操作,或者您使用List并且“使用List”表示使用 a {{ 1}},不要尝试通过List创建数组。 List和数组之间的根本区别在于,您无法将List分配给List<Predicate<Double>>List<Predicate>(没有未经检查的操作),因此它提供了Generics承诺的安全性。