【问题标题】:Initializing a general HashMap with constant values for a class [duplicate]使用类的常量值初始化通用 HashMap [重复]
【发布时间】:2019-02-12 16:26:33
【问题描述】:

我在用常量值实例化一般 HashMap 时遇到问题。我打算在汽车租赁服务中跟踪各种汽车类型的库存;以 car type 为 key, num 为 value。 我尝试使用方法 createAvailable cars 将地图初始化为常量,以获取每种汽车类型的最大数量。为了进一步测试,我还包括了一个 setMaxCarsAvailable 方法。尽管如此,我还是从我的 canReserveVehicle 方法enter image description here得到了一个 NullPointer 异常,该行指定如果有 0 辆可用汽车,那么您就不能预订车辆。如何使用我的汽车地图正确处理库存?我应该把它放在哪里?我尝试使用静态方法,后来将其包含在构造函数中,但没有成功。请参阅下面的代码..(我已经包含了堆栈跟踪的图片,显示了 testCase 类中的错误。我希望所有这些额外的信息对您有所帮助)

public class CarReservationController {
String phoneNumber; 
long numDays = 0; 
Vehicle vehicle;
VehicleType vType;

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 

public static final int MAX_ECONOMY = 10; //used this to track the amount of cars available to rent. This was applied in the canReserveVehicle and addReservation methods
public static final int MAX_PREMIUM = 10; 
public static final int MAX_SUV = 5;

public CarReservationController()
{
    availableCars = createAvailableCarsMap(); //this is my attempt at instantiating my availableCars map to contain (VehicleType.ECONOMY, 10), (VehicleType.PREMIUM, 10), map.put(VehicleType.SUV, 5); ;
}

Map<VehicleType, Integer> availableCars; 
Map<VehicleType, PriorityQueue<Date>> reservedVehicleReturnDates = new HashMap<>(); // Map from vehicle type to reserved car end dates. This will hold all the current reservations end dates for each vehicle type
//was public static map
public HashMap<String, List<CarReservation>> reservationsMap = new HashMap<>();
//previously private static Map... 
private Map<VehicleType, Integer> createAvailableCarsMap() {
    Map<VehicleType, Integer> map = new EnumMap<VehicleType, Integer>(VehicleType.class);
    map.put(VehicleType.ECONOMY, MAX_ECONOMY);
    map.put(VehicleType.PREMIUM, MAX_PREMIUM);
    map.put(VehicleType.SUV, MAX_SUV);
    return map;
}



public void setMaxCarsAvailable(VehicleType v, int maxAvailable) {
        availableCars.put(v, maxAvailable);
}

//I UPDATE carReservationsMap here..this adds an actual reservation but first it checks the boolean canReserveVehicle below
public void addReservation(CarReservation res) throws Exception //right here
{   

    Date sDate = res.getStartDate(); //HERE
    Date eDate = res.getEndDate(); //HERE
    String phoneNumber = res.getPhoneNumber();
        if(canReserveVehicle(vType, phoneNumber, sDate, eDate)) {
            if (reservationsMap.containsKey(phoneNumber)) {
                List<CarReservation> currCustomerRes = reservationsMap.get(phoneNumber);
                currCustomerRes.add(res);
                reservationsMap.put(phoneNumber, currCustomerRes);
            } else {
                List<CarReservation> currCustomerRes = new ArrayList<CarReservation>(Arrays.asList(res));
                reservationsMap.put(phoneNumber, currCustomerRes);
            }
            int countForVehicleType = availableCars.get(vType);
            availableCars.put(vType, countForVehicleType - 1);
            if (reservedVehicleReturnDates.containsKey(vType)) {
                reservedVehicleReturnDates.get(vType).add(eDate);
            } else {
                PriorityQueue<Date> q = new PriorityQueue<Date>();
                reservedVehicleReturnDates.put(vType, q);
            }
        }   
}

//NULL POINTER EXCEPTION COMING UP HERE FROM JUNIT TESTS
public boolean canReserveVehicle(VehicleType v, String phoneNumber, Date startDate, Date endDate) throws ParseException 
{
    PriorityQueue<Date> reservedVehicleQueue = reservedVehicleReturnDates.get(v);
    if(endDate.before(startDate))
        return false; // check that the start date of the reservation is before the end date 

    if (availableCars.get(v) == 0) { /// SAYS THERE IS A NULL POINTER EXCEPTION from here... because availableCars is still 0..
        Date nextCarReturnDate = reservedVehicleQueue.peek();
        if(nextCarReturnDate.after(startDate))
            return false; // return false if a reserved car is not going to be available before the new customer is requesting one.
    }
    else {
        // If a car that will become available before the customer requests it, remove it from the queue and replace with the 
        //requesting customer's return date (as they now lay claim to the car)
        reservedVehicleQueue.poll();
        reservedVehicleQueue.add(endDate);
    }

    //these are comparing strings.
    if (reservationsMap.containsKey(phoneNumber)) {
        List<CarReservation> resByCustomer = reservationsMap.get(phoneNumber);
        CarReservation lastResByCustomer = resByCustomer.get(resByCustomer.size() - 1); 
        Date lastResEndDate = sdf.parse(lastResByCustomer.endDate);
        if (startDate.before(lastResEndDate)) {  //1 customer can only have one rental at a time within the system.
            return false;
        } 
    }
    return true;    
}

}

“java.lang.NullPointerException”CarReservationController.canReserveCarVehicle 的测试用例如下所示

import java.text.SimpleDateFormat;

import org.junit.Test;

public class CarReservationTest {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 


@Test
public void testThatCustomerCanMakeReservation() throws Exception {
    CarReservationController reservationSystem = new CarReservationController();
    reservationSystem.setMaxCarsAvailable(VehicleType.PREMIUM, 2);
    CarReservation firstRes = new CarReservation(VehicleType.PREMIUM, "Jon Snow", "1234567890", "2019-01-23", "2019-01-31");
    reservationSystem.addReservation(firstRes);
    //assertTrue(reservationSystem.reservationsMap.containsKey("1234567890"));
    assertTrue(reservationSystem.reservationsMap.size() > 0);
    assertEquals(firstRes, reservationSystem.reservationsMap.get("1234567890"));
}
}

【问题讨论】:

  • 你在哪里向reservationsMap添加值?
  • 请提供完整的异常堆栈恍惚,从哪里调用canReserveVehicle?也不要手动编写堆栈跟踪,请复制粘贴,以免出现拼写错误。
  • 嗨@Janik 我包括了堆栈跟踪的图像以及为 canReserveVehicle 提供更多上下文的 addReservation 方法
  • @nabster 发生在我已包含在编辑中的 addReservation 方法中。如果您需要更多信息,请告诉我。
  • @Andy Turner 为什么在对问题没有帮助时会被标记为重复?

标签: java enums maps constants


【解决方案1】:

有几个问题使调试变得复杂。

也许对于您提出的问题最重要的是,如果没有完整的堆栈跟踪,您看到的 NPE 是来自 availbleCars.get(v) 还是来自 availableCars.get(v) == 0 并不明显。

这个问题因为不知道ReservationSystem::addReservation 方法的作用而变得复杂,我认为不可能排除任何一种可能性。

可能性1

但是,如果问题来自 availableCars.get(v) == 0,那么您可能会选择使用 == 而不是 .equals() 比较 Integer 和数字原语之间的相等性。请参阅此之前的答案以获得更完整的讨论:Why comparing Integer with int can throw NullPointerException in Java?

可能性2

如果问题来自availableCars.get(v)(即availableCars 本身就是null),那么您可能对实例化availableCars 映射的方式有疑问。您在那里使用的方法不需要是静态的,也不需要您创建的 setter。

后续步骤

要解决此问题,我建议使用断点或使用调试语句将比较分为两个步骤 - 首先检查 availableCars 是否为空,然后检查 availableCars.get(v) 是否为 Integer,然后使用.equals() 来检查与0 的相等性。

此外,您还可以尝试对您的方法进行单元测试,以分别实例化 availableCars 映射和 ReservationSystem::addReservation 方法,以帮助缩小可能存在错误的范围。

【讨论】:

  • Integer countForVehicleType = availableCars.get(vType); 我把它改成了 int。我也从 createAvailableCarsMap() 中删除了 static 关键字,但仍然收到 NullPointerException。源于availableCars.get(v) == 0。我想这又回到了我最初的问题,如何正确填充我的availableCarsMap ..启发我正确的语法。
猜你喜欢
  • 2014-07-17
  • 1970-01-01
  • 2018-10-25
  • 2015-03-10
  • 2022-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多