Warning: Parameter 1 to wp_default_scripts() expected to be a reference, value given in /home/liter/domains/vmatianyu.cn/public_html/wp-includes/plugin.php on line 601

编码常见问题总结

1. StringBuffer/StringBuilder 和 字符串拼结的选择
String str = “This is ” + “ a “ + “ test”
String str = “This is ” + f + z
这两个是有区别的
通常StringBuffer更加高效,并且是线程安全的
StringBuilder不是线程安全的,通常这个就够用了,在单线程下比StringBuffer更高效。
2. String.split() 和 StringTokenizer的选择
String.split()功能更加强大,支持正则表达式等,但是如果在简单的分隔符分隔中StringTokenizer快非常多,基于它们的实现方法的不同,StringTokenizer是基于char的判定,尽量少用StringTokenizer.countTokens()方法,这个方法比较慢。
3. String.valueof() 和 (new Integer()).toString()
String.valueof()通过Integer.toString()方法,直接从char构造出一个String对象
后者要先构建一个Integer对象,多创建了一个对象
4. Integer.valueof(int) 方法与 new Integer(i),
当i值在-128到127之间时,对于Integer.valueof会返回cache中的Integer对象,会减少对象的创建,但是要小心,这时Integer i1 = Integer.valueof(5); Integer i2 = Integer.valueof(5); i1 == i2
同样的情况也出现在Long.valueof上
5. If(!s.equals(“”)) 这样判空首先会进行hash,
替代的方法是: if( s!=null && s.length > 0)
6. 丢失异常的来源
try {
doStuff();
} catch(Exception e) {
throw new IOException(“Could not do stuff because: “+ e.getMessage);
}
这个例子里面 doStuff方法抛出的异常被吞掉了
7. 冗余的异常日志
try {
doStuff();
} catch(ExceptionA e) {
logger.error(e.getMessage(), e);
throw e;
} catch(ExceptionB e) {
logger.error(e.getMessage(), e);
throw e;
}
在这里,这两个异常捕获后并没有做什么处理,只是为了输出日志,在系统处部的调用处会有最终的异常拦截,这样会造成日志的内容重复出现。
8. 使用集合类的接口在所有使用它们的地方(Map, List, Set, Collection)
9. 使用HashMap, ArrayList/LinkedList, HashSet 而不是Hashtable和Vector
Hashtable和Vector是线程安全的,意味着更多的同步锁的存在,确认你所用的集合要否要考虑多线程问题,如果不需要,不需要使用这组线程安全的集合。
在确定运用于多线程环境并且有同步的需求,请考虑使用concurrent包下新的基于CAS算法的集合。
10. 使用正确的集合
这要仔细考虑你使用的集合的场景,需要中间插入,还是顺序检索等等,结合集合的算法实现来选择,下面是一个例子关于ArrayList, LinkedList的
| ArrayList LinkedList
add (append) | O(1) or ~O(log(n)) | O(1)
insert (middle) | O(n) or ~O(n*log(n)) | O(1)
iterate | O(n) | O(n)
get by index | O(1) | O(n)
11. 不要用LinkedList用于按index的查找
12. HashMap这样的集合的key值不要使用复杂的对象,特别是一些hash特别复杂的对象,比如URL(它的hashCode,equal会引发网络DNS的分析)
13. 使用System.arrayCopy代替迭代的人工复制,这两个性能差拒巨大!
14. 在对象数组和集合间的转换
MyObj[] a;
List l = Arrays.asList(a);
MyObj[] b = (MyObj[])l.toArray(new MyObj[l.size()])
ArrayList的底层是一个数组,所以这样的转换是最高效的,不要用人工的循环去做。
15. 不要通过Map的keyset去循环取value
Iterator it = map.keySet().iterator();
while(it.hasNext()) {
Object value = map.get(it.next());
}
这里是个不好的写法,在一个循环内又用key在集合内查找一遍
直接访问entryset进行迭代,通过Map.Entry可以取到key值,也可以取到value
16. j++ 这不是一个原子操作,所以这也不是线程安全的
17. Object o = new Object(), 这个也不是线程安全的,典型的问题出现在singleton模式中最常见的double check方法。
18. 尽量避免静态成员,这个会阻止GC对它的回收(Class会永久留在JVM里,这个成员被class引用了,在引用树上就是可到达的,按GC的策略,就不会被回收掉)
19. 不要忘记在finally中释放锁
Lock.lock()
try{
//do something
}finally{
Lock.unlock();
}
20. 声明所有的内部类为static的,这是通常引起memory leak的原因
class OuterA {
class InnerB {
// 这里InnerB会指向一个OuterA的实例,由于Class不会退出JVM
这样就会造成OuterA的实例永远不会被回收,如果这个OuterA又不是单例,而是一个大量创建的对象,就很常易引起memory leak
}
}
21. 如果在内部类中引用了外部类,请使用weakreference
class OuterA {
static class InnerB { // this is an independent class declaration
private final WeakReference _parentRef;
public InnerB(OuterA parent) {
_parentRef = new WeakReference(parent);
}
public void doSmth() {
OuterA parent = _parentRef.get();
if(parent != null) {
}
}
}
}
22. 日志的输出判断
Log.debug(“aaa” + e.getMessage() + “b”);
这里无论日志级别是否是debug,字符串的拼结总会发生
正确的做法如下:
If ( Log.isDebugEnable()) {
Log.debug(“aaa” + e.getMessage() + “b”);
}
更好的方法是使用占位符(这里也可以去掉isDebugEnable的判断)
If ( Log.isDebugEnable()) {
Log.debug(“aaa {} b”, e.getMessage());
}
23. 关于XMLDocument, 尽量避免使用Dom模型,这是一个极其消耗内存,引发GC的操作,除非需要非常复杂的xpath查询,尽量使用SAX进行xml节点的访问

Leave a Reply