面對(duì)Java問題的定位-表現(xiàn)得不那么自信衡招,有時(shí)我在想是我把問題想的太難篱昔,還是問題本身就難,還是我沒有專心去看代碼...始腾,因?yàn)榭偪傊莨簦袝r(shí)還沒有看到真正的問題,就陣亡啦浪箭,想來死得好冤呀穗椅。
本文屬于《軟件缺陷模式與測(cè)試》的讀書摘要,感謝作者們辛苦寫書奶栖,受益良多匹表,書中對(duì)Java故障模式進(jìn)行了總結(jié),分6大類宣鄙,對(duì)每個(gè)故障形成原因袍镀、表現(xiàn)形式進(jìn)行分析,并給出了解決方案冻晤,值得細(xì)細(xì)閱讀苇羡,去體會(huì)示例代碼,相信讀后再看到程序報(bào)錯(cuò)鼻弧,會(huì)多那么點(diǎn)底氣设江。
- 空指針
日志:NullPointerException
表現(xiàn)在:
- 可能為null的引用變量
增加是否為null的判斷 - 不完全的null條件判斷
判斷邏輯不嚴(yán)謹(jǐn)锦茁,前面雖判斷了是否為null,但是其他地方又用到該對(duì)象--修改判斷邏輯 - 函數(shù)返回值可能為null
list.getNext().dosomething() --list.getNext()為null
使用返回值前 先做判斷 - 函數(shù)返回值是數(shù)組類型時(shí)返回null
return new string[0];
改成
return null;
- 所調(diào)用函數(shù)的參數(shù)約束為not null
if ( getClass() != obj.getClass() )
#如果obj為null绣硝,則拋出異常
- 重載equals 方法時(shí)沒有處理好參數(shù)null的情況
總結(jié):獲取到的對(duì)象有可能為null,在使用前最好先做判斷蜻势,不為null,才做下一步。
- 數(shù)組越界
基礎(chǔ)知識(shí):數(shù)組的下標(biāo)index從(0--數(shù)組長(zhǎng)度-1)
即是:數(shù)組長(zhǎng)度為2鹉胖,數(shù)組兩個(gè)值array_name[0]握玛、array_name[1]
任何index小于0,大于數(shù)組長(zhǎng)度-1的-都會(huì)拋出數(shù)組越界
日志:ArrayIndexOutOfBoundsException
1)顯示指定數(shù)組長(zhǎng)度甫菠,數(shù)組使用越界
public void arrayStudy(){
int max_len = 4;
int[] array = new int[max_len];
for (int i=0; i<= max_len; i++){
array[i] = i;
}
}
#當(dāng)array[4]時(shí)報(bào)
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)
- 隱式指定數(shù)組長(zhǎng)度挠铲,數(shù)組使用越界
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)使用數(shù)組,length方法不當(dāng)寂诱,數(shù)組使用越界
4)多維數(shù)組越界
總結(jié):index只要在0-length-1內(nèi)拂苹,不管是一維還是二維都不會(huì)有數(shù)組越界
- 資源泄漏
基礎(chǔ)知識(shí):指的是封裝了類似文件句柄、Socket痰洒、數(shù)據(jù)庫(kù)連接瓢棒、圖形界面對(duì)象等這樣的操作系統(tǒng)底層資源的對(duì)象被使用后,沒有被顯性的釋放-及時(shí)將其回收丘喻。
- 函數(shù)內(nèi)部資源泄漏
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)異常路徑導(dǎo)致的資源泄漏
public void f() throws FileNotFoundException, IOException {
FileOutputStream e = null;
try {
e = new FileOutputStream("C:\test.java");
e.write(20);
e.close();
}
finally {}// Defect
}
當(dāng)程序運(yùn)行到e.write(20)拋出異常后脯宿,e.close()將不會(huì)被執(zhí)行。
3)私有域資源不能釋放導(dǎo)致泄漏
4)函數(shù)間調(diào)用產(chǎn)生的資源泄漏
簡(jiǎn)單的講:A方法中中new了一個(gè)資源泉粉,沒有寫釋放连霉,直接將資源傳遞給B方法,B方法也沒有是否該資源的地方
5)包裝類構(gòu)造方法出錯(cuò)可能造成資源泄漏
總結(jié):不管出的現(xiàn)象怎么變嗡靡,都是一個(gè)原因跺撼,創(chuàng)建了可和底層操作相關(guān)的對(duì)象時(shí) 就必須有釋放該對(duì)象的方法,否則就會(huì)產(chǎn)生資源泄漏讨彼。
附:JDK庫(kù)中資源分配和釋放需要注意的問題
- 在JDK庫(kù)中有一些修飾類-不是資源歉井,但它們的構(gòu)造方法中可能包裝了一個(gè)資源。調(diào)用這些類的釋放函數(shù)哈误,也釋放了內(nèi)部包裝的資源哩至。
2)不同的資源使用不同的釋放函數(shù)close、dispose黑滴、disconnect
3)不用資源具有不同的分配方式
4)釋放函數(shù)為close
FileOutputStream
FilterOutputStream
...
#這類最多
5)釋放函數(shù)為dispose
StreamPrintService
CompositeContext
Graphics
InputContext
InputMethod
PaintContext
Window
6)釋放函數(shù)為disconnect
HttpURLConnection
7)其他分配方式
getConnection
createStatement
executeQuery
getResultSet
prepareStatement
prepareCall
accept
8)可能被包裝的非資源類
ByteArrayOutputStream
9)可能被包裝的資源類
FileOutputStream
- 非法計(jì)算
- 除法或取余運(yùn)算的第二個(gè)操作數(shù)可能為0
2)常用的數(shù)學(xué)函數(shù)參數(shù)超出其定義范圍
如:asin(x) --- -1 <=x <=1
- 死循環(huán)
- 循環(huán)語(yǔ)句中的死循環(huán)結(jié)構(gòu)
- while語(yǔ)句中的死循環(huán)結(jié)構(gòu)
- do-while語(yǔ)句中的死循環(huán)結(jié)構(gòu)
- 函數(shù)遞歸調(diào)用造成的死循環(huán)
當(dāng)真有死循環(huán)時(shí)非常容易發(fā)現(xiàn)的憨募,只要訪問到死循環(huán)代碼,你就會(huì)發(fā)現(xiàn)CPU超級(jí)高袁辈,去看下線程就能找到是哪里死循環(huán)啦菜谣。
- 并發(fā)
線程并發(fā)問題導(dǎo)致的缺陷模式
- 不正確的同步
- 死鎖
- 多線程應(yīng)用中方法調(diào)用時(shí)機(jī)或方式不正確
- 同一變量的雙重驗(yàn)證
public static Singleton getInstance(){
if ( instance == null ){
synchronized (Singleton.class) {
if ( instance == null )
instance = new Singleton();
}
}
return instance;
}
線程1已運(yùn)行到 instance = new Singleton(); ,被線程2搶占CPU,線程2運(yùn)行 因instance不為null,返回對(duì)象尾膊。
由于instance已經(jīng)被分配了內(nèi)存空間媳危,但沒有初始化數(shù)據(jù),因此利用線程2返回的instance做操作時(shí)會(huì)出現(xiàn)失敗或異常冈敛。
- 相互初始化的類