- 审慎看待Java的循环遍历
Java中的列表遍历可比它看起来要麻烦多了。就以上面两段代码为例:
A:
private final List<Bar> _bars; for(Bar bar : _bars) { //Do important stuff}
B:
private final List<Bar> _bars; for(int i = 0; i < _bars.size(); i++) { Bar bar = _bars.get(i); }
代码A执行的时候会为这个形象列表创立一个迭代器,而代码B就间接应用 get(i) 来获取元素,绝对于代码A省去了迭代器的开销。
实际上这里还是须要一些衡量的。代码A应用了迭代器,保障了在获取元素的时候的工夫复杂度是 O(1) (应用了 getNext() 和 hasNext() 办法),最终的工夫复杂度为 O(n) 。然而对于代码B,循环里每次在调用 _bars.get(i) 的时候破费的工夫复杂度为 O(n) (假如这个list为一个 LinkedList),那么最终代码B整个循环的工夫复杂度就是 O(n^2) (但如果代码B外面的list是 ArrayList, 那 get(i) 办法的工夫复杂度就是 O(1)了)。所以在决定应用哪一种遍历的形式的时候,咱们须要思考列表的底层实现,列表的均匀长度以及所应用的内存。如果咱们须要优化内存,再加上 ArrayList 在大多数状况下查找的工夫复杂度为 O(1) ,能够抉择代码B所应用的办法。
2.在初始化的时候预估汇合的大小
从Java的这篇 文档咱们能够理解到: “一个HashMap 实例有两个影响它性能的因素:初始大小和加载因子(load factor)。 当哈希表的大小达到初始大小和加载因子的乘积的时候,哈希表会进行 rehash操作。如果在一个HashMap 实例外面要存储多个映射关系时,咱们须要设置足够大的初始化大小以便更无效地存储映射关系而不是让哈希表主动增长让后rehash,造成性能瓶颈。”
经常碰到须要遍历一个 ArrayList 并将这些元素保留到 HashMap 外面去,将这个 HashMap 初始化预期的大小能够防止再次哈希所带来的开销。初始化大小能够设置为输出的数组大小除以默认加载因子的后果值(这里取0.7):
优化前的代码:
HashMap<String,Foo> _map; void addObjects(List<Foo> input) { _map = new HashMap<String, Foo>(); for(Foo f: input) { _map.put(f.getId(), f); } }
优化后的代码:
HashMap<String,Foo> _map; void addObjects(List<Foo> input) { _map = new HashMap<String, Foo>((int)Math.ceil(input.size() / 0.7)); for(Foo f: input) { _map.put(f.getId(), f); } }
3.转载学习材料 https://blog.csdn.net/qq35960...