JAVA源代码缺陷说明Word格式文档下载.docx
《JAVA源代码缺陷说明Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《JAVA源代码缺陷说明Word格式文档下载.docx(41页珍藏版)》请在冰豆网上搜索。
stream.close();
byte[]b=newbyte[200];
inti=stream.read(b);
//使用已释放资源的stream对象
}
1.3 解引用类
null解引用
对于值可能为null的引用类型变量,未检查变量是否为null而直接解引用该变量。
null解引用会导致程序抛出NullPointerException类型的运行时异常。
在解引用变量前检查变量是否为null并对变量值为null的情况进行处理。
示例3:
publicStringexampleFun(boolflag,Strings1,Strings2){
Strings3=null;
if(flag){
s3=s1+s2;
//变量s3的值可能为null,当变量s3的值为null时,以下语句出现null解引用
returns3.trim();
示例4:
publicStringexampleFun(boolflag,Strings1,Strings2)
{
returns3.trim();
returnnull;
1.4 控制语句类
用于控制程序流程的条件表达式为常量
用于控制程序流程的条件表达式的结果恒为真或恒为假。
用于控制程序流程的条件表达式为常量时,代码的部分分支路径永远不会被执行,条件表达式变得毫无意义。
当用于控制循环的条件表达式的结果恒为真时,可能导致程序进入死循环。
publicvoidexampleFun(){
Strings="
"
;
if(s==null){//用于控制程序流程的条件表达式“s==null”恒为假
“If”语句的“then”分支无语句
“If”语句的“then”分支无语句。
“If”语句的“then”分支无语句通常不是程序的本意。
“If”语句的“then”分支无语句通常是遗漏了代码,可能会导致程序出错或程序功能实现不正确。
补充“then”分支的代码。
publicvoidexampleFun(booleancond){
if(cond){
//“If”语句的“then”分支无语句
“If”语句的“then”分支只有分号
“If”语句的“then”分支只有分号。
“If”语句的“then”分支只有分号通常不是程序的本意。
“If”语句的“then”分支只有分号通常是打字错误,可能会导致“If”语句的“then”分支部分的代码在不满足判断条件时也进行执行。
修复打字错误。
publicvoidexampleFun(){
inta=0;
if(a>
0);
//“If”语句的“then”分支只有分号
a++;
}
在用于控制程序流程的条件表达式中使用位运算符“&
”或“|”
”或“|”。
当用于控制程序流程的条件表达式使用位运算符“&
”或“|”时,程序的本意可能为使用运算符“&
&
”或“||”,可能会改变原本的判断逻辑,导致程序执行不同的分支路径。
使用运算符“&
”或“||”。
示例5:
publicvoidexampleFun(intarr[]){
//在用于控制程序流程的条件表达式中使用位运算符“&
”
if(arr!
=null&
arr.length!
=0){
示例6:
=null&
1.5 运算处理类
非法计算
对于某些算术运算的操作数,其取值是受到限制的,如%,/,%=,/=后面的除数都不应该为0。
一些数学函数的参数是有定义域的,如果变量的取值范围中包括不合法的数据则会引起异常。
如asin,acos,atan2,div,fmod,ldiv,log,log10,sqrt等。
非法计算错误会产生运行时异常处理逻辑,导致未知错误。
在使用算术运算前应检查操作数或运算参数,判断其是否符合相应的约束,并对不符合的情况进行处理。
示例7:
publicvoidexampleFun(inti){
if(i<
10){
i=20/i;
//非法计算
}
示例8:
if((i<
10)&
(i!
=0)){
运算结果溢出
使用int类型进行计算,然后将计算结果赋值给一个long类型的变量。
使用int类型进行计算,当计算结果超出int类型的最大值时,计算结果不会自动转换成long类型,会导致计算结果错误。
将int类型转换成long类型后再进行计算。
示例9:
longconvertDaysToMilliseconds(intdays){
return1000*3600*24*days;
//运算结果溢出
示例10:
return1000L*3600*24*days;
浮点数的相等或不等比较
两个浮点型或双精度浮点型的值使用“==”或“!
=”运算符进行比较。
浮点数在计算机中的存储和计算是不精确的,因此对浮点数采用“==”或“!
=”运算符进行比较可能得到与期望结果相反的结果。
通过计算两个浮点数之间的差的绝对值是否小于一个允许的误差值判断浮点数之间是否相等或不等。
publicboolexampleFun(doublea,doubleb){
if(a==b){//浮点数的相等比较
returntrue;
returnfalse;
自身相除或比较
在表达式中变量与自己相除或作比较。
自身相除或比较通常不是程序的本意,程序中可能存在打字错误,自身相除可能导致程序出错或程序功能实现不正确,自身比较可能导致部分代码永远不会被执行。
修复程序中存在的打字错误。
示例11:
publicboolexampleFun(inta,intb){
if(a<
a){//a<
a恒为假
returntrue;
returnfalse;
示例12:
b){
位运算错误
int或long变量使用位运算符“&
”或“|”与位掩码进行位运算后与常量进行比较,且比较结果恒为真或恒为假,不会随着int或long变量的值的改变而发生变化。
表达式的结果为可预知的常量通常不是程序的本意,此缺陷可能表明位运算符或位掩码存在错误,导致程序出错或程序功能实现不正确。
修复位运算符或位掩码中存在的错误。
示例13:
publicvoidexampleFun(inti){
if(i|0x0F==0){//表达式“i|0x0F==0x0F”恒为假
示例14:
if(i&
0x0F==0){
1.6 比较判断类
equals方法的参数为对象自身
代码中调用equals方法的对象和equals方法的参数对象相同。
若代码中调用equals方法的对象和equals方法的参数对象相同,则返回值恒为true,当作为条件表达式用于控制程序流程时,代码的部分分支路径永远不会被执行,条件表达式无意义。
当作为条件表达式用于控制循环语句时,可能导致程序进入死循环。
abc"
if(s.equals(s)){//“s.equals(s)”恒为真
equals方法的参数为null
调用equals方法时参数为null。
调用equals方法时参数为null则返回值恒为假,作为条件表达式时会导致部分代码永远不会被执行,条件表达式无意义。
Strings="
if(s.equals(null)){//“s.equals(null)”恒为假
...
this引用与null比较
用this引用与null进行比较。
this引用不可能为null,因此使用this引用与null进行比较无意义。
删除this引用与null进行比较的代码。
if(this==null){//“this==null”恒为假
equals方法的错误使用
equals方法的错误使用情况包括:
两个数组间使用equals方法进行比较、数组和非数组间使用equals方法进行比较、不兼容的类型间使用equals方法进行比较。
两个数组间使用equals方法进行比较就相当于“==”运算符,比较的是数组对象的引用而不是数组的值,可能导致判断逻辑错误;
数组和非数组间、不兼容的类型间使用equals方法进行比较,比较的结果总是false,可能导致部分代码永远不会被执行,条件表达式无意义。
。
两个数组间的值比较应对数组的每个元素的值分别进行比较,两个数组间的引用比较应使用“==”运算符。
publicclassMyClass{
Stringnames[];
publicbooleanequals(Objecto){
if(!
(oinstanceofMyClass)){
returnfalse;
MyClassm=(MyClass)o;
returnthis.names.equals(m.names);
//两个数组间采用equals方法进行比较
低效的空字符串判断
采用equals方法判断字符串是否为空字符串。
采用equals方法判断字符串是否为空字符串会导致程序运行效率低下。
采用length方法获取字符串的长度并判断长度是否为0。
示例15:
publicvoidexampleFun(Strings){
if(s.equals("
)){//采用equals方法判断字符串是否为空字符串
示例16:
if(s.length()==0){
使用“==”运算符比较字符串
使用“==”运算符比较字符串。
“==”运算符比较的是字符串对象的引用而不是字符串的值。
使用“==”运算符比较字符串可能会产生欺骗的结果。
使用equals方法比较字符串对象。
示例17:
if(s=="
){//使用“==”运算符比较字符串
示例18:
if(s.equals("
)){
1.7 类型转换类
集合可能抛出ClassCastException异常
从集合中获取元素后进行转换的目标类型不为存入集合的元素类型或其父类。
当类型转换不兼容时会引起ClassCastException异常。
在进行类型转换前使用“instanceof”运算符来检查对象是否是转换的目标类型的一个实例。
publicclassMyClass{
HashMaphm;
publicvoidexampleFun(){
hm.put("
a"
"
b"
);
//存入集合时元素为String类型,取出时为MyClass类型
MyClassmc=(MyClass)hm.get("
类型转换引起潜在的ClassCastException异常
使用“instanceof”运算符检查的对象是A类型的实例,在转换时却指向B类,且B类不为A类的父类。
在进行类型转换前采用“instanceof”运算符检查被转换的对象是否为转换的目标类型。
示例19:
publicvoidexampleFun(Objecto){
if(oinstanceofString){
//对象“o”的类型是“String”类型,却转换成“StringBuffer”类型
StringBuffersb=(StringBuffer)o;
示例20:
if(oinstanceofStringBuffer){
StringBuffersb=(StringBuffer)o;
从集合中获取元素的关键字类型与存入集合的关键字类型不一致
从集合中获取元素的关键字类型与存入集合的关键字类型不一致。
从集合中获取元素的关键字类型与存入集合的关键字类型不一致将导致无法从集合中获取期望的元素。
采用存入集合的关键字类型从集合中获取元素。
示例21:
HashMaplen=newHashMap();
voidfill(Filedir){
File[]list=dir.listFiles();
for(inti=0;
i<
list.length;
i++){
Filefile=list[i];
len.put(file,newLong(file.length()));
//存入的关键字类型是“File”
intgetLength(Stringfile){
Longl=(Long)len.get(file);
//取出的关键字类型是“String”
if(l!
=null){
returnl.intValue();
return0;
示例22:
intgetLength(Filefile){
//取出的关键字类型也是“File”
1.8 声明定义类
子类的成员变量与父类的public或protected成员变量同名
子类的成员变量与父类的public或protected成员变量同名。
子类的成员变量与父类的public或protected成员变量同名会隐藏父类的成员变量,容易产生混淆。
避免子类的成员变量与父类的public或protected成员变量同名。
示例23:
publicclassSuperClass{
protectedinta;
publicclassSubClassextendsSuperClass{
privateinta;
//声明了一个与父类的protected成员变量同名称的变量。
示例24:
//...
privateintb;
非构造器的方法命名与类名相同
方法命名与类名相同,且包含返回类型。
方法与构造器名字相同容易造成混淆,可能造成不期望的结果。
对非构造器的方法进行命名时不要与类名相同。
若为构造器,则不应包含返回类型。
示例25:
publicStringname;
publicvoidMyClass()//方法名与类名相同,返回类型为“void”
{
this.name=name;
示例26:
publicMyClass()
1.9 调用返回类
忽略只作用在返回值上的方法的返回值
调用只作用在返回值上的方法,该方法不改变其他对象的值,并且调用该方法的返回值未赋值给变量保存。
方法只作用在返回值上却忽略返回值则方法调用无任何意义,可能会导致程序出错或程序功能实现不正确。
调用只作用在返回值上的方法时,保存方法的返回值。
示例27:
publicStringexampleFun(Strings){
s.trim();
//未保存s.trim方法的返回值
returns;
示例28:
Stringstr;
str=s.trim();
returnstr;
忽略新创建的对象
使用“new”关键字创建对象时,未保存对象的引用,也未直接调用对象的方法。
忽略新创建对象会造成程序代码难以理解,也有可能隐藏逻辑错误。
保存新创建的对象的引用,或直接调用新创建的对象的方法。
示例29:
newObject();
//新创建对象被忽略
示例30:
Objecto=newObject();
忽略read或skip方法的返回值
使用read、skip等方法获取数据时,未对方法返回值进行检查就直接使用获取的数据。
使用read、skip等方法获取数据时,获取数据可能失败,如果不对返回值进行检查就直接使用获取的数据可能导致程序出错。
使用read、skip等方法获取数据时,对方法返回值进行检查,确保获取数据成功后再使用获取的数据。
示例31:
voidcopyFile(Stringsrc,Stringdest){
FilesrcFile=newFile(src);
FiledestFile=newFile(dest);
FileInputStreamfis=newFileInputStream(srcFile);
FileOutputStreamfos=newFileOutputStream(destFile);
bytebytes[]=newbyte[1024];
fis.read(bytes);
//read操作未检查方法返回值
fos.write(bytes,0,bytes.length);