在List&中避免使用非常长的类型参数地图使用'?' java中的关键字

时间:2017-10-24 11:17:33

标签: java generics

我一直在研究一个类,我遇到了具有非常大的Type值的Maps和List。 例如。

Map<String, Map<String, Map<String, ...>>> map = new HashMap<>();

List<List<Map<String,...>>> list = new ArrayList<>();

循环遍历这些数据类型会使样板代码看起来非常难看!

for(Map<String, Map<String, ...>> e : map.entrySet()){
    //do something...
    for(Map<String, ..> e1 : e.entrySet()){
       ..more such loops
    }
}

我想出了一个使用'?'缩小模板大小的解决方案关键词 以下是我的解决方案

Map<String, Map<String, Map<String, Long>>> map = ....

for(Entry<String, ?> e : map.entrySet()){
    Map<String , ?> mapLevel1 = (Map<String, ?>)e.getValue();
    for(Entry<String, ?> e1 : mapLevel1.entrySet()){
        Map<String, ?> mapLevel2Map = (Map<String, ?>) e1.getValue();
        for(Entry<String, ?> e2 : mapLevel2Map.entrySet()){
            Long data =  (Long)e2.getValue();
            .....
        }
    }
}
采用这种方法会有任何潜在的问题吗? 感谢预期!

3 个答案:

答案 0 :(得分:2)

?表示&#34;某种类型,但我不知道哪些&#34; (大约)。既然你知道这个类型是什么,那就不合适了。

  采用这种方法可能存在任何潜在的问题

getValue之后到处都需要的演员阵容(并且不需要?)是一个非常重要的问题,我甚至不会称之为“#34;潜力&# 34 ;.如果该类型的任何部分发生变化,请运气好,找出需要更改的内容以及更改内容。

答案 1 :(得分:1)

  采用这种方法会有任何潜在的问题吗?   感谢预期!

由于您必须使用Map方法返回的值,因此无法读取代码并丢失泛型权益,就像使用原始类型一样。

在任何情况下,具有如此重要的深层结构可能会因为潜在的实例化缺失而产生运行时错误,并使代码复杂化以便读取和维护。

您应该改进设计并引入自定义类来包装地图并提供添加和检索数据的逻辑方法 您还应该将库视为Guava。
例如,Table是一个很好的候选者,可以为你的被操作类型带来一些抽象。

答案 2 :(得分:1)

正如其他人所指出的那样,使用?会更糟。不要这样做。

您应该在IDE中启用所有编译器警告(或使用-Xlint,如果在命令行上构建)。这将告诉您,转换为泛型类型是一种不安全的操作。

保持清洁的一个好方法是创建封装这些地图的实际数据类。

例如,您可以替换它:

Map<String, Map<String, Map<String, Boolean>>> map = new HashMap<>();

用这个:

Person person = new Person();
这三个类支持

public class Person {
    private final Map<String, Address> addressesByType = new HashMap<>();

    public Set<String> getAddressTypes() {
        return new HashSet<>(addressesByType.keySet());
    }

    public Address getAddress(String type) {
        return addressesByType.get(type);
    }

    public void addAddress(String type,
                           Address address) {
        Objects.requireNonNull(type);
        Objects.requireNonNull(address);
        addressesByType.put(type, address);
    }
}

public class Address {
    public static final String TYPE_HOME = "Home";
    public static final String TYPE_WORK = "Work";

    private final Map<String, Vehicle> vehiclesByType = new HashMap<>();

    public Set<String> getVehicleTypes() {
        return new HashSet<>(vehiclesByType.keySet());
    }

    public Vehicle getVehicle(String type) {
        return vehiclesByType.get(type);
    }

    public void addVehicle(String type,
                           Vehicle vehicle) {
        Objects.requireNonNull(type);
        Objects.requireNonNull(vehicle);
        vehiclesByType.put(type, vehicle);
    }
}

最后:

public class Vehicle {
    public static final String TYPE_PERSONAL = "Personal";
    public static final String TYPE_BUSINESS = "Business";

    private final Map<String, Boolean> inspectionsByDate = new HashMap<>();

    public Set<String> getInspectionDates() {
        return inspectionsByDate.keySet();
    }

    public Boolean getInspectionOutcome(String date) {
        return inspectionsByDate.get(date);
    }

    public void addInspection(String date,
                              boolean outcome) {
        Objects.requireNonNull(date);
        inspectionsByDate.put(date, outcome);
    }
}

你的循环看起来像这样:

for (String addressType : person.getAddressTypes()) {
    Address address = person.getAddress(addressType);
    for (String vehicleType : address.getVehicleTypes()) {
        Vehicle vehicle = address.getVehicle(vehicleType);
        for (String date : vehicle.getInspectionDates()) {
            boolean outcome = vehicle.getInspectionOutcome(date);
            // ...
        }
    }
}

(以上只是一个例子。显然,在现实生活中,密钥是枚举值,日期是LocalDateDate个对象,人们可以拥有多个地址,不止一种用于特定目的的车辆。)

您可以以类似的方式封装列表;例如,请参阅NodeList