sonar常見缺陷和修改

1. Resources should be closed

IO資源應該在使用後關閉。在try語句中使用了Connections, streams, files等,這些類實現了Closeable 或者AutoCloseable接口,必須在finally塊中關閉,否則,如果出現異常就可能無法關閉。對於實現了AutoCloseable接口的類,最好使用“try-with-resource”語句來自動關閉。如果不能正確地關閉資源,就會導致資源泄漏,這可能會導致應用程序甚至整個系統的崩潰。

關於IO資源的處理問題,以下比較三種解決方案。

  • close()放在try塊中
  • close()放在finally塊中
  • 使用try-with-resource語句

close()放在try塊中

//close() is in try clause
try {
    PrintWriter out = new PrintWriter(
            new BufferedWriter(
            new FileWriter("out.txt", true)));
    out.println("the text");
    out.close();
} catch (IOException e) {
    e.printStackTrace();
}

這種方式容易造成IO資源的泄露,因爲對於IO資源來說不管操作的結果如何都必須關閉。

close()放在finally塊中

//close() is in finally clause
PrintWriter out = null;
try {
    out = new PrintWriter(
        new BufferedWriter(
        new FileWriter("out.txt", true)));
    out.println("the text");
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (out != null) {
        out.close();
    }

這種方式在JDK1.7之前,推薦使用這種方式,但是,這種方式還是有問題,因爲,在try塊和finally塊中可能都會發生Exception。

使用try-with-resource語句

//try-with-resource statement
try (PrintWriter out2 = new PrintWriter(
            new BufferedWriter(
            new FileWriter("out.txt", true)))) {
    out2.println("the text");
} catch (IOException e) {
    e.printStackTrace();
}

這種方式可能是最好的,Java官方推薦使用這種方式,但是,使用的前提是你的jdk版本在1.7以上。

因爲不管什麼情況下(異常或者非異常)資源都必須關閉,在jdk1.6之前,應該把close()放在finally塊中,以確保資源的正確釋放。

如果使用jdk1.7以上的版本,推薦使用try-with-resources語句。


2. "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塊中只是打印了異常日誌,相當於忽略了這個異常。

處理建議爲拋出異常:

public void run () {
  try {
    while (true) {
      // do stuff
    }
  }catch (InterruptedException e) {
    LOGGER.log(Level.WARN, "Interrupted!", e);
    // Restore interrupted state...
    Thread.currentThread().interrupt();
  }
}

catch塊中記錄中斷狀態之後將線程中斷,正確的處理了中斷異常。

3.Null pointers should not be dereferenced/accessed.

對值爲null的指針調用任何方法,就會引發空指針異常(java.lang.NullPointerException)。在最好的情況下,這樣的異常會導致程序終止。在最壞的情況下,它可能暴露出對攻擊者有用的調試信息,或者它可能允許攻擊者繞過安全措施。

以下爲不符合要求的代碼舉例:

public boolean isNameEmpty() {
  return getName().length() == 0; // Noncompliant; the result of getName() could be null, but isn't null-checked
}
 
Connection conn = null;
Statement stmt = null;
try{
  conn = DriverManager.getConnection(DB_URL,USER,PASS);
  stmt = conn.createStatement();
  // ...
 
}catch(Exception e){
  e.printStackTrace();
}finally{
  stmt.close();   // Noncompliant; stmt could be null if an exception was thrown in the try{} block
  conn.close();  // Noncompliant; conn could be null if an exception was thrown
}
 
private void merge(@Nonnull Color firstColor, @Nonnull Color secondColor){...}
 
public  void append(@CheckForNull Color color) {
    merge(currentColor, color);  // Noncompliant; color should be null-checked because merge(...) doesn't accept nullable parameters
}
 
void paint(Color color) {
  if(color == null) {
    System.out.println("Unable to apply color " + color.toString());  // Noncompliant; NullPointerException will be thrown
    return;
  }
  ...
}

4.Non-thread-safe fields should not be static

並不是標準Java庫中的所有類都爲線程安全的。多線程時,有些類很可能會在運行時引起數據問題或異常。

在Calendar,DateFormat,javax.xml.xpath.XPath或 javax.xml.validation.SchemaFactory生成靜態的實例時會出問題。

缺陷舉例:

public class MyClass {
  static private SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");  // Noncompliant
  static private Calendar calendar = Calendar.getInstance();  // Noncompliant
解決建議:
public class MyClass {
  private SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");
  private Calendar calendar = Calendar.getInstance();


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章