SonarQube 簡介
Sonar 是一個用於代碼質量管理的開放平台。通過插件機制,Sonar 可以集成不同的測試工具,代碼分析工具,以及持續集成工具。
與持續集成工具(例如 Hudson/Jenkins 等)不同,Sonar 並不是簡單地把不同的代碼檢查工具結果(例如 FindBugs,PMD 等)直接顯示在 Web 頁面上,而是通過不同的插件對這些結果進行再加工處理,通過量化的方式度量代碼質量的變化,從而可以方便地對不同規模和種類的工程進行代碼質量管理。
在對其他工具的支持方面,Sonar 不僅提供了對 IDE 的支持,可以在 Eclipse 和 IntelliJ IDEA 這些工具里聯機查看結果;同時 Sonar 還對大量的持續集成工具提供了接口支持,可以很方便地在持續集成中使用 Sonar。
此外,Sonar 的插件還可以對 Java 以外的其他編程語言提供支持,對國際化以及報告文檔化也有良好的支持
1."@RequestMapping" 方法應為“ public”
將調用具有@Controller注釋的類的@RequestMapping注釋部分的方法(直接或間接通過元注釋-Spring Boot的@RestController是一個很好的示例)來處理匹配的Web請求。即使該方法是私有的,也會發生這種情況,因為Spring會通過反射調用此類方法,而不檢查可見性。
因此,將敏感方法標記為私有似乎是控制如何調用此類代碼的好方法。不幸的是,並非所有的Spring框架都以這種方式忽略可見性。例如,如果您試圖通過將其標記為@Secured來控制對敏感,私有@RequestMapping方法的Web訪問,則無論用戶是否被授權訪問它,它仍將被調用。這是因為AOP代理不適用於非公開方法。
除了@RequestMapping之外,此規則還考慮了Spring Framework 4.3中引入的注釋:@ GetMapping,@ PostMapping,@ PutMapping,@ DeleteMapping,@ PatchMapping。
2.默認軟件包中不應使用“ @SpringBootApplication”和“ @ComponentScan”
@ComponentScan用於確定哪些Spring Bean在應用程序上下文中可用。可以使用basePackageClasses或basePackages(或其別名值)參數來配置要掃描的軟件包。如果未配置任何參數,則@ComponentScan將僅考慮帶有注釋的類的程序包。在屬於默認包的類上使用@ComponentScan時,將掃描整個類路徑。
這將減慢應用程序的啟動速度,並且該應用程序可能無法啟動BeanDefinitionStoreException,因為您最終掃描了Spring Framework軟件包本身。
在以下情況下,此規則會引起問題:
@ ComponentScan,@ SpringBootApplication和@ServletComponentScan用於默認包的類
@ComponentScan已使用默認程序包顯式配置
不兼容代碼示例
兼容解決方案
3.不應使用雙重檢查鎖定
雙重檢查鎖定是在輸入同步塊之前和之后檢查延遲初始化對象的狀態,以確定是否初始化該對象。
如果不對float或int以外的任何可變實例進行額外同步,則無法以獨立於平台的方式可靠地工作。使用延遲初始化的雙重檢查鎖定任何其他類型的原始或可變對象風險第二個線程使用未初始化或部分初始化成員第一個線程仍然是創建它時,程序崩潰。
有多種解決方法。最簡單的方法是根本不使用雙重檢查鎖定,而是同步整個方法。對於早期版本的JVM,出於性能原因,通常建議不要同步整個方法。但是,在新的JVM中,同步性能已大大提高,因此,現在這是首選的解決方案。如果您希望完全避免使用同步,則可以使用內部靜態類來保存引用。內部靜態類保證延遲加載。
不兼容代碼示例
兼容解決方案
4.資源應該關閉
在使用后,需要關閉實現Closeable接口或其超級接口AutoCloseable的連接,流,文件和其他類。此外,必須在finally塊中進行關閉調用,否則異常可能使調用無法進行。最好在類實現AutoCloseable時,應使用“ try-with-resources”模式創建資源並將其自動關閉。
無法正確關閉資源將導致資源泄漏,這可能首先導致應用程序崩潰,然后可能使應用程序崩潰。
不兼容代碼示例
兼容解決方案
Java 7引入了try-with-resources語句,該語句隱式關閉Closeables。在try-with-resources語句中打開的所有資源都被該規則忽略。
4.“Random”對象應重復使用
每次需要一個隨機值時,創建一個新的Random對象都是效率低下的,並且可能生成取決於JDK的非隨機數。為了獲得更好的效率和隨機性,請創建一個隨機數,然后存儲並重新使用它。
Random()構造函數每次嘗試為種子設置一個不同的值。但是,不能保證種子將是隨機的,甚至是均勻分布的。一些JDK將當前時間用作種子,這使得生成的數字根本不是隨機的。
該規則查找每次調用方法並將其分配給局部隨機變量時都會創建新的Random的情況。
不兼容代碼示例
兼容解決方案
5.不再使用時應清除“ ThreadLocal”變量
一旦保持線程不再存在,就應該對ThreadLocal變量進行垃圾回收。當重新使用保持線程時,可能會發生內存泄漏,在使用線程池的應用程序服務器上就是這種情況。
為避免此類問題,建議始終使用remove()方法清除ThreadLocal變量,以刪除ThreadLocal變量的當前線程值。
另外,調用set(null)刪除值可能會在映射中保留對該指針的引用,這在某些情況下可能導致內存泄漏。使用remove可以更安全地避免此問題。
不兼容代碼示例
兼容解決方案
6.字符串和包裝類型應使用“equals()"進行比較
使用引用相等==或!=比較java.lang.String或包裝類型(如java.lang.Integer)的兩個實例幾乎總是一個錯誤,因為它不是在比較實際值,而是在內存中的位置。
不兼容代碼示例
兼容解決方案
在Java 中包裝類型與基本數據類型存儲位置不同。
Java 基本數據類型存放位置
-
方法參數、局部變量存放在棧內存中的棧楨中的局部變量表
-
常量存放在常量池中
包裝類型如Integer存放位置
-
常量池
-
堆內存
Integer 存儲在常量池中時可以使用==對比,但當在堆內存中時,使用==對比,實際對比的是兩個內存地址而非值。
根據Integer源碼,
可以看出數值在-128-127時,會使用cache中的數據,其實也就是常量池。超過范圍后新創建Integer,此時數據就無法使用==。
本項規則,主要就是為了避免對比內存地址而引發的錯誤判斷。
7.“ compareTo”不應重載
在實現Comparable.compareTo方法時,參數的類型必須與Comparable聲明中使用的類型匹配。當使用其他類型時,這將創建一個重載而不是一個重寫,這不太可能成為意圖。
當實現Comparable的類的compareTo方法的參數與Comparable聲明中使用的參數不同時,此規則會引起問題。
不兼容代碼示例
兼容解決方案
8.周年("YYYY")不應用於日期格式
當使用SimpleDateFormat格式化和解析日期時,很少有開發人員會意識到“周年”的Y和“年”的y之間的區別。這很可能是因為對於大多數日期而言,“周年”和“年”是相同的,因此在除該年的第一周或最后一周之外的任何時間進行測試,都會得到y和Y相同的值。但是在12月的最后一周和 一月的第一周,您可能會得到意想不到的結果。
不兼容代碼示例
兼容解決方案
異常
9.裝箱和拆箱不應連續操作
裝箱是將原始值放入類似對象的過程,例如創建一個Integer來保存一個int值。拆箱是從此類對象中檢索原始值的過程。
由於在裝箱和拆箱期間原始值保持不變,因此在不需要時進行任何操作都是沒有意義的。這也適用於自動裝箱和自動拆箱(當Java為您隱式處理原始/對象轉換時)。
不兼容代碼示例
兼容解決方案
10.Boxed "Boolean" should be avoided in boolean expressions
在布爾表達式中應避免使用裝箱的“布爾”
如果將裝箱的類型java.lang.Boolean用作表達式,則如Java語言規范§5.1.8取消裝箱轉換中所定義的,如果該值為null,則它將拋出NullPointerException。
完全避免這種轉換並顯式處理null值是更安全的。
不兼容代碼示例
兼容解決方案
微信公眾號