9、忽视日志记录时机、级别

  现象

  存在下面两则示例:

  示例一:该不该记录日志?

catch (SocketException e)
{
    LOG.error("server error", e);
    throw new ConnectionException(e.getMessage(), e);
}

  示例二:记什么级别日志?

  在用户登录系统中,每次失败登录:

LOG.warn("Failed to login by "+username+");

  解决

  1、移除日志记录:在遇到需要re-throw的异常时,如果每个人都按照先记录后throw的方式去处理,那么对一个错误会记录太多的日志,所以不推荐如此做;但是如果re-throw出去的exception没有带完整的trace( 即cause),那么好还是记录下。

  2、如果恶意登录,那系统内部会出现太多WARN,从而让管理员误以为是代码错误。可以反馈用户以错误,但是不要记录用户错误的行为,除非想达到控制的目的。

  启示

  日志改不改记?记成什么级别?如何记?这些都是问题,一定要根据具体情况,需要考虑:

  1、是用户行为错误还是代码错误?

  2、记录下来的日志,能否能给别人在不造成过多的干扰前提下提供有用的信息以快速定位问题。

  10、忘设初始容量

  现象

  在JAVA中,我们常用Collection中的Map做Cache,但是我们经常会遗忘设置初始容量。

cache = new LRULinkedHashMap< K, V>(maxCapacity);

  解决

  初始容量的影响有多大?拿LinkedHashMap来说,初始容量如果不设置默认是16,超过16×LOAD_FACTOR,会resize(2 * table.length),扩大2倍:采用 Entry[] newTable = new Entry[newCapacity]; transfer(newTable),即整个数组Copy, 那么对于一个需要做大容量CACHE来说,从16变成一个很大的数量,需要做多少次数组复制可想而知。如果初始容量设置很大,自然会减少resize, 不过可能会担心,初始容量设置很大时,没有Cache内容仍然会占用过大体积。其实可以参考以下表格简单计算下, 初始时还没有cache内容, 每个对象仅仅是4字节引用而已。

  ● memory for reference fields (4 bytes each);

  ● memory for primitive fields

Java type  Bytes required
boolean  1
byte  
char  2
short  
int  4
float  
long  8
double  

  启示

  不仅是map, 还有stringBuffer等,都有容量resize的过程,如果数据量很大,不能忽视初始容量可以考虑设置下,否则不仅有频繁的 resize还容易浪费容量。

  在Java编程中,除了上面枚举的一些容易忽视的问题,日常实践中还存在很多。相信通过不断的总结和努力,可以将我们的程序完美呈现给读者。