There are things that have weight, so here's their interface, for example:
public interface Banana {
public Double getWeight();
}
// This function is a static function in a public tool class.
@Nullable
public static Banana pickItemByTheirWeight(List<Banana> originalVideos) {
// ...
return randomOneByWeight;
}
now I want to create things that have weight, so:
class Video implements Banana {
@Override
public Double getWeight() {
//....
return weight;
}
}
now, when I want to pick a video by weight, for example:
List<Video> videos = new ArrayList<>();
// ...
Video randomOne = pickItemByTheirWeight(videos);
I get a compile error. so what is the correct way to do it?
Hey guys, it's not that easy.
I tried
public static <T extends Banana> T pickOneByTheirWeight(List<T> domains) {
// ...
}
public abstract class Banana {
public abstract Double getWeight();
}
And it's still not working, I cannot call the function without cast the class type.
* can someone tell my why Java choose not to let it just work ???*
After reading some basic knowledge to Java Generics, here comes a solution:
public static <T extends Banana> T pickOneByTheirWeight(List<? extends Banana> domains) {
if (domains.isEmpty()) {
return null;
}
// calculate total weight
Double totalWeight = domains.stream().map(x -> {
Double weight = x.getWeight();
return weight == null ? 0.0 : weight;
}).reduce((first, second) -> {
Double firstWeight = first != null ? first : 0.0;
Double secondWeight = second != null ? second : 0.0;
return firstWeight + secondWeight;
}).get();
// random process
final Double randomSeed = Math.random() * totalWeight;
double currentWeight = 0.0;
for (Banana v: domains) {
Double weight = v.getWeight();
weight = weight == null ? 0.0 : weight;
currentWeight += weight;
if (currentWeight >= randomSeed) {
return (T) v;
}
}
// it'll not reach here indeed.
logger.warn("pickDomainByTheirWeight cannot pick an element from list by their weights.");
return null;
}
But declear the function like this, we can simply call:
List<Video> videos = new ArrayList<>();
// ...
Video p = Utility.pickOneByTheirWeight(videos);
no more cast outside, however, still a cast inside the function. Any better idea?