1. 关于基础数据类型。
还记得上一片文章中结尾部分的那个例子么?
因为计算机的2进制的特性,Java语言(其他语言好像也一样)无法准确地进行float,double类型数据的计算,所以,作这些计算的时候需要考虑使用BigDecimal着各类。
2. String类与StringBuffer类
Java的String类提供如下的简单的字符串连接方法。
String s1 = “a”;
String s2 = “b”;
String s3 = “c”;
String s = s1 + s2 + s3;
但是这里有一个问题,String类的每一次加操作都会产生一个新的对象。当你针对String类的加的操作开始变得多起来的时候,不但程序占用内存会增加得非常明显,程序运行时间也会大大增加。这个时候需要考虑StringBuffer类的append方法。笑着不是一个极端主义者,所以,笑着还是倾向,不要只要对字符串采用加的操作就用append方法。而是应该根据具体情况,自己衡量一下。具体的测试,自己写个for循环1w次,很容易测试出来的。
3. 关于import*
尽量不要采用import*的写法,而是应该把要import的类具体写出来。这里的原因,一个是因为import*的写法会影响程序的阅读,导致维护者不是很清楚你具体用到了哪些类。但是更主要的是,如果你import*,那么在你打包生成jar,war等等文件的时候,你的*代表的所有类都会被打包进去。一方面导致了你发布内容的大小大幅度增加,另外,很可能会泄漏了一些你并不想要泄露出去的内容。这才是问题的关键,安全第一。
4. 合理使用异常处理,不要过度使用。
Java得异常处理是个不错的东西。可以节省我们很多工作量。但是,有异常处理的的代码段比没有异常处理的代码段运行的时间要增加不少。所以不要把什么都交给异常处理。我们应该做出适当的判断,最后的最后,处理不了的东西才应该交给异常处理,这也符合业务处理的逻辑。
比如,存在FileNotFoundException,但是,
try {
} catch ( FileNotFoundException ) {
}
就不如
if ( f.exists() ) {
} else {
}
5. 尽量不要简单的捕捉Exception异常。
因为在Java里面旧的异常会被新的异常所淹没,而使得我们仅仅根据新的异常信息很难判断出问题究竟出在什么地方。而简单的捕捉Exception异常,会使得这种可能性大大增加。另外,简单的捕捉Exception异常会使得我们很难针对不同的异常采取对应的措施。所以请尽量捕捉具体的异常而不是Exception这个超级异常。可以考虑如下代码结构。
try {
} catch() {
} catch() {
} catch(Exception) {
}
关于Java里面旧的异常会被新的异常所淹没地解决办法,一般是需要自己来实现一些异常类的,因为不是这一篇文章的重点,这里不打算具体讨论。
6. 不要重复生成你的对象。Java中new一个新的对象,相对的是要花费比较多的时间的。虽然现在的CPU可能不太在乎这么点时间。但是积少成多啊。可能new一次的,就尽量不要new两次了。目前阶段能够接触到的是要在循环体外而不是循环体内new除你的对象,这很简单,也很容易注意到。但是在复杂的系统中,如何尽量减少你new一个对象的次数,是否需要使用static关键字,就并不是那么明显,那么容易被考虑到,解决掉了。而且考虑到可维护性,代码结构,等等因素,取舍角度也是不同的。至少,我们先记住这样的原则。不要重复生成你的对象。
7. 不要在你的循环体内做一些不必要的计算。比如:
for(;;al.size()){}
不如:
int size = al.size();
for(;;size){}
虽然看过文章好像说Java编译器会做优化,这两种写法是一样的。但是基本原则“不要在你的循环体内做一些不必要的计算。”我想这是不会有任何不同意见的。笑着不喜欢记那么多东西,记不住。对于编译器到底做哪些优化笑着也觉得是个没有什么承诺的事情。还是自己控制更安心一点。当然,当后一种写法严重影响了你的代码可读性的时候,可以在效率和可读性之间作一个权衡。毕竟现在的CPU还是很强悍的,循环次数不是很多的话效率的影响基本可以忽略。
8. String 的==与equal()
在对字符串的相等判断,==判断的是地址是否相同,equal()判断的是字符值是否相同。大多数时候==跟equal()的结果都是相同的。这是因为String对象是不变模式的,如果你不是明确地new一个String对象,Java对于String对象的保存默认的是会把新生成的String对象放到一个缓冲区,然后每次判断缓冲区中是否已经有了这个对象,如果有了,那么后建立的同样字符值的String对象也会指向最初建立是该字符值对象的地址。也就是说字符值相同的时候,大多数情况下地质也是相同的。==与equal()效果是相同的。但是当对象是str = new String(“abc”)生成的而不是直接str = “abc”这样赋值生成,或者经过了一些字符串连接处理,或者通过StringBuffer等对象生成,都会在内存中开辟新的地址的,这个时候==和equal()结果是不同的。
是不是稍微有些复杂?这里需要一些关于内存,堆栈,对象保存方面的理解。笑着不想纠缠于这个问题的讨论。如果不能理解,那么只要记住如果你想要判断两个字符串的字符值是否相等,没有别的要求的时候,那么请使用equal()而不是==,至于什么时候需要使用==,我想当你需要的时候,你自然就会明白了。实际上,对于字符串的判断,我们很少需要用的==的。
9. 关于str.equal(“abc”)和”abc”.equal(str)
这个好像争论也挺多的,第一种常量写在后面可能符合大多数人的习惯,也符合我们的逻辑思维。但是需要多一个str是否为null的判断。否则这里是有可能出现异常的。而后一种写法不需要多做关于是否为null这个判断。就笑着个人喜好来说,比较喜欢后一种写法。
10. Java是传值还是传引用?
曾经,Java程序员都是从C++转过来的,大家最爱讨论的就是这个冒似高深实际却很无聊的问题。笑着不懂什么叫做传值什么叫做传引用。笑着只想提醒大家记住下面的事实,记住就足够了。到底这种事实说明了Java是传值还是传引用,争论下去有什么意义么?
事实是,在一个方法里面,对他的参数对象本身是无法改变的。比如:
private void changeParam1(XXXClass _pc){
_pc = new XXXClass();// 想要改变参数对象本身。
}
上面代码的_pc = new XXXClass();操作,只是在函数体内部生效。除了函数体,你传给这个函数的对象是什么,那他还是什么。就是说你在函数内部是无法改变参数所指向的内存地址的。你是无法改变参数对象本身本身的。这里,争论的产生就是C++程序员非常喜欢的一个好象叫做Swap的函数,在Java里面无法同样实现了。
但是,Java里面是可以对参数对象的属性进行变更的。
private void changeParam2(XXXClass _pc){
_pc.setField(fieldValue)// 想要改变参数对象的属性。
}
如上代码是可以实现你的意图的。
至于原因,需要画画内存中对象存储,对象指向才能说清楚。笑着觉得那没有研究的价值。记住结论就好了。画图好累的,笑着就偷懒不画了。
11. 适当考虑Java的跨平台性,尽量使用Java提供给你的功能。
比如,换行回车到底是/r/n还是/r或者是/n,不同的系统是不一样的。所以考虑一下使用Java提供的功能吧
System类中提供public static String getProperty(String key)方法,其中key可以取如下的值。
file.separator | 文件分隔符(在 UNIX 系统中是“/”) |
path.separator | 路径分隔符(在 UNIX 系统中是“:”) |
line.separator | 行分隔符(在 UNIX 系统中是“/n”) |