| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 378 人关注过本帖, 1 人收藏
标题:程序员 几个错误
取消只看楼主 加入收藏
p454252689
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2011-4-22
结帖率:0
收藏(1)
已结贴  问题点数:20 回复次数:0 
程序员 几个错误
     每一个顺序员在编写代码的过程中都免不了出现错误或是小的失误, 这些小的错误和失误往往使得顺序员还得返工。 那么, 如何才能尽量避免这些错误的发作呢?笔者总结只有在日常的编写代码中总结出经验, 在这篇文章中, 笔者列出了几个个Java编程中常见的错误, 你可以把这些错误添加到你的代码审查的检查列表中, 这样在经过代码审查后, 你可以确信你的代码中不再存在这类错误了。     
常见错误    1:多次拷贝字符串   测试所不能发现的一个错误是生成不可变(immutable)对象的多份拷贝。  不可变对象是不可改变的, 因此不需求拷贝它。 最常用的不可变对象是String。     如果你必须改变一个String对象的内容, 你应该运用StringBuffer。 下面的代码会正常工作:
     String s = new String ("Text here");   
但是, 这段代码性能差, 而且没有必要这么复杂。 你还可以用以下的方式来重写上面的代码:
  String temp = "Text here";
    String s = new String (temp);   
    但是这段代码包含额外的String, 并非完全必要。 更好的代码为: 
    String s = "Text here";  
常见错误       2:没有克隆(clone)返回的对象   封装(encapsulation)是面向对象编程的重要概念。 不幸的是, Java为不小心打破封装提供了方便Java允许返回私无数据的援用(reference)。 下面的代码提醒了这一点:
    import java. awt. Dimension;
      /** *//***Example class. The x and y values should never*be negative. */  
     public class Example. . .
    {
      private Dimension d = new Dimension (0, 0);
      public Example (). . . { }
       /** *//*** Set border="1" Height and width. Both border="1" Height and width must be nonnegative * or an exception is thrown. */
       public synchronized void setValues (int border="1" Height, int width) throws IllegalArgumentException. . . {   
    if (border="1" Height <0 || width <0)
       throw new IllegalArgumentException();
       d. border="1" height = border="1" Height;
      d. width = width;   
    }
      public synchronized Dimension getValues(). . . {
       // Ooops! Breaks encapsulation
      return d;
       }
    }   
    Example类保证了它所存储的border="1" Height和width值永远非正数, 试图运用setValues()方法来设置负值会触发异常。 不幸的是, 由于getValues()返回d的援用, 而不是d的拷贝,
     你可以编写如下的破坏性代码:
       Example ex = new Example();
      Dimension d = ex. getValues();
       d. border="1" height = -5;
      d. width = -10;
       如今, Example对象拥有负值了!如果getValues() 的调用者永远也不设置返回的Dimension对象的width 和border="1" Height值, 那么仅凭测试是不能够检测到这类的错误。
       不幸的是, 随着时间的推移, 客户代码能够会改变返回的Dimension对象的值, 这个时候, 跟随错误的本源是件单调且费时的事情, 尤其是在多线程环境中。   更好的方式是让getValues()返回拷贝:
         public synchronized Dimension getValues(). . . {
       return new Dimension (d. x, d. y);
      }   
    如今, Example对象的内部状态就安全了。 调用者可以依据需求改变它所得到的拷贝的状态, 但是要修改Example对象的内部状态, 必须通过setValues()才可以。
   三、常见错误   3:不用要的克隆   我们如今晓得了get方法应该返回内部数据对象的拷贝, 而不是援用。 但是, 事情没有相对:
    /** *//*** Example class. The value should never * be negative. */
      public class Example. . . {
       private Integer i = new Integer (0);
       public Example (). . . { }
       /** *//*** Set x. x must be nonnegative* or an exception will be thrown*/
       public synchronized void setValues (int x) throws IllegalArgumentException. . . {
      if (x <0)
       throw new IllegalArgumentException();
       i = new Integer (x);
       }
       public synchronized Integer getValue(). . . {
       // We can"t clone Integers so we makea copy this way.
       return new Integer (i. intValue());
      }
     }   
    这段代码是安全的, 但是就象在错误1#那样, 又作了多余的工作。 Integer对象, 就象String对象那样, 一旦被创建就是不可变的。 因此, 返回内部Integer对象, 而不是它的拷贝, 也是安全的。   方法getValue()应该被写为:
         public synchronized Integer getValue(). . . {
      // "i" is immutable, so it is safe to return it instead of a copy.
       return i;  
    }   
    Java顺序比C++顺序包含更多的不可变对象。 JDK 所提供的若干不可变类包括:  ·Boolean ·Byte ·Character ·Class ·Double ·Float ·Integer ·Long ·Short ·String  ·大部分的Exception的子类  
    常见错误四:  自编代码来拷贝数组   Java允许你克隆数组, 但是开发者通常会错误地编写如下的代码, 成果在于如下的循环用三行做的事情, 如果采用Object的clone方法用一行就可以完成:
     public class Example. . . {
   private int[] copy;
    /** *//*** Save a copy of "data". "data" cannot be null. */
      public void saveCopy (int[] data). . . {
      copy = new int[data. length];
      for (int i = 0; i   copy[i] = data[i];
       }
      }   这段代码是正确的, 但却不用要地复杂。 saveCopy()的一个更好的实现是:     void saveCopy (int[] data). . . {
       try. . . {
       copy = (int[])data. clone();
       }catch (CloneNotSupportedException e). . . {
       // Can"t get here.
      }
      }
      如果你常常克隆数组, 编写如下的一个工具方法会是个好主见:
         static int[] cloneArray (int[] data). . . {
      try. . . {
      return(int[])data. clone();
      }catch(CloneNotSupportedException e). . . {
       // Can"t get here.   
       }
     }   
    这样的话, 我们的saveCopy看起来就更繁复了:
         void saveCopy (int[] data). . . {
      copy = cloneArray ( data); 
     }  
    常见错误  5:拷贝错误的数据   有时候顺序员晓得必须返回一个拷贝, 但是却不小心拷贝了错误的数据。 由于仅仅做了部分的数据拷贝工作, 下面的代码与顺序员的意图有偏差:
     import java. awt. Dimension;
    /** *//*** Example class. The border="1" Height and width values should never * be   negative. */
      public class Example. . . {
      static final public int TOTAL_VALUES = 10;
       private Dimension[] d = new Dimension[TOTAL_VALUES];
       public Example (). . . { }
       /** *//*** Set border="1" Height and width. Both border="1" Height and width must be nonnegative * or an exception will be thrown. */
      public synchronized void setValues (int index, int border="1" Height, int width) throws IllegalArgumentException. . . {
       if (border="1" Height <0 || width <0)
       throw new IllegalArgumentException();
       if (d[index] == null)
       d[index] = new Dimension();
       d[index]. border="1" height = border="1" Height;
       d[index]. width = width;
      }
       public synchronized Dimension[] getValues()
       throws CloneNotSupportedException. . . {
       return (Dimension[])d. clone();
      }
      }   
    这儿的成果在于getValues()方法仅仅克隆了数组, 而没有克隆数组中包含的Dimension对象, 因此, 虽然调用者无法改变内部的数组使其元素指向不同的Dimension对象, 但是调用者却可以改变内部的数组元素(也就是Dimension对象)的内容。 方法getValues()的更好版本为
    :public synchronized Dimension[] getValues() throws CloneNotSupportedException. . .{
      Dimension[] copy = (Dimension[])d. clone();
       for (int i = 0; i   
    // NOTE: Dimension isn"t cloneable.
      if (d != null)
      copy[i] = new Dimension (d[i]. border="1" Height, d[i]. width);
       }
       return copy;
      }   
    在克隆原子类型数据的多维数组的时候, 也会犯类似的错误。 原子类型包括int, float等。 复杂的克隆int型的一维数组是正确的, 如下所示:
      public void store (int[] data) throws CloneNotSupportedException. . . {
      this. data = (int[])data. clone();   
    // OK
      }
      拷贝int型的二维数组更复杂些。 Java没有int型的二维数组, 因此一个int型的二维数组实际上是一个这样的一维数组:它的类型为int[]。 复杂的克隆int[][]型的数组会犯与上面例子中getValues()方法第一版本异样的错误, 因此应该避免这么做。 下面的例子演示了在克隆int型二维数组时错误的和正确的做法:
      public void wrongStore (int[][] data) throws CloneNotSupportedException. . . {
      this. data = (int[][])data. clone();
    // Not OK!
      }
      public void rightStore (int[][] data). . . {
      // OK!
       this. data = (int[][])data. clone();
      for (int i = 0; i
       if (data != null)
      this. data[i] = (int[])data[i]. clone();
      }
      }  
搜索更多相关主题的帖子: 程序员 字符串 Java 文章 
2011-04-22 22:35
快速回复:程序员 几个错误
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.023246 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved