java编程常见错误五[转帖]_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3573 | 回复: 0   主题: java编程常见错误五[转帖]        下一篇 
lynda
注册用户
等级:上尉
经验:570
发帖:49
精华:0
注册:2012-8-7
状态:离线
发送短消息息给lynda 加好友    发送短消息息给lynda 发消息
发表于: IP:您无权察看 2012-8-8 17:19:15 | [全部帖] [楼主帖] 楼主

不必要的同步

错误的写法:

  1. Collection l = new Vector();   
  2. for (...) {   
  3.  l.add(object);   

Vector是ArrayList同步版本。

正确的写法:

  1. Collection l = new ArrayList();   
  2. for (...) {   
  3.  l.add(object);   

错误的选择List类型

根据下面的表格数据来进行选择

ArrayList LinkedList add (append) O(1) or ~O(log(n)) if growing O(1) insert (middle) O(n) or ~O(n*log(n)) if growing O(n) remove (middle) O(n) (always performs complete copy) O(n) iterate O(n) O(n) get by index O(1) O(n)


 HashMap size陷阱

错误的写法:

  1. Map map = new HashMap(collection.size());  
  2. for (Object o : collection) {  
  3.  map.put(o.key, o.value);  

这里可以参考guava的Maps.newHashMapWithExpectedSize的实现. 用户的本意是希望给HashMap设置初始值, 避免扩容(resize)的开销. 但是没有考虑当添加的元素数量达到HashMap容量的75%时将出现resize。

正确的写法:

  1. Map map = new HashMap(1 + (int) (collection.size() / 0.75)); 

对Hashtable, HashMap 和 HashSet了解不够

这里主要需要了解HashMap和Hashtable的内部实现上, 它们都使用Entry包装来封装key/value, Entry内部除了要保存Key/Value的引用, 还需要保存hash桶中next Entry的应用, 因此对内存会有不小的开销, 而HashSet内部实现其实就是一个HashMap. 有时候IdentityHashMap可以作为一个不错的替代方案. 它在内存使用上更有效(没有用Entry封装, 内部采用Object[]). 不过需要小心使用. 它的实现违背了Map接口的定义. 有时候也可以用ArrayList来替换HashSet.

这一切的根源都是由于JDK内部没有提供一套高效的Map和Set实现。

对List的误用

建议下列场景用Array来替代List:

  • list长度固定,比如一周中的每一天
  • 对list频繁的遍历,比如超过1w次
  • 需要对数字进行包装(主要JDK没有提供基本类型的List)

比如下面的代码。

错误的写法:

  1. List<Integer> codes = new ArrayList<Integer>();  
  2. codes.add(Integer.valueOf(10));  
  3. codes.add(Integer.valueOf(20));  
  4. codes.add(Integer.valueOf(30));  
  5. codes.add(Integer.valueOf(40)); 

正确的写法:

  1. int[] codes = { 10, 20, 30, 40 }; 

错误的写法:

  1. // horribly slow and a memory waster if l has a few thousand elements (try it yourself!)  
  2. List<Mergeable> l = ...;  
  3. for (int i=0; i < l.size()-1; i++) {  
  4.  Mergeable one = l.get(i);  
  5.  Iterator<Mergeable> j = l.iterator(i+1); // memory allocation!  
  6.  while (j.hasNext()) {  
  7.  Mergeable other = l.next();  
  8.  if (one.canMergeWith(other)) {  
  9.  one.merge(other);  
  10.  other.remove();  
  11.  }  
  12.  }  

正确的写法:

  1. // quite fast and no memory allocation  
  2. Mergeable[] l = ...;  
  3. for (int i=0; i < l.length-1; i++) {  
  4.  Mergeable one = l[i];  
  5.  for (int j=i+1; j < l.length; j++) {  
  6.  Mergeable other = l[j];  
  7.  if (one.canMergeWith(other)) {  
  8.  one.merge(other);  
  9.  l[j] = null;  
  10.  }  
  11.  }  

实际上Sun也意识到这一点, 因此在JDK中, Collections.sort()就是将一个List拷贝到一个数组中然后调用Arrays.sort方法来执行排序。

用数组来描述一个结构

错误用法:

  1. /**   
  2. * @returns [1]: Location, [2]: Customer, [3]: Incident   
  3. */   
  4. Object[] getDetails(int id) {... 

这里用数组+文档的方式来描述一个方法的返回值. 虽然很简单, 但是很容易误用, 正确的做法应该是定义个类。

正确的写法:

  1. Details getDetails(int id) {...}   
  2. private class Details {   
  3.  public Location location;   
  4.  public Customer customer;   
  5.  public Incident incident;   

对方法过度限制

错误用法:

  1. public void notify(Person p) {   
  2.  ...   
  3.  sendMail(p.getName(), p.getFirstName(), p.getEmail());   
  4.  ...   
  5. }   
  6. class PhoneBook {   
  7.  String lookup(String employeeId) {   
  8.  Employee emp = ...   
  9.  return emp.getPhone();   
  10.  }   

第一个例子是对方法参数做了过多的限制, 第二个例子对方法的返回值做了太多的限制。

正确的写法:

  1. public void notify(Person p) {   
  2.  ...   
  3.  sendMail(p);   
  4.  ...   
  5. }   
  6. class EmployeeDirectory {   
  7.  Employee lookup(String employeeId) {   
  8.  Employee emp = ...   
  9.  return emp;   
  10.  }   

对POJO的setter方法画蛇添足

错误的写法:

  1. private String name;   
  2. public void setName(String name) {   
  3.  this.name = name.trim();   
  4. }   
  5. public void String getName() {   
  6.  return this.name;   

有时候我们很讨厌字符串首尾出现空格, 所以在setter方法中进行了trim处理, 但是这样做的结果带来的副作用会使getter方法的返回值和setter方法不一致, 如果只是将JavaBean当做一个数据容器, 那么最好不要包含任何业务逻辑. 而将业务逻辑放到专门的业务层或者控制层中处理。

正确的做法:

  1. person.setName(textInput.getText().trim());  

日历对象(Calendar)误用

错误的写法:

  1. Calendar cal = new GregorianCalender(TimeZone.getTimeZone("Europe/Zurich"));   
  2. cal.setTime(date);   
  3. cal.add(Calendar.HOUR_OF_DAY, 8);   
  4. date = cal.getTime();  

这里主要是对date, time, calendar和time zone不了解导致. 而在一个时间上增加8小时, 跟time zone没有任何关系, 所以没有必要使用Calendar, 直接用Date对象即可, 而如果是增加天数的话, 则需要使用Calendar, 因为采用不同的时令制可能一天的小时数是不同的(比如有些DST是23或者25个小时)

正确的写法:

  1. date = new Date(date.getTime() + 8L * 3600L * 1000L); // add 8 hrs  




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论