使用类的常量值初始化常规HashMap

时间:2019-02-12 16:26:33

标签: java enums maps constants

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

MongoClient.connect()

}

带有“ java.lang.NullPointerException” CarReservationController.canReserveCarVehicle的测试用例看起来像这样

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;    
}

1 个答案:

答案 0 :(得分:0)

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

对于您所问的问题而言,也许最重要的一点是,它没有完整的堆栈跟踪信息,但是您看到的NPE是来自availbleCars.get(v)还是来自availableCars.get(v) == 0,这并不是很明显。

由于不知道ReservationSystem::addReservation方法的作用,因此我认为不可能排除任何一种可能性。

可能性1

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

可能性2

如果问题来自availableCars.get(v)availableCars本身是null),那么您可能无法确定如何实例化availableCars映射。在那里使用的方法不必是静态的,也不需要创建的设置器。

后续步骤

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

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