Java十大低级错误
为了规范大家的编程行为,借鉴前人的编程经验,避免低级错误的不断发生,特发布MDSP产品Java十大低级错误,供所有Java开发人员学习:
1、方法和变量命名随意而不规范,没有类注释、方法注释或注释不规范,代码修改后,不同步修改注释,导致注释与代码不符。
2、数据类不重载toString()方法(说明:编程规范要求“所有的数据类必须重载toString() 方法,返回该类有意义的内容”)。
3、对方法的调用不进行空指针判断而造成空指针异常。
4、数据库操作、IO操作的资源没有及时释放,数据库结果集和连接释放顺序不正确,或者使用没有必要的预处理。
5、循环体内包含了大量没有必要在循环中处理的语句,循环体内循环获取数据库连接,循环体内进行不必要的try-catch操作。(说明:编程规范中建议“不要在循环体内调用同步方法和使用 try-catch 块”)
6、嵌套使用try-catch,或者try-catch后面没有必要的finally操作(说明:数据库操作、IO操作等需要使用结束close()的对象必须在try -catch-finally 的finally中close())。
7、不对数组下标作范围校验。
8、equals操作时没有将常量放在equals操作符的左边(说明:字符串变量与常量比较时,先写常量,这样可以避免空指针异常)。
9、字符串转化为数字时没有做异常处理。
10、没有在异常分支记录日志导致问题定位困难。
代码案例(说明:所有样例都是错误的代码):
1、方法和变量命名随意而不规范,没有类注释、方法注释或注释不规范,代码修改后,不同步修改注释,导致注释与代码不符。
public class MethodName
{
//错误:没有类的注释
//错误:方法的注释不规范、方法名不规范
public void a( int i )
{
//错误:变量名称太短
String b = "";
//错误:变量名称太长,超过40个字符
String longVariableLongVariableLongVariableLongVariable= "";
}
/**
* <一句话功能简述>方法命名约定:应以小写字母开头、同时命名不应含有下划线字符。
* <功能详细描述>
* @param i
* @see [类、类#方法、类#成员]
*/
public void Check_Method( int i )
{
// 错误:方法名称不规范
//错误:变量名称不规范
String b = "";
}
/**
* <一句话功能简述>变量、方法名、类名、接口名避免出现美元字符$。
* <功能详细描述>
* @param i
* @see [类、类#方法、类#成员]
*/
public void Fo$o ()
{
// 错误:方法名称不规范
}
/**
* <一句话功能简述>注意hashCode方法大小写。此规则用于推测作者可能是要实现hashCode方法,但大小写错了。
* <功能详细描述>
* @return
* @see [类、类#方法、类#成员]
*/
public int hashcode()
{
// 错误:方法名称不规范
int temp = 0;
// oops,this probably was supposed to be hashCode
return temp;
}
/**
*
* @param o 只有参数类型和返回值类型不一致,方法名equals完全相同(包括大小写也相同),推测可能是想实现equals方法。
* @return
*/
public int equals(Object o)
{
// 错误:方法名称不规范
// oops, thisprobably was supposed to be boolean equals
int temp = 0;
return temp;
}
/**
* <一句话功能简述>只有参数类型和返回值类型不一致,方法名equals完全相同(包括大小写也相同),推测可能是想实现equals方法。
* <功能详细描述>
* @param s
* @return
* @see [类、类#方法、类#成员]
*/
public booleanequals(String s)
{
// 错误:方法名称不规范
// oops, thisprobably was supposed to be equals(Object)
return true;
}
/**
* <一句话功能简述>'getX()'方法同时返回值又是 'boolean' ,则建议用'isX()'命名。checkParameterizedMethods属性用于决定是否对带参数的方法检测。
* <功能详细描述>
* @return
* @see [类、类#方法、类#成员]
*/
public boolean getFoo()
{
// 错误:方法名称不规范
// bad
return true;
}
}
2、数据类不重载toString()方法(说明:编程规范要求“所有的数据类必须重载toString() 方法,返回该类有意义的内容”)。
public classContent extendsBaseMetaData
{
private String oldCID;
private String cId;
private String spId;
private inttype;
private int serviceType;
.........................
/**
* 设置修改标识
* @param update_flag修改标识
*/
public voidsetUpdate_flag(String update_flag)
{
this.updateFlg= update_flag;
}
public voidsetVersion(String version)
{
this.version= version;
}
public StringtoString()
{
//没有重载toString方法或者重载无意义的toString方法
return null;
}
}
3、对方法的调用不进行空指针判断而造成空指针异常。
/**
* <一句话功能简述>演示不进行空指针判断造成空指针异常
* <功能详细描述>
*
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class NullPoint
{
/**
* <一句话功能简述>
* <功能详细描述>
* @return
* @see [类、类#方法、类#成员]
*/
public String returnNull()
{
Stringtemp = null;
return temp;
}
public void checkNull()
{
String str1 = "aa";
//错误:没有对returnNull()的值进行为空判断,会造成空指针
if (str1.equals(returnNull()))
{
str1 = returnNull();
}
print(str1);
}
public void print(String str)
{
}
}
4、数据库操作、IO操作的资源没有及时释放,数据库结果集和连接释放顺序不正确,或者使用没有必要的预处理。
/**
* <一句话功能简述>该类用来演示没有释放资源的的错误
* <功能详细描述>
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class ReleaseRes
{
public void releaseDB ()
{
Connectionconn = null;
APLResultSet rs = null;
Stringsql= "";
try
{
conn =DB.getConnection();
rs =DB.query(sql);
if (rs.next())
{
return rs.getString("currentdate");
}
else
{
returnDateTool.getCurrentDate(pattern);
}
Conn.close();
//错误:连接没有在finally正确释放,会出现异常时导致在运行一段时间后,系统由于连接池满载而崩溃。
}
catch (DBException e)
{
...................
}
//错误:资源APLResultSet没有正确释放
}
/**
* <一句话功能简述>
* <功能详细描述>
* @param file
* @see [类、类#方法、类#成员]
*/
public void releaseIO (Filefile)
{
StringBuffer sb = null;
BufferedReader in = null;
try
{
in = new BufferedReader(new FileReader(file));
sb = new StringBuffer();
for (String line; (line = in.readLine()) != null;)
{
sb.append(line + "\r\n");
}
}
catch (IOException ex)
{
Throwex;
}
//错误:IO资源没有正确释放,需要在finally中释放资源
}
5、循环体内包含了大量没有必要在循环中处理的语句,循环体内循环获取数据库连接,循环体内进行不必要的try-catch操作。(说明:编程规范中建议“不要在循环体内调用同步方法和使用 try-catch 块”)
/**
* <一句话功能简述>该类用来演示循环中的错误
* <功能详细描述>
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class CheckCycle
{
public void cycleInfo()
{
String[] Str = null;
//获取各个部件的通知地址
Str =outNotify.getResult();
StringBuffer sb = null;
BufferedReader in = null;
Connectionconn = null;
APLResultSet rs = null;
Stringsql= "";
File file= null;
for (int i = 0; i <Str.length; i++)
{
//错误:判断完全可以在for外部进行而不是在内内部。
if( null != Str)
{
System.out.print(Str[i]);
}
//错误:不要在循环中获取数据库连接。
conn =DB.getConnection();
//错误:循环体内进行无必要的try-catch操作,完全可以放在循环外边。
try
{
//错误:不要在循环中获取IO连接。
in= new BufferedReader(new FileReader(file));
sb= new StringBuffer();
}
catch (IOException ex)
{
Throw ex;
}
}
}
}
6、嵌套使用try-catch,或者try-catch后面没有必要的finally操作(说明:数据库操作、IO操作等需要使用结束close()的对象必须在try -catch-finally 的finally中close())。
/**
* <一句话功能简述>演示嵌套循环的错误
* <功能详细描述>
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class NestingTry
{
/**
* <一句话功能简述>
* <功能详细描述>
* @see [类、类#方法、类#成员]
*/
public void checkTry()
{
StringBuffer sb = null;
BufferedReader in = null;
File file = null;
try
{
initFtpClient(this.ftpClient,getFtpServConfig());
// 把绝对路径加入到文件中
String[] absoluteFiles null;
//错误:完全没有必要在内容进行异常处理,而应该将异常处理放在try块后面进行处理。
try
{
absoluteFiles =addAbsolutePath(this.ftpClient, files);
}
Catch(IOException ex)
{
Throw ex;
}
File file = null;
in = new BufferedReader(newFileReader(file));
sb = new StringBuffer();
}
catch (Exception e)
{
throw newFtpOperationsException(FtpConst.Ftp_Operations_Del_Error,
"IOException wheninvoking deleteFiles method", e);
}
//错误:IO资源没有正确释放,必须有finally进行释放资源
}
}
7、不对数组下标作范围校验。
/**
* <一句话功能简述>该类用来演示数据下标越界
* <功能详细描述>
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class ArrayOver
{
public void checkArray()
{
//获取一个数组对象
String[] cIds =ContentService.queryByName(name);
if(null != cIds)
{
//错误:只是考虑到cids有可能为null的情况,但是cids完全有可能是个0长度的数组,因此cIds[0]有可能数组下标越界。
Stringcid=cIds[0];
}
}
}
8、equals操作时没有将常量放在equals操作符的左边(说明:字符串变量与常量比较时,先写常量,这样可以避免空指针异常)。
/**
* 定义常量
*/
public static final String SP_NAME = "SPNAME";
/**
* <一句话功能简述>常量比较
* <功能详细描述>
* @see [类、类#方法、类#成员]
*/
public void equalsConst()
{
Stringtemp = null;
//错误;//在temp为null的情况下,此时会导致意想不到的异常抛出,如果将常量放在左边,就不会有这种问题。
if(temp.equals(SP_NAME))
{
temp = SP_NAME + "AA";
}
}
9、字符串转化为数字时没有做异常处理。
/**
* <一句话功能简述>字符传传唤成数字
* <功能详细描述>
* @see [类、类#方法、类#成员]
*/
public void switchStr()
{
String temp = "123a";
//错误:对字符串转换为数字没有进行任何异常处理。可能抛出未知异常。
if(Integer.parseInt(temp)== 123)
{
//......
}
}
10、没有在异常分支记录日志导致问题定位困难。
/**
* 根据objectId删除业务信息
*
* @param id 业务objectId
* @throws IllegalServiceStatusException 非法业务状态异常
* @see [类、类#方法、类#成员]
*/
public void deleteService(String id)
throwsIllegalServiceStatusException
{
log.enterMethodDebugLog(new Object[][] {{"id", id}});
MdspTServiceinfo serviceInfo =getMdspServiceByObjectId(id);
if (null == serviceInfo)
{
return;
//错误:异常分支没有记录日志,导致问题定位困难。
}
........
}