培训首页  >  JAVA新闻  >  Java编程中容易忽略的10个问题

Java编程中容易忽略的10个问题

[2017-08-24 14:50:03] 浏览量:58 来源:

北大青鸟瀚唐校区

  在Java编码中,我们容易犯一些错误,也容易疏忽一些问题,因此笔者对日常编码中曾遇到的一些经典情形归纳整理成文,以共同探讨。

  1. 纠结的同名

  现象

  很多类的命名相同(例如:常见于异常、常量、日志等类),导致在import时,有时候张冠李戴,这种错误有时候很隐蔽。因为往往同名的类功能也类似,所以IDE不会提示warn。

  解决

  写完代码时,扫视下import部分,看看有没有不熟悉的。替换成正确导入后,要注意注释是否也作相应修改。

  启示

  命名尽量避开重复名,特别要避开与JDK中的类重名,否则容易导入错,同时存在大量重名类,在查找时,也需要更多的辨别时间。

  2. 想当然的API

  现象

  有时候调用API时,会想当然的通过名字直接自信满满地调用,导致很惊讶的一些错误:

  示例一:flag是true?

  boolean flag = Boolean.getBoolean("true");

  可能老是false。

  示例二:这是去年的今天吗(今年是2012年,不考虑闰年)?结果还是2012年:

  Calendar calendar = GregorianCalendar.getInstance();calendar.roll(Calendar.DAY_OF_YEAR, -365);

  下面的才是去年:

  calendar.add(Calendar.DAY_OF_YEAR, -365);

  解决办法

  问自己几个问题,这个方法我很熟悉吗?有没有类似的API? 区别是什么?就示例一而言,需要区别的如下:

  Boolean.valueOf(b) VS Boolean.parseBoolean(b) VS Boolean.getBoolean(b);

  启示

  名字起的更详细点,注释更清楚点,不要不经了解、测试就想当然的用一些API,如果时间有限,用自己为熟悉的API。

  3. 有时候溢出并不难

  现象

  有时候溢出并不难,虽然不常复现:

  示例一:

  long x=Integer.MAX_VALUE+1;System.out.println(x);

  x是多少?竟然是-2147483648,明明加上1之后还是long的范围。类似的经常出现在时间计算:

  数字1×数字2×数字3…

  示例二:

  在检查是否为正数的参数校验中,为了避免重载,选用参数number, 于是下面代码结果小于0,也是因为溢出导致:

  Number i=Long.MAX_VALUE;

  System.out.println(i.intValue()>0);

  解决

  让一开始的一个操作数是long型,例如加上L或者l(不建议小写字母l,因为和数字1太相似了);

  不确定时,还是使用重载吧,即使用doubleValue(),当参数是BigDecimal参数时,也不能解决问题。启示

  对数字运用要保持敏感:涉及数字计算就要考虑溢出;涉及除法就要考虑被除数是0;实在容纳不下了可以考虑BigDecimal之类。

  4. 日志跑哪了?

  现象

  有时候觉得log都打了,怎么找不到?

  示例一:没有stack trace!

  } catch (Exception ex) { log.error(ex); }

  示例二:找不到log!

  } catch (ConfigurationException e) { e.printStackTrace();}

  解决

  替换成log.error(ex.getMessage(),ex);

  换成普通的log4j吧,而不是System.out。

  启示

  API定义应该避免让人犯错,如果多加个重载的log.error(Exception)自然没有错误发生

  在产品代码中,使用的一些方法要考虑是否有效,使用e.printStackTrace()要想下终端(Console)在哪。5. 遗忘的Volatile

  现象

  在DCL模式中,总是忘记加一个Volatile。

  private static CacheImpl instance; //lose volatilepublic static CacheImpl getInstance() { if (instance == null) { synchronized (CacheImpl.class) { if (instance == null) { instance = new CacheImpl (); } } } return instance;}

  解决

  毋庸置疑,加上一个吧,synchronized 锁的是一块代码(整个方法或某个代码块),确保的是这”块“代码的可见性及原子性,但是instance == null次次判断时不再范围内的。所以可能读出的是过期的null。

  启示

  我们总是觉得某些低概率的事件很难发生,例如某个时间并发的可能性、某个异常抛出的可能性,所以不加控制,但是如果可以,还是按照前人的“实践”来写代码吧。至少不用过多解释为啥另辟蹊径。

  6. 不要影响彼此

  现象

  在释放多个IO资源时,都会抛出IOException ,于是可能为了省事如此写:

  public static void inputToOutput(InputStream is, OutputStream os, boolean isClose) throws IOException { BufferedInputStream bis = new BufferedInputStream(is, 1024); BufferedOutputStream bos = new BufferedOutputStream(os, 1024); …. if (isClose) { bos.close(); bis.close(); }}

  假设bos关闭失败,bis还能关闭吗?当然不能!

  解决办法

  虽然抛出的是同一个异常,但是还是各自捕获各的为好。否则一开始的一个失败,后一个面就没有机会去释放资源了。

  启示

  代码/模块之间可能存在依赖,要充分识别对相互的依赖。

  7. 用断言取代参数校验

  现象

  如题所提,作为防御式编程常用的方式:断言,写在产品代码中做参数校验等。例如:

  private void send(List eventList) { assert eventList != null;}

  


文中图片素材来源网络,如有侵权请联系删除
  • Adobe认证
  • Oracle认证
  • 思科认证
  • 微软认证
  • Linux认证
  • 其他
  • 职业技能提升
  • 考证找工作
  • 兴趣爱好
  • 周末班
  • 全日制白班
  • 随到随学

网上报名

热门信息

温馨提示