Java getCoordinates方法try/catch结构优化咨询
问题说明
现有一个从慢加载页面拉取坐标的方法,功能可正常运行,但代码结构(尤其是try/catch部分)存在较多可优化点,原实现代码如下:
public void getCoordinates(){ EventQueue.invokeLater(() -> loadingLabel.updateCoordinates(true)); consolePanel.getConsole().append("\nRetrieving coordinates from server\n"); shapes.clear(); URL url = null; try { url = new URL("http://TestServlet/"); } catch (MalformedURLException e) { e.printStackTrace(); consolePanel.getConsole().append(e.toString()); } try { URLConnection connection = url.openConnection(); connection.setConnectTimeout(1000); try (InputStream dataSource = url.openStream()) { BufferedReader inputStream = new BufferedReader(new InputStreamReader( dataSource, StandardCharsets.ISO_8859_1)); double xCoordinate; double yCoordinate; String line; while ((line = inputStream.readLine()) != null) { if(!line.startsWith("#")) { consolePanel.getConsole().append(line + "\n"); String[] text = line.split(","); xCoordinate = Double.parseDouble(text[0]); yCoordinate = Double.parseDouble(text[1]); xCoordinate = Math.abs(xCoordinate)/4; yCoordinate = Math.abs(yCoordinate)/4; String name = text[2]; shapes.add(this.mapPanelState.getNewShape(xCoordinate, yCoordinate, 10, name)); } } } } catch (IOException e) { e.printStackTrace(); consolePanel.getConsole().append(e.toString()); } EventQueue.invokeLater(this::repaint); EventQueue.invokeLater(() -> loadingLabel.updateCoordinates(false)); }
具体优化点
- 修复空指针风险,合并冗余try/catch:
MalformedURLException本身是IOException的子类,不需要单独拆分try块。原代码如果URL初始化失败,url变量为null,后续执行url.openConnection()会直接抛出未捕获的空指针异常,加载状态会永远停留在加载中。 - 修复超时配置不生效的bug:原代码创建了
URLConnection对象并设置了1000ms连接超时,但后续直接调用url.openStream()获取流,根本没有用到配置好超时参数的connection对象,等于超时设置完全无效,这也是慢页面加载时程序长时间无响应的核心原因。另外需要同时设置读取超时,避免服务端响应慢时连接一直挂起。 - 完善资源自动管理:原代码只把InputStream放进了try-with-resources,外层包装的InputStreamReader、BufferedReader没有纳入自动关闭范围,极端场景下会出现IO句柄泄漏,所有实现了
AutoCloseable接口的流对象都应该放到try-with-resources的声明中统一释放。 - 避免阻塞UI线程:原代码的网络请求、流读取、数据解析全在调用线程执行,如果是在Swing的事件dispatch线程中调用该方法,会直接阻塞UI渲染导致界面卡死。应该把所有IO、计算逻辑放到后台工作线程执行,只有更新控件、写控制台、触发重绘这类UI操作才通过
EventQueue.invokeLater切回UI线程执行。 - 增加坏数据兜底逻辑:原代码直接读取split后数组的固定下标、直接解析数字,如果服务端返回的行缺字段、坐标值不是合法数字,会抛出未捕获的
ArrayIndexOutOfBoundsException或NumberFormatException,直接中断整个拉取流程。需要增加格式校验和局部异常捕获,跳过无效行即可,不需要让整个流程崩溃。 - 保证状态兜底:原代码只有流程正常走到最后才会关闭加载状态、触发重绘,一旦中间抛出未捕获异常,加载动画会一直转。需要把状态重置的逻辑放到finally块中,无论请求成功、失败还是抛异常,都能正常恢复UI状态。
优化后参考代码
public void getCoordinates(){ // UI操作统一在事件线程执行 EventQueue.invokeLater(() -> { loadingLabel.updateCoordinates(true); consolePanel.getConsole().append("\nRetrieving coordinates from server\n"); }); shapes.clear(); // 网络IO与数据解析放后台线程,避免卡UI new Thread(() -> { try { URL url = new URL("http://TestServlet/"); URLConnection connection = url.openConnection(); // 同时设置连接超时和读取超时 connection.setConnectTimeout(1000); connection.setReadTimeout(5000); // 所有流资源统一自动管理 try (InputStream dataSource = connection.getInputStream(); InputStreamReader isr = new InputStreamReader(dataSource, StandardCharsets.ISO_8859_1); BufferedReader inputStream = new BufferedReader(isr)) { String line; while ((line = inputStream.readLine()) != null) { if (line.startsWith("#")) { continue; } consolePanel.getConsole().append(line + "\n"); String[] text = line.split(","); // 校验行格式合法性 if (text.length < 3) { consolePanel.getConsole().append("跳过无效数据行: " + line + "\n"); continue; } try { double xCoordinate = Math.abs(Double.parseDouble(text[0])) / 4; double yCoordinate = Math.abs(Double.parseDouble(text[1])) / 4; String name = text[2]; shapes.add(this.mapPanelState.getNewShape(xCoordinate, yCoordinate, 10, name)); } catch (NumberFormatException e) { consolePanel.getConsole().append("坐标格式错误,跳过行: " + line + "\n"); } } } } catch (IOException e) { e.printStackTrace(); EventQueue.invokeLater(() -> consolePanel.getConsole().append("坐标拉取失败: " + e + "\n")); } finally { // 无论成功失败,最终都重置UI状态 EventQueue.invokeLater(() -> { repaint(); loadingLabel.updateCoordinates(false); }); } }).start(); }
内容的提问来源于stack exchange,提问作者Mr.Gomer
相关产品推荐
相关产品推荐

