将JSON转换为HashMap时出现NullPointerException,求技术解决方案
问题分析与修复方案
看起来你在使用Gson解析OpenWeatherMap的JSON数据时遇到了不少麻烦,NullPointerException和JSON解析异常的根源主要有三个方面:URL格式错误、对API返回结构理解有误,还有不正确的Gson使用方式。我来帮你一步步修复这些问题:
核心问题拆解
- URL参数格式错误:你代码里用了
&来分隔URL参数,这是HTML转义字符,直接放在URL里会导致OpenWeatherMap API无法正确识别参数,返回的可能不是有效的JSON数据(甚至是错误页面),后续解析自然会出问题。 - API返回结构误解:OpenWeatherMap的
forecast(5天预报)接口返回的JSON结构中,main和wind并不是直接在根对象里的,它们嵌套在list数组的每一个元素中。你直接调用respMap.get("main")会得到null,再调用null.toString()就触发了NullPointerException。 - 错误的对象转Map方式:就算拿到了正确的嵌套对象,先调用
toString()再传入jsonToMap是错误的——Gson解析后的Map对象调用toString()得到的不是标准JSON格式,再次解析会抛出异常。正确的做法是直接将嵌套的Object强制转换为Map<String, Object>。
修复后的完整代码
import java.util.HashMap; import java.net.*; import java.io.*; import java.util.List; import java.util.Map; import com.google.gson.*; import com.google.gson.reflect.*; public class Weather { private static Map<String, Object> jsonToMap(String str){ return new Gson().fromJson(str, new TypeToken<HashMap<String, Object>>() {}.getType()); } public static void main(String[] args){ String apiKey = "YOUR_ACTUAL_API_KEY"; // 替换成你的OpenWeatherMap API密钥 // 修正URL中的参数分隔符:把&换成& String urlString = "http://api.openweathermap.org/data/2.5/forecast?id=1174872&APPID=" + apiKey + "&units=metric"; try{ StringBuilder result = new StringBuilder(); URL url = new URL(urlString); URLConnection connection = url.openConnection(); BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = reader.readLine()) != null) { result.append(line); } reader.close(); System.out.println("json print: "); System.out.println(result); // 解析根对象 Map<String, Object> respMap = jsonToMap(result.toString()); // 获取list数组(forecast接口返回的是多个时段的预报数据) List<Map<String, Object>> forecastList = (List<Map<String, Object>>) respMap.get("list"); if (forecastList == null || forecastList.isEmpty()) { System.out.println("No forecast data available"); return; } // 取第一个时段的预报数据(最近的预报) Map<String, Object> firstForecast = forecastList.get(0); // 直接将嵌套的main和wind转换为Map,不需要转String Map<String, Object> mainMap = (Map<String, Object>) firstForecast.get("main"); Map<String, Object> windMap = (Map<String, Object>) firstForecast.get("wind"); // 输出数据,先判空避免NPE if (mainMap != null) { System.out.println("Current Temperature: " + mainMap.get("temp")); System.out.println("Current Humidity: " + mainMap.get("humidity")); } if (windMap != null) { System.out.println("Current Wind Speed: " + windMap.get("speed")); System.out.println("Current Wind Direction : " + windMap.get("deg")); } }catch(NullPointerException e){ System.out.println("Null Pointer Exception Occurred!"); e.printStackTrace(); // 打印堆栈信息,方便排查具体哪里出问题 }catch (IOException e) { System.out.println("Input Output Exception Occurred!"); e.printStackTrace(); } } }
额外提示
- 记得把代码里的
YOUR_ACTUAL_API_KEY替换成你从OpenWeatherMap获取的有效API密钥。 - 添加了
e.printStackTrace()可以帮助你更精准地定位异常发生的位置,方便后续调试。 - 增加了判空逻辑,避免因为API返回结构变化或者数据缺失导致的NPE。
内容的提问来源于stack exchange,提问作者FallenGodfather
相关产品推荐
相关产品推荐

