Situation:
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];
}
}
Code with unchecked conversion:
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 ...;
}
How can solve this without unchecked conversion?
I can't use such:
public Attribute split(Entity[] examples) {
Predicate<Double>[] pa = Arrays.stream(examples).map(e -> P.isEqual(e.getValue(a.index))).toArray(Predicate<Double>[]::new);
return ...;
}
There is no way to create a generic array without unchecked conversion, as the creation of a generic array is an unsafe operation per se. Since its creation is not allowed, you can only create a non-generic array and perform an unchecked conversion.
Simply said, every operation that could enable subsequent heap pollution without any warning, must be considered an unsafe operation that either, generates a warning itself or even will produce an error. The problem can easily demonstrated:
Predicate<Double>[] p=/* someway to get the array*/;
Object[] array=p;
array[0]=(Predicate<Integer>)i -> i==0;
This situation, where an array whose elements are declared to be of type Predicate<Double>
, but one of them is actually a Predicate<Integer>
, is called heap pollution. Since both, the assignment of p
to a variable of type Object[]
and the assignment of a Predicate<Integer>
to an element of an array of type Object[]
, are legal constructs that don’t generate warnings, the creation of the array itself must be considered an unsafe operation that must generate either, a warning or an error, to prevent the subsequent silent heap pollution. Otherwise, Generics could not claim to provide compile-time safety, i.e. that code free of unchecked/unsafe operations guarantees the absence of heap pollution.
The only exception where generic array creation is accepted, is in the context of varargs, but to have a warning free code, i.e. using @SafeVarargs
, you have to accept fundamental restrictions, e.g. you can not assign the array to any other variable nor return it from the method, to avoid a sneaky introduction of the problem described above.
So the bottom line is, either, you accept that there is an unchecked operation or you use a List
and “use a List
” means use a List
, not try to create the array via a List
. The fundamental difference between a List
and an array is that you can’t assign a List<Predicate<Double>>
to a List<Predicate>
nor List<Object>
(without an unchecked operation), so it provides the safety that Generics promise.