分享

Java常见问题汇总(二)

 俊在晴空 2016-07-12

接上篇Java常见问题汇总(一)

重复包装RuntimeException

错误的写法:

try {   
doStuff();   
} catch(Exception e) {   
throw new RuntimeException(e);   
}

正确的写法:

try {   
doStuff();   
} catch(RuntimeException e) {   
throw e;   
} catch(Exception e) {   
throw new RuntimeException(e.getMessage(), e);   
}   
try {   
doStuff();   
} catch(IOException e) {   
throw new RuntimeException(e.getMessage(), e);   
} catch(NamingException e) {   
throw new RuntimeException(e.getMessage(), e);   
}


不正确的传播异常


错误的写法:

try {   
} catch(ParseException e) {   
throw new RuntimeException();   
throw new RuntimeException(e.toString());   
throw new RuntimeException(e.getMessage());   
throw new RuntimeException(e);   
}

       主要是没有正确的将内部的错误信息传递给调用者. 第一个完全丢掉了内部错误信息, 第二个错误信息依赖toString方法, 如果没有包含最终的嵌套错误信息, 也会出现丢失, 而且可读性差. 第三个稍微好一些, 第四个跟第二个一样。

正确的写法:

try {   
} catch(ParseException e) {   
throw new RuntimeException(e.getMessage(), e);   
}


用日志记录异常


错误的写法:

try {   
...   
} catch(ExceptionA e) {   
log.error(e.getMessage(), e);   
throw e;   
} catch(ExceptionB e) {   
log.error(e.getMessage(), e);   
throw e;   
}

一般情况下在日志中记录异常是不必要的, 除非调用方没有记录日志。


异常处理不彻底


错误的写法:

try {   
is = new FileInputStream(inFile);   
os = new FileOutputStream(outFile);   
} finally {   
try {   
is.close();   
os.close();   
} catch(IOException e) {   
/* we can't do anything */   
}   
}

is可能close失败, 导致os没有close

正确的写法:

try {   
is = new FileInputStream(inFile);   
os = new FileOutputStream(outFile);   
} finally {   
try { if (is != null) is.close(); } catch(IOException e) {/* we can't do anything */}   
try { if (os != null) os.close(); } catch(IOException e) {/* we can't do anything */}   
}


捕获不可能出现的异常


错误的写法:

try {   
... do risky stuff ...   
} catch(SomeException e) {   
// never happens   
}   
... do some more ...

正确的写法:

try {   
... do risky stuff ...   
} catch(SomeException e) {   
// never happens hopefully   
throw new IllegalStateException(e.getMessage(), e); // crash early, passing all information   
}   
... do some more ...


transient的误用


错误的写法:

public class A implements Serializable {   
private String someState;   
private transient Log log = LogFactory.getLog(getClass());   

public void f() {   
log.debug('enter f');   
...   
}   
}

       这里的本意是不希望Log对象被序列化. 不过这里在反序列化时, 会因为log未初始化, 导致f()方法抛空指针, 正确的做法是将log定义为静态变量或者定位为具备变量。

正确的写法:

public class A implements Serializable {   
private String someState;   
private static final Log log = LogFactory.getLog(A.class);   

public void f() {   
log.debug('enter f');   
...   
}   
}   
public class A implements Serializable {   
private String someState;   

public void f() {   
Log log = LogFactory.getLog(getClass());   
log.debug('enter f');   
...   
}   
}


不必要的初始化


错误的写法:

public class B {   
private int count = 0;   
private String name = null;   
private boolean important = false;   
}

       这里的变量会在初始化时使用默认值:0, null, false, 因此上面的写法有些多此一举。

正确的写法:

public class B {   
private int count;   
private String name;   
private boolean important;   
}


最好用静态final定义Log变量

private static final Log log = LogFactory.getLog(MyClass.class);

这样做的好处有三:

  • 可以保证线程安全

  • 静态或非静态代码都可用

  • 不会影响对象序列化


选择错误的类加载器

错误的代码:

Class clazz = Class.forName(name);   
Class clazz = getClass().getClassLoader().loadClass(name);

       这里本意是希望用当前类来加载希望的对象, 但是这里的getClass()可能抛出异常, 特别在一些受管理的环境中, 比如应用服务器, web容器, Java WebStart环境中, 最好的做法是使用当前应用上下文的类加载器来加载。

正确的写法:

ClassLoader cl = Thread.currentThread().getContextClassLoader();   
if (cl == null) cl = MyClass.class.getClassLoader(); // fallback   
Class clazz = cl.loadClass(name);


反射使用不当

错误的写法:

Class beanClass = ...   
if (beanClass.newInstance() instanceof TestBean) ...

       这里的本意是检查beanClass是否是TestBean或是其子类, 但是创建一个类实例可能没那么简单, 首先实例化一个对象会带来一定的消耗, 另外有可能类没有定义默认构造函数. 正确的做法是用Class.isAssignableFrom(Class) 方法。

正确的写法:

Class beanClass = ...   
if (TestBean.class.isAssignableFrom(beanClass)) ...


不必要的同步

错误的写法:

Collection l = new Vector();   
for (...) {   
l.add(object);   
}

Vector是ArrayList同步版本。

正确的写法:

Collection l = new ArrayList();   
for (...) {   
l.add(object);   
}


错误的选择List类型

根据下面的表格数据来进行选择


ArrayListLinkedList
add (append)O(1) or ~O(log(n)) if growingO(1)
insert (middle)O(n) or ~O(n*log(n)) if growingO(n)
remove (middle)O(n) (always performs complete copy)O(n)
iterateO(n)O(n)
get by indexO(1)O(n)


HashMap size陷阱

错误的写法:

Map map = new HashMap(collection.size());  
for (Object o : collection) {  
  map.put(o.key, o.value);  
}

       这里可以参考guava的Maps.newHashMapWithExpectedSize的实现. 用户的本意是希望给HashMap设置初始值, 避免扩容(resize)的开销. 但是没有考虑当添加的元素数量达到HashMap容量的75%时将出现resize。

正确的写法:

Map map = new HashMap(1   (int) (collection.size() / 0.75));









ASO推荐

“图灵it教育”是今日图灵it教育培训机构专门的信息交流、分享平台,哈尔滨今日灵图职业培训学校专注IT培训15年,秉承着 “以实战为导向,以质量为中心”的教学理念,随着全球IT技术的不断进步而不断发展创新!










    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多