打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Java常见问题汇总(二)
接上篇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技术的不断进步而不断发展创新!
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
spring ioc原理(看完后大家可以自己写一个spring)
信息摘要工具类
Hibernate 中getSession().save() 保存不到数据库 解决办法
Best Practices for Using Exceptions
Guava学习笔记:简化异常处理的Throwables类
JAVA异常处理方式 try
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服