下面的代码现在对我来说很好,但它不是未来的证明,因为if else
和instanceof
的数量。我想用更多的对象来扩展传输列表,比如biyles、motors等……但每次添加新对象时,我都需要添加更多的if else
语句并创建更多的instanceof
。有人有更好的想法或更好的解决方案吗?
private static Transport filterObjects(List<Transport> listOfTransport, int refNr) {
List<Transport> cars = listOfTransport.stream()
.filter(transport -> transport instanceof Cars)
.collect(Collectors.toList());
List<Transport> airPlanes = listOfTransport.stream()
.filter(transport -> transport instanceof Airplanes)
.collect(Collectors.toList());
if (!cars.isEmpty()){
return cars.get(refNr);
} else if (!airPlanes.isEmpty()) {
return airPlanes.get(refNr);
} else {
return null;
}
}
传入所需的子类型。也许这会奏效:
private static Transport filterObjects(List<Transport> listOfTransport, Class clazz, int refNr) {
List<Transport> transports = listOfTransport.stream().filter(clazz::isInstance).collect(Collectors.toList());
return !transports.isEmpty() ? transports.get(refNr) : null;
}
正如你目前优先考虑汽车而不是飞机一样,随着交通类型的增加,你也需要某种优先权才能优先返回。你可以用枚举来解决这个问题。您只需要在添加新的传输类型后立即相应地扩展枚举。枚举可能看起来像:
enum Priority{
Car(1),
Airplane(2);
private int value;
Priority (int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
然后,您可以重构您的方法,方法是根据列表中的元素的简单类名对其进行分组,并使用您在枚举中定义的优先级将它们添加到排序映射中。然后,您可以使用映射的第一个条目来确定返回值。示例:
private static Transport filterObjects(List<Transport> listOfTransport, int refNr) {
Comparator<String> comp = Comparator.comparingInt(e -> Priority.valueOf(e).getValue());
List<Transport> result =
listOfTransport.stream()
.collect(Collectors.groupingBy(
e -> e.getClass().getSimpleName(),
() -> new TreeMap<>(comp),
Collectors.toList()))
.firstEntry().getValue();
return (result != null && 0 <= refNr && refNr < result.size()) ?
result.get(refNr) : null;
}
首先根据子类型将列表元素分组到映射中,然后创建传输的子类型列表。重复此列表,然后检查地图中是否存在相应的条目:
private static final List<Class> subTypes = List.of(Cars.class, Airplanes.class);
private static Transport filterObjects(List<Transport> listOfTransport, int refNr) {
Map<Class, List<Transport>> map = listOfTransport.stream()
.collect(Collectors.groupingBy(t -> t.getClass()));
Optional<List<Transport>> op = subTypes.stream()
.filter(map::containsKey)
.findFirst();
if(op.isPresent()) {
return op.get().get(refNr); // This could cause IndexOutOfBoundsException
}else{
return null;
}
}
好吧,您可以执行以下操作。
首先,定义您的订单:
static final List<Class<? extends Transport>> ORDER = List.of(
Car.class,
Airplane.class
);
然后,您可以编写以下方法:
private static Transport filterObjects(List<Transport> listOfTransport, int refNr) {
Map<Class<? extends Transport>, Transport> map = listOfTransport.stream()
.collect(Collectors.groupingBy(Transport::getClass, Collectors.collectingAndThen(Collectors.toList(), list -> list.get(refNr))));
return ORDER.stream()
.filter(map::containsKey)
.map(map::get)
.findFirst()
.orElse(null);
}
这样做的目的是将每个不同的Class
映射到作为相应类的子类型的第refNr
个元素。
然后,它遍历ORDER
并检查是否在原始listOfTransport
中找到了元素。如果listOfTransport
不包含特定类的任何元素,则键将不存在于映射中。
注意,如果映射中存在特定类的任何元素,则该类的元素数至少为refNr
,否则抛出IndexOutOfBoundsException
。换句话说,每次传输必须在listOfTransport
内发生0次或至少refNr
次。
还要注意,getClass()
不一定产生与instanceof
相同的结果。然而,我在这里假设每个相应的传输都没有进一步的子类。