Java实用技巧:当不能抛出checked异常时

发表于:2010-11-22 10:13

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:Elliotte Rusty Harol    来源:51Testing软件测试网采编

  然而,这违反了compare()方法的约定,因为它不是一个稳定的结果。对于相同的对象,前后两次调用可能产生不同的结果。如果使用这个比较器来排序,那么意味着最终列表没有被正确排序。所以现在试试第2个选项—声明compare()抛出IOException:

  1. publicintcompare(Filef1,Filef2)throwsIOException{  
  2. returnf1.getCanonicalPath().compareTo(f2.getCanonicalPath());  

  这也不能通过编译。因为checked异常是方法签名的一部分,在覆盖方法时,不能增加checked异常,就像不能改变return类型一样。那么最后还剩下一个折中选项:在compare()中捕捉异常,将它转换成运行时异常,然后抛出运行时异常,如清单3所示:

  1. 清单3.将checked异常转换成运行时异常  
  2. publicintcompare(Filef1,Filef2){  
  3. try{  
  4. returnf1.getCanonicalPath().compareTo(f2.getCanonicalPath());  
  5. }  
  6. catch(IOExceptionex){  
  7. thrownewRuntimeException(ex);  
  8. }  

  不幸的是,虽然这样可以通过编译,但是这种方法也不管用,其原因较为微妙。Comparator接口定义一个合约(请参阅参考资料)。这个合约不允许该方法抛出运行时异常(防止因违反泛型类型安全而成为调用代码中的bug)。使用这个比较器的方法合理地依靠它来比较两个文件,而不抛出任何异常。它们没有准备好处理compare()中意外出现的异常。

  正是由于这个微妙的原因,让运行时异常成为代码要处理的外部状况是一个坏主意。这样只是逃避问题,并没有真正处理问题。不处理异常所带来的不良后果仍然存在,包括毁坏数据和得到不正确的结果。

  这样便陷入了困境。既不能在compare()内真正有效地处理异常,又不能在compare()之外处理异常。还剩下什么地方可以处理异常—System.exit()?惟一正确的办法是完全避免这种困境。幸运的是,至少有两种方法可以做到这一点。

  将问题一分为二

  第一种办法是将问题一分为二。比较本身不会导致异常。比较的只是字符串而已。通过标准路径将文件转换成字符串才会导致异常。如果将可能抛出异常的操作与不会抛出异常的操作分开,那么问题就更容易处理了。也就是说,首先将所有文件对象转换为字符串,然后通过字符串比较器(甚至可以通过java.lang.String的自然排序)对字符串排序,最后使用排序后的字符串列表对原始的文件列表排序。这种方法不太直接,但是优点是在列表被改变之前就抛出IOException。如果出现异常,它只会出现在预先设计好的地方,不会造成损害,调用代码可以指定如何处理异常。清单4对此作了演示:

  1. 清单4.先读取,然后排序  
  2. importjava.io.File;  
  3. importjava.io.IOException;  
  4. importjava.util.ArrayList;  
  5. importjava.util.Collections;  
  6. importjava.util.HashMap;  
  7.  
  8. publicclassFileComparator{  
  9.  
  10. privatestaticArrayList<String>getCanonicalPaths(ArrayList<File>files)  
  11. throwsIOException{  
  12. ArrayList<String>paths=newArrayList<String>();  
  13. for(Filefile:files)paths.add(file.getCanonicalPath());  
  14. returnpaths;  
  15. }  
  16.  
  17. publicstaticvoidmain(String[]args)throwsIOException{  
  18. ArrayList<File>files=newArrayList<File>();  
  19. for(Stringarg:args){  
  20. files.add(newFile(arg));  
  21. }  
  22.  
  23. ArrayList<String>paths=getCanonicalPaths(files);  
  24.  
  25. //tomaintaintheoriginalmapping  
  26. HashMap<String,File>map=newHashMap<String,File>();  
  27. inti=0;  
  28. for(Stringpath:paths){  
  29. map.put(path,files.get(i));  
  30. i++;  
  31. }  
  32.  
  33. Collections.sort(paths);  
  34. files.clear();  
  35. for(Stringpath:paths){  
  36. files.add(map.get(path));  
  37. }  
  38. }  
  39.  

42/4<1234>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号