Java空指针异常求助:输入文件非空但flightReader为何为空?
Java空指针异常排查:flightReader为null的问题
报错信息
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "F28DA_CW2.FlightsReader.getAirports()" because "this.flightReader" is null at F28DA_CW2.FlyingPlanner.leastCost(FlyingPlanner.java:206) at F28DA_CW2.FlyingPlannerMainPartBC.main(FlyingPlannerMainPartBC.java:29)
相关代码
主文件FlyingPlannerMainPartBC.java
import java.io.FileNotFoundException; public class FlyingPlannerMainPartBC { public static void main(String[] args) throws FlyingPlannerException, FileNotFoundException { FlyingPlanner fi; fi = new FlyingPlanner(); try { fi.populate(new FlightsReader()); // Implement here your user interface using the methods of Part B. You could // optionally expand it to use the methods of Part C. } catch (FileNotFoundException | FlyingPlannerException e) { e.printStackTrace(); } FlightsReader flightReader = new FlightsReader(); flightReader.getAirports(); flightReader.getFlights(); FlyingPlanner pr = new FlyingPlanner(); System.out.println(pr.leastCost("EDI", "DXB")); // line: 29 } }
FlyingPlanner类的leastCost方法
@Override public Journey leastCost(String from, String to) throws FlyingPlannerException { // TODO Auto-generated method stub HashSet<String[]> airports = flightReader.getAirports(); //line206 HashSet<String[]> flights = flightReader.getFlights(); DefaultDirectedWeightedGraph<String, DefaultWeightedEdge> leastCost = new DefaultDirectedWeightedGraph<>( DefaultWeightedEdge.class); for (String[] flight : flights) { leastCost.addVertex(flight[1]); leastCost.addVertex(flight[3]); leastCost.addEdge(flight[1], flight[3]); leastCost.setEdgeWeight(flight[1], flight[3], Integer.parseInt(flight[5])); } DijkstraShortestPath<String, DefaultWeightedEdge> dijkstraAlg = new DijkstraShortestPath<>(leastCost); GraphPath<String, DefaultWeightedEdge> shortestPath = dijkstraAlg.getPath(from, to); int totalCost = 0; int totalHop = 0; int totalTime = 0; for (DefaultWeightedEdge defaultWeightedEdge : shortestPath.getEdgeList()) { totalCost = totalCost + (int) leastCost.getEdgeWeight(defaultWeightedEdge); totalHop = totalHop + 1; String v1 = leastCost.getEdgeSource(defaultWeightedEdge); String v2 = leastCost.getEdgeTarget(defaultWeightedEdge); System.out.println(totalHop + ". " + v1 + "--->" + v2); } Journey journey = new Journey(); journey.setTotalCost(totalCost); journey.setTotalHop(totalHop); System.out.println(totalCost); System.out.println(totalHop); return journey; }
FlightsReader类
import java.io.File; import java.io.FileNotFoundException; import java.util.HashSet; import java.util.Scanner; public class FlightsReader { private static final File flightsDatasetFolder = new File("FlightsDataset"); private static final File flightsDatasetFlights = new File(flightsDatasetFolder, "flights.csv"); private static final File flightsDatasetAirports = new File(flightsDatasetFolder, "airports.csv"); private HashSet<String[]> airports; private HashSet<String[]> flights; public FlightsReader() throws FileNotFoundException, FlyingPlannerException { this.airports = new HashSet<String[]>(); this.flights = new HashSet<String[]>(); // Adding flights, and building list of needed airport HashSet<String> airportsNeeded = new HashSet<String>(); Scanner flightsScanner = new Scanner(flightsDatasetFlights); while (flightsScanner.hasNextLine()) { String line = flightsScanner.nextLine(); String[] fields = line.split(","); String from = fields[1]; String to = fields[3]; airportsNeeded.add(from); airportsNeeded.add(to); this.flights.add(fields); } flightsScanner.close(); // Adding airports Scanner airportsScanner = new Scanner(flightsDatasetAirports); while (airportsScanner.hasNextLine()) { String line = airportsScanner.nextLine(); String[] fields = line.split(","); if (airportsNeeded.contains(fields[0])) { this.airports.add(fields); } } airportsScanner.close(); } /** * Returns a hash set of airport details (0: airport code, 1: city, 2: airport * name) */ public HashSet<String[]> getAirports() { return this.airports; } /** * Returns a hash set of flight details (0: flight code, 1: airport code of * departure, 2: departure time GMT, 3: airport code of arrival, 4: arrival time * GMT, 5: flight cost) */ public HashSet<String[]> getFlights() { return this.flights; } }
问题根源
核心问题出在main方法的后半段:
- 新建的
FlyingPlanner pr对象未调用populate方法,导致其内部的flightReader成员变量始终为null - 前面已通过
populate完成初始化的fi对象未被用来调用leastCost方法,属于无效创建 - 单独创建的
flightReader对象仅调用了getAirports()和getFlights(),未关联到pr对象,无实际作用
调用pr.leastCost()时,pr内部的flightReader为null,触发空指针异常。
解决方案
修改main方法,选择以下两种方案之一即可:
方案一:复用已初始化的fi对象
import java.io.FileNotFoundException; public class FlyingPlannerMainPartBC { public static void main(String[] args) throws FlyingPlannerException, FileNotFoundException { FlyingPlanner fi = new FlyingPlanner(); try { fi.populate(new FlightsReader()); // 直接使用已初始化的对象调用方法 System.out.println(fi.leastCost("EDI", "DXB")); } catch (FileNotFoundException | FlyingPlannerException e) { e.printStackTrace(); } } }
方案二:给pr对象执行populate初始化
import java.io.FileNotFoundException; public class FlyingPlannerMainPartBC { public static void main(String[] args) throws FlyingPlannerException, FileNotFoundException { try { FlightsReader flightReader = new FlightsReader(); FlyingPlanner pr = new FlyingPlanner(); pr.populate(flightReader); // 关键:初始化内部的flightReader System.out.println(pr.leastCost("EDI", "DXB")); } catch (FileNotFoundException | FlyingPlannerException e) { e.printStackTrace(); } } }
额外说明
FlyingPlanner的populate方法作用是将外部FlightsReader实例赋值给内部成员,必须在调用leastCost等依赖方法前执行- 清理代码中多余的未使用对象,避免逻辑混乱和资源浪费
内容的提问来源于stack exchange,提问作者lucas lootan
相关产品推荐
相关产品推荐

