Sonar规范扫描Java代码暴露的问题
字符串和封装类型应使用 equals()
进行比较
例如java.lang.Integer
使用引用等于==
或!=
,因为它不是比较实际值,而是比较内存中的位置。
String firstName = getFirstName(); // String overrides equals
String lastName = getLastName();
if (firstName == lastName) { ... }; // 即使字符串具有相同的值,也为false
方法参数,捕获的异常和foreach变量的初始值不应忽略
public void doTheThing(String str, int i, List<String> strings) {
// str = Integer.toString(i); // 不符合规定
String str1 = str //在使用之前需要保存初始值
for (String s : strings) {
s = "hello world"; // Noncompliant
}
}
"InterruptedException" should not be ignored
在代码中不应该忽略中断异常,只在日志中打印异常日志,就像“忽略”一样。抛出中断异常会清除线程的中断状态,因此如果异常处理不当,那么线程被中断的信息将会丢失。相反,中断应该被重新抛出——立即或者在清理方法的状态之后——或者应该通过调用Thread.interrupt()来重新中断线程,即使这是单线程的应用程序。任何其他的操作过程都有延迟线程关闭的风险,并且丢失了线程被中断的信息——线程很可能没有完成它的任务。
类似地,也应该传播ThreadDeath异常。根据它的JavaDoc:
如果ThreadDeath异常被一个方法捕获,那么它被重新抛出是很重要的,这样线程就会结束。
不符合要求的代码如下:
public void run () {
try {
while (true) {
// do stuff
}
}catch (InterruptedException e) { // Noncompliant; logging is not enough
LOGGER.log(Level.WARN, "Interrupted!", e); // catch块中只是打印了异常日志,相当于忽略了这个异常。
}
}
解决方案
//Compliant Solution
public void run () {
try {
while (true) {
// do stuff
}
}catch (InterruptedException e) {
LOGGER.log(Level.WARN, "Interrupted!", e);
// 恢复中断状态
Thread.currentThread().interrupt();
}
}
枚举字段不应有public修饰的setter方法
enum
通常被视为常量,但是enum
带有public
字段或public
的setter方法的不仅是非常量的,而且还容易受到恶意代码的攻击。理想情况下,枚举字段应该用private
修饰或者在构造器中赋值,但如果不可能,则应尽可能降低其可见性
反例
public enum Continent {
NORTH_AMERICA (23, 24709000),
// ...
EUROPE (50, 39310000);
public int countryCount; // 不合理
private int landMass;
Continent(int countryCount, int landMass) {
// ...
}
public void setLandMass(int landMass) { // 不合理
this.landMass = landMass;
}
规范写法
public enum Continent {
NORTH_AMERICA (23, 24709000),
// ...
EUROPE (50, 39310000);
private int countryCount;
private int landMass;
public Continent(int countryCount, int landMass) {
// ...
}
void setCountryCount(int countryCount){
this.countryCount = countryCount;
}
public getCountryCount(){
return countryCount;
}