常见Java缺陷模式

面对Java问题的定位-表现得不那么自信,有时我在想是我把问题想的太难,还是问题本身就难,还是我没有专心去看代码...,因为总总,有时还没有看到真正的问题,就阵亡啦,想来死得好冤呀。

本文属于《软件缺陷模式与测试》的读书摘要,感谢作者们辛苦写书,受益良多,书中对Java故障模式进行了总结,分6大类,对每个故障形成原因、表现形式进行分析,并给出了解决方案,值得细细阅读,去体会示例代码,相信读后再看到程序报错,会多那么点底气。

  1. 空指针
    日志:NullPointerException
    表现在:
  1. 可能为null的引用变量
    增加是否为null的判断
  2. 不完全的null条件判断
    判断逻辑不严谨,前面虽判断了是否为null,但是其他地方又用到该对象--修改判断逻辑
  3. 函数返回值可能为null
    list.getNext().dosomething() --list.getNext()为null
    使用返回值前 先做判断
  4. 函数返回值是数组类型时返回null
return new string[0]; 
改成 
return null;
  1. 所调用函数的参数约束为not null
if ( getClass() != obj.getClass() ) 
#如果obj为null,则抛出异常
  1. 重载equals 方法时没有处理好参数null的情况
    总结:获取到的对象有可能为null,在使用前最好先做判断,不为null,才做下一步。
  1. 数组越界
    基础知识:数组的下标index从(0--数组长度-1)
    即是:数组长度为2,数组两个值array_name[0]、array_name[1]
    任何index小于0,大于数组长度-1的-都会抛出数组越界
    日志:ArrayIndexOutOfBoundsException
    1)显示指定数组长度,数组使用越界
 public void arrayStudy(){
        int max_len = 4;
        int[] array = new int[max_len];
        for (int i=0; i<= max_len; i++){
            array[i] = i;   
        }
    }
#当array[4]时报
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
    at pers.qingqian.study.eight.ErrorStudy.arrayStudy(ErrorStudy.java:32)
    at pers.qingqian.study.eight.ErrorStudy.main(ErrorStudy.java:38)
  1. 隐式指定数组长度,数组使用越界
    public void arrayStudy(){
        int max_len = 4;
    //    int[] array = new int[max_len];
        int[] array = new int[]{1,2,3,4};
        for (int i=0; i<= max_len; i++){
            array[i] = i;
        }
    }

3)使用数组,length方法不当,数组使用越界
4)多维数组越界
总结:index只要在0-length-1内,不管是一维还是二维都不会有数组越界

  1. 资源泄漏
    基础知识:指的是封装了类似文件句柄、Socket、数据库连接、图形界面对象等这样的操作系统底层资源的对象被使用后,没有被显性的释放-及时将其回收。
  1. 函数内部资源泄漏
    public void printLines(String fName,Line lines){
      try{
           File file = new File(fName);
           PrintWriter pstr = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));
          ... 省略N行代码
      }catch (IOException e){
            e.printStackTrace();
      }
     }
修改成
    public void printLines(String fName,Line lines){
        PrintWriter pstr = null;
      try{
           File file = new File(fName);
           pstr = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));
            ... 省略N行代码
      }catch (IOException e){
            e.printStackTrace();
      }finally{
          pstr.close();
      }
     }

2)异常路径导致的资源泄漏

public void f() throws FileNotFoundException, IOException {
       FileOutputStream e = null;
       try {
           e = new FileOutputStream("C:\test.java");
           e.write(20);
           e.close();
       }
       finally {}// Defect
   }

当程序运行到e.write(20)抛出异常后,e.close()将不会被执行。
3)私有域资源不能释放导致泄漏
4)函数间调用产生的资源泄漏
简单的讲:A方法中中new了一个资源,没有写释放,直接将资源传递给B方法,B方法也没有是否该资源的地方
5)包装类构造方法出错可能造成资源泄漏
总结:不管出的现象怎么变,都是一个原因,创建了可和底层操作相关的对象时 就必须有释放该对象的方法,否则就会产生资源泄漏。
附:JDK库中资源分配和释放需要注意的问题

  1. 在JDK库中有一些修饰类-不是资源,但它们的构造方法中可能包装了一个资源。调用这些类的释放函数,也释放了内部包装的资源。
    2)不同的资源使用不同的释放函数close、dispose、disconnect
    3)不用资源具有不同的分配方式
    4)释放函数为close
FileOutputStream
FilterOutputStream
...
#这类最多

5)释放函数为dispose

StreamPrintService
CompositeContext
Graphics
InputContext
InputMethod
PaintContext
Window

6)释放函数为disconnect

HttpURLConnection

7)其他分配方式

getConnection
createStatement
executeQuery
getResultSet
prepareStatement
prepareCall
accept

8)可能被包装的非资源类

ByteArrayOutputStream

9)可能被包装的资源类

FileOutputStream
  1. 非法计算
  1. 除法或取余运算的第二个操作数可能为0
    2)常用的数学函数参数超出其定义范围
    如:asin(x) --- -1 <=x <=1
  1. 死循环
  1. 循环语句中的死循环结构
  2. while语句中的死循环结构
  3. do-while语句中的死循环结构
  4. 函数递归调用造成的死循环
    当真有死循环时非常容易发现的,只要访问到死循环代码,你就会发现CPU超级高,去看下线程就能找到是哪里死循环啦。
  1. 并发
    线程并发问题导致的缺陷模式
  1. 不正确的同步
  2. 死锁
  3. 多线程应用中方法调用时机或方式不正确
  4. 同一变量的双重验证
 public static Singleton getInstance(){
        if ( instance == null ){
            synchronized (Singleton.class) {
                if ( instance == null )
                    instance = new Singleton();                
            }           
        }
        return instance;
    }

线程1已运行到 instance = new Singleton(); ,被线程2抢占CPU,线程2运行 因instance不为null,返回对象。
由于instance已经被分配了内存空间,但没有初始化数据,因此利用线程2返回的instance做操作时会出现失败或异常。

  1. 相互初始化的类

你可能感兴趣的:(常见Java缺陷模式)