本文将一点一滴的累计记录Java中的一些细节知识。不只是加以说明,而是所有的细节都找到来源,以官方文档、知名社区的介绍为主。
StringTokenizer和String.split
//Use StringTokenizer
StringTokenizer st = new StringTokenizer("this is a test");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
//Use split
String[] results = "this is a test".split("\\s");
for (String result:results){
System.out.println(result);
}
关于StringTokenizer和String.split的差异说法很多。官方文档http://docs.oracle.com/javase/6/docs/api/java/util/StringTokenizer.html 有定性说明(附注:最新的JDK8 API文档中也是相同的说明)。
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
大意是StringTokenizer是一个历史遗留类,为了保证向后兼容性而保留这个类。推荐在新的代码中使用split或regex替换。
至于网上的测评资料说StringTokenizer比String.split效率更高,由于没有亲测就不妄加评论了。作为项目管理者,从风险和可靠性的角度考虑,在项目规范和代码review的过程中,还是以官方文档为准。
transient和volatile关键词的使用
transient volatile Set<K> keySet = null;
transient volatile Collection<V> values = null;
transient是变量修饰符,表明该字段不是对象持久状态的一部分,储存的时候不用储存,比如序列化这个对象时,该字段是不会储存的。
volatile也是变量修饰符,只能用来修饰变量。volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。 而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
在此解释一下Java的内存机制:
Java使用一个主内存来保存变量当前值,而每个线程则有其独立的工作内存。线程访问变量的时候会将变量的值拷贝到自己的工作内存中,这样,当线程对自己工作内存中的变量进行操作之后,就造成了工作内存中的变量拷贝的值与主内存中的变量值不同。
Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时地得到共享成员变量的变化。而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。