用日志记录异常
错误的写法:
- 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)) ...