一、变量和常量
1.变量命名要规范(小驼峰,大驼峰)
2. Value Never Read
没有使用该变量的值。赋值之后,变量或者被重新赋值,或者超出范围之外。
//错误的代码示范
r = getName();
r = getNewBuffer(buf);
修复建议:为了使代码易于理解和维护,删除不必要的赋值。
3. Local variables should not be declared and then immediately returned or thrown
变量不应该在马上被返回或者抛出的情况下被声明。
//错误的代码示范
public long computeDurationInMilliseconds() {
long duration = (((hours * 60) + minutes) * 60 + seconds ) * 1000 ;
return duration;
}
public void doSomething() {
RuntimeException myException = new RuntimeException();
throw myException;
}
//正确的代码示范
public long computeDurationInMilliseconds() {
return (((hours * 60) + minutes) * 60 + seconds ) * 1000 ;
}
public void doSomething() {
throw new RuntimeException();
}
4. Math operands should be cast before assignment
数字操作在操作或赋值之前要分配结果类型。
//错误的代码示例
float twoThirds = 2/3; // Noncompliant; int division. Yields 0.0
long millisInYear = 1_000*3_600*24*365; // Noncompliant; int multiplication. Yields 1471228928
long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647
long bigNegNum = Integer.MIN_VALUE-1; //Noncompliant, gives a positive result instead of a negative one.
Date myDate = new Date(seconds * 1_000); //Noncompliant, won't produce the expected result if seconds > 2_147_483
...
public long compute(int factor){
return factor * 10_000; //Noncompliant, won't produce the expected result if factor > 214_748
}
public float compute2(long factor){
return factor / 123; //Noncompliant, will be rounded to closest long integer
}
//正确的代码示范
float twoThirds = 2/3; // Noncompliant; int division. Yields 0.0
long millisInYear = 1_000*3_600*24*365; // Noncompliant; int multiplication. Yields 1471228928
long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647
long bigNegNum = Integer.MIN_VALUE-1; //Noncompliant, gives a positive result instead of a negative one.
Date myDate = new Date(seconds * 1_000); //Noncompliant, won't produce the expected result if seconds > 2_147_483
...
public long compute(int factor){
return factor * 10_000; //Noncompliant, won't produce the expected result if factor > 214_748
}
public float compute2(long factor){
return factor / 123; //Noncompliant, will be rounded to closest long integer
}
Compliant Solution
float twoThirds = 2f/3; // 2 promoted to float. Yields 0.6666667
long millisInYear = 1_000L*3_600*24*365; // 1000 promoted to long. Yields 31_536_000_000
long bigNum = Integer.MAX_VALUE + 2L; // 2 promoted to long. Yields 2_147_483_649
long bigNegNum = Integer.MIN_VALUE-1L; // Yields -2_147_483_649
Date myDate = new Date(seconds * 1_000L);
...
public long compute(int factor){
return factor * 10_000L;
}
public float compute2(long factor){
return factor / 123f;
}
//或者是这样
float twoThirds = (float)2/3; // 2 cast to float
long millisInYear = (long)1_000*3_600*24*365; // 1_000 cast to long
long bigNum = (long)Integer.MAX_VALUE + 2;
long bigNegNum = (long)Integer.MIN_VALUE-1;
Date myDate = new Date((long)seconds * 1_000);
...
public long compute(long factor){
return factor * 10_000;
}
public float compute2(float factor){
return factor / 123;
}
原因:将算数结果分配给变量可能损失精度(例如twoThirds
),或者溢出(例如millisInYear
)。
二、集合
1.Use isEmpty() to check whether the collection is empty or not
使用 isEmpty()
方法来判断集合是否为空,而不是使用其他的方法。
//错误的代码示范
if (myCollection.size() == 0) { // Noncompliant
/* ... */
}
//正确的代码示范
if (myCollection.isEmpty()) {
/* ... */
}
三、异常
1. “throws” declarations should not be superfluous
不要多余地抛异常。
2. 不要捕获范围过大的异常
不要捕获范围过大的异常类,比如 Exception、Throwable、Error 或 RuntimeException,除非是级别非常高的程序或线程。
//以下代码使用了同一方式来处理三种不同的异常类型。
try {
doExchange();
}catch (IOException e) {
logger.error("doExchange failed", e);
}catch (InvocationTargetException e) {
logger.error("doExchange failed", e);
}catch (SQLException e) {
logger.error("doExchange failed", e);
}
//我们也可以使用一个单独的 catch 块来处理这三种异常,如下所示:
try {
doExchange();
}catch (Exception e) {
logger.error("doExchange failed", e);
}
但是如果修改 doExchange(),以抛出需要以某种不同的方式处理的新异常类型,则范围过大的 catch 块会阻止编译器指出这一情况(有新的异常抛出)。此外,新 catch 块也将处理那些来自于 RuntimeException 的异常,比如 ClassCastException 和 NullPointerException,而这些异常的发生是不在程序员的计划之内的。
四、其他
1. 没有使用的导包应该被删除
2. The diamond operator ("<>") should be used
请使用菱形语法。
//错误的代码示范
List<String> strings = new ArrayList<String>(); // Noncompliant
Map<String,List<Integer>> map = new HashMap<String,List<Integer>>(); // Noncompliant
//正确的代码示范
List<String> strings = new ArrayList<>();
Map<String,List<Integer>> map = new HashMap<>();
3. 不要使用硬编码文件分隔符File Separator
使用硬编码文件分隔符会导致可移植性问题。 不同的操作系统使用不同的字符作为文件分隔符。例如,Microsoft Windows 系统使用“\”,而 UNIX 系统则使用“/”。应用程序需要在不同的平台上运行时,使用硬编码文件分隔符会导致应用程序逻辑执行错误,并有可能导致 denial of service。
//错误的代码示范
File file = new File(directoryName + "\\" + fileName);
//正确的代码示范
File file = new File(directoryName + File.separator + fileName);
4. 将不受信任的数据附加到使用默认支持数组大小进行初始化的 StringBuilder 实例会导致 JVM 过度使用堆内存空间。
将用户控制的数据附加到使用默认支持字符数组大小 (16) 进行初始化的 StringBuilder 实例,会导致应用程序在调整基础数组的大小以适应用户数据时占用大量堆内存。每次新数据附加到 StringBuilder 实例时,它都会尝试使数据适应其支持字符数组。如果数据不合适,将会创建新的数组,大小为之前的两倍,而旧数组在进行回收之前,将继续留在堆中。此缺陷可被攻击者用于执行拒绝服务 (DoS) 攻击。
//错误的代码示范
StringBuilder sb = new StringBuilder();
sb.append(request.getParameter("foo"));
//正确的代码示范
private final int MAX_DATA = 128;
private final int EXPECTED_BUFFER_DATA = 1024;
StringBuilder sb = new StringBuilder(EXPECTED_BUFFER_DATA);
String data = request.getParameter("foo");
if (data.length() < MAX_DATA) {
sb.append(data);
}
5. 不要使用 System.out
或 System.err
使用 System.out 或 System.err 而不是专门的日志记录工具,会导致难以监控程序的运行状况
6. Access Control: Database(数据越权)
参考文章: https://www.cnblogs.com/meInfo/p/9004667.html
说一下我对这个问题的理解:SQL查询要考虑到数据的归属权问题,不能单单用主键来做查询条件,需要根据账户角色的不同来限制数据的访问。(特别是在自增主键的情况下,攻击者可以根据后台url使用轮询的方式扫描主键,从而获取信息。)