一.只做有目的性的优化
大型软件系统肯定非常关注性能问题。虽然我们希望能够写出较的代码,但很多时候,如果想对代码进行优化,我们却无从下手。例如,下面的这段代码会影响到性能吗?
public void processIntegers(List<Integer>integers){
for(Integer value:integers){
for(int i=integers.size()-1;i>=0;i--){
value+=integers.get(i);
}
}
}
这就得视情况而定了。上面这段代码可以看出它的处理算法是O(n³)(使用大O符号),其中n是list集合的大小。如果n只有5,那么就不会有问题,只会执行25次迭代。但如果n是10万,那可能会影响性能了。请注意,即使这样我们也不能判定肯定会有问题。尽管此方法需要执行10亿次逻辑迭代,但会不会对性能产生影响仍然有待讨论。
较重要的是天下没有0元的午餐,因此为了降低代价,我们通常会通过类似于缓存、循环展开或预计算值这类技术去实现优化,这样反而增加了系统的复杂性,也降低了代码的可读性。如果这种优化可以提高系统的性能,那么即使变得复杂,那也是值得的。
二.包装类和基本类型的选择
在代码中,如果可以使用基本数据类型来做局部变量类型的话尽量使用基本数据类型,因为基本类型的变量是存放在栈中的,包装类的变量是在堆中,栈的操作速度比堆快很多。
三.重新定义类里面的equals()方法
对象识别可能是一个很难解决的问题:如果两个对象在内存中占据相同的位置,那么它们是相同的吗?如果它们的id相同,它们是相同的吗?或者如果所有的字段都相等呢?虽然每个类都有自己的标识逻辑,但是在系统中有很多西方都需要去判断是否相等。例如,有如下的一个类,表示订单购买…
public class Purchase{
private long id;
public long getId(){
return id;
}
public void setId(long id){
this.id=id;
}
}
……就像下面写的这样,代码中肯定有很多地方都是类似于的:
Purchase originalPurchase=new Purchase();
Purchase updatedPurchase=new Purchase();
if(originalPurchase.getId()==updatedPurchase.getId()){
//Execute some logic for equal purchases
}
这些逻辑调用的越多(反过来,违背了DRY原则),Purchase类的身份信息也会变得越来越多。如果出于某种原因,更改了Purchase类的身份逻辑(例如,更改了标识符的类型),则需要更新标识逻辑所在的位置肯定也非常多。
四.ArrayList和LinkedList的选择
这个问题比较常见。通常程序员应当能够对list的使用场景做出评估,然后根据特性作出选择。ArrayList底层是使用数组实现的,因此随机读取数据比LinkedList快很多,而LinkedList是使用链表实现的,新增和删除数据的速度比ArrayList快不少。