下面的代码现在对我来说很好用,但它不是未来的证明,因为 if else
语句和 instanceof
的数量。我想用更多的对象(如自行车、马达等)来扩展运输列表……但每次添加新对象时,我都需要添加更多的 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;
}
}
答案 0 :(得分:2)
传入你想要的子类型。也许这会奏效:
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;
}
答案 1 :(得分:2)
正如您目前优先考虑汽车而不是飞机一样,随着您的交通工具类型的增长,您也需要某种优先权来优先返回。您可以使用枚举解决此问题。添加新的传输类型后,您只需相应地扩展您的枚举。枚举可能类似于:
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;
}
答案 2 :(得分:0)
首先根据子类型将列表元素分组到一个映射中,然后创建一个传输子类型列表。迭代这个列表,然后检查映射中是否存在相应的条目:
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;
}
}
答案 3 :(得分:0)
好吧,您可以执行以下操作。
首先,定义您的订单:
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
被抛出。换言之,每次传输必须在 refNr
内出现 0 次或至少 listOfTransport
次。
另请注意,getClass()
不一定会产生与 instanceof
相同的结果。但是,我在这里假设每个传输都没有进一步的子类。