公司今年有个很大的任务,就是完成所有工程的静态代码清理。在搭建好 SonarQube 平台后,每个人都有一块责任田,各自负责静态代码清理。此文便是记录一下所处理的清理工作,后续开发工作应当避免这些问题。
修饰符排序
示例:
1 | final static String WVJB_OVERRIDE_SCHEMA = "sp://"; |
SonarQube 提示:
1 | Reorder the modifiers to comply with the Java Language Specification. |
即调整修饰符顺序以遵循Java语言规范。应修改为:
1 | static final String WVJB_OVERRIDE_SCHEMA = "sp://"; |
常见的修饰符推荐顺序为:
- 访问控制符( public / protected / private )
- 静态修饰符( static )
- 最终修饰符( final )
- 抽象修饰符( abstract )
- 同步修饰符( synchronized )等
静态类构造函数
示例:
1 | public class BridgeUtil { |
SonarQube 提示:
1 | Add a private constructor to hide the implicit public one. |
即添加私有构造方法以隐藏默认的公共构造方法。应修改为:
1 | public class BridgeUtil { |
工具类仅包含静态方法和常量,无需实例化,应该添加私有构造方法,以防止外部实例化。
自动资源管理
示例:
1 | public static String assetFile2Str(Context c, String urlStr) { |
SonarQube 提示:
1 | Change this "try" to a try-with-resources. (sonar.java.source not set. Assuming 7 or greater.) |
即将此普通 try 语句转换为带资源的 try 语句。应修改为:
1 | public static String assetFile2Str(Context c, String urlStr) { |
将传统的 try-catch-finally 资源管理方式,替换为 Java 7+ 引入的 try-with-resources 语法,以自动关闭资源并简化代码。
未使用的属性
示例:
1 | private final String TAG = "BridgeWebView"; |
SonarQube 提示:
1 | Remove this unused "TAG" private field. |
即删除未使用的属性。应直接删掉。
命名
还是用上面的示例:
1 | private final String TAG = "BridgeWebView"; |
假设需要保留 TAG 使用, SonarQube 提示:
1 | Rename this field "TAG" to match the regular expression '^[a-z][a-zA-Z0-9]*$'. |
即命名不规范,应该改为小写驼峰形式。
菱形运算符
示例:
1 | Map<String, CallBackFunction> responseCallbacks = new HashMap<String, CallBackFunction>(); |
SonarQube 提示:
1 | Replace the type specification in this constructor call with the diamond operator ("<>"). (sonar.java.source not set. Assuming 7 or greater.) |
即将此构造方法调用中的类型声明替换为菱形运算符("<>")。应修改为:
1 | Map<String, CallBackFunction> responseCallbacks = new HashMap<>(); |
注释代码块
示例:
1 | private void init() { |
SonarQube 提示:
1 | This block of commented-out lines of code should be removed. |
即应移除这段被注释掉的代码块。应直接删掉。
空判断
示例:
1 | if (list.size() == 0) { |
SonarQube 提示:
1 | Use isEmpty() to check whether the collection is empty or not. |
即使用 isEmpty() 方法检查集合是否为空。应修改为:
1 | if (list.isEmpty()) { |
方法复杂度
示例:
1 | void flushMessageQueue() { |
SonarQube 提示:
1 | Refactor this method to reduce its Cognitive Complexity from 48 to the 15 allowed. |
即重构此方法以减少其认知复杂度从 48 到 15 允许的最大值。可以修改为:
1 | void flushMessageQueue() { |
空方法
示例:
1 | open fun initPageConfig(pageConfig: FragmentPageConfig) { |
SonarQube 提示:
1 | Add a nested comment explaining why this function is empty or complete the implementation. |
即添加注释说明为什么此函数为空或完成实现。可以增加相应注释:
1 | open fun initPageConfig(pageConfig: FragmentPageConfig) { |
空代码块
示例:
1 | private get() { |
SonarQube 提示:
1 | Either remove or fill this block of code. |
即删除或填充此代码块。可以修改为:
1 | private get() { |
TODO
示例:
1 | var AMIGO = "amigo" // 金立 // todo |
SonarQube 提示:
1 | Complete the task associated to this TODO comment. |
即完成此 TODO 注释关联的任务。如有需要完成的任务,需要完善代码。如果已经完成,或不需要了,则直接删除。
正则优化
示例:
1 | public ROMInfo checkBuildProp(RomProperties properties) throws Exception { |
SonarQube 提示:
1 | Refactor this repetition that can lead to a stack overflow for large inputs. |
即重构此重复代码,以避免栈输入过大时的溢出问题。因为代码中只用到了 group(1),所以可以把正则表达式修改为:
1 | "[Vv]?(\\d+(?:\\.\\d+)*)[.A-Za-z]*" |
正则表达式引擎在处理重复结构时,会使用栈来跟踪匹配状态:
- 原始正则的 (\.\d+)* 会为每个匹配的子组创建栈帧
- 当输入超长时(如包含上百个版本号段),栈内存会被耗尽
- 非捕获组 (?:\.\d+)* 不会创建额外栈帧,大幅减少内存消耗
未使用的参数
示例:
1 | private fun doGetRomType(context: Context): ROM { |
SonarQube 提示:
1 | Remove this unused function parameter "context". |
即删除未使用的函数参数 "context"。参数未使用应直接删掉。
if 语句合并
示例:
1 | if (checker.checkManufacturer(manufacturer)) { |
SonarQube 提示:
1 | Merge this "if" statement with the nested one. |
即将此 if 语句与嵌套的 if 语句合并。应修改为:
1 | if (checker.checkManufacturer(manufacturer) && checker.checkRom()) { |
方法参数过长
示例:
1 | private fun loadNotificationImage( |
SonarQube 提示:
1 | This function has 9 parameters, which is greater than the 7 authorized. |
即此函数有 9 个参数,超过 7 个参数的授权。应将参数抽取,可以修改为:
1 | data class NotificationImageConfig( |
修改方法签名一定要注意调用方。
Deprecated
示例:
1 |
|
SonarQube 提示:
1 | Do not forget to remove this deprecated code someday. |
即此代码已废弃,应在将来移除。需要仔细检查,确认是否有其他地方使用了此代码。若最终确认没有使用,即可删除。
另还有一种场景:
1 | open operator fun <T : ShareViewModel?> get(key: String, modelClass: Class<T>): T { |
modelClass.newInstance() 会有提示:
1 | Deprecated code should not be used. |
此场景需要寻找替代方法进行调用,不再调用已经标记为废弃的方法。
重复代码
示例:
1 | when (info.downloadStatus) { |
SonarQube 提示:
1 | This branch's code block is the same as the block for the branch on line 52. |
即此分支的代码与第 52 行的代码相同。应修改为:
1 | when (info.downloadStatus) { |
枚举类重复字符串
示例:
1 | public enum CloudNetErrorCode { |
SonarQube 提示:
1 | Define a constant instead of duplicating this literal "Exceeded the number of applications" 3 times. |
即字符串 "Exceeded the number of applications" 被重复写了 3 次,应定义一个常量来代替。应修改为:
1 | public enum CloudNetErrorCode { |
注意,枚举类比较特殊,若只是定义 public static final String 变量,也会报错:
1 | Cannot read value of field 'MSG_EXCEEDED_APPLICATIONS' before the field's definition |
所以需要提取到 Const 静态类中。
(持续更新…)