关于kotlin
kotlin作为一个JVM语言,它在高度兼容Java代码的前提之下,对Java语言进行了极大的简化和升级,在保留了面向对象的编程语言的优势前提下,拔高语言中函数的地位并拓展函数的能力,为开发者提供了函数式的编程框架,各种函数用法使kotlin代码极其简洁,甚至乍一看已经和Java完全不同了,,以上种种保证它可以不影响现有代码的前提下,提高后续的代码开发效率。因此kotlin这几年在迅速普及,据我所知,大量的前后端开发团队都已经在使用kotlin了。
既然kotlin大家都在用,那么我们如何写好kotlin代码呢?最佳选择当然是参考官方教程或者官方代码规范指导等等文档来写。比如作为Android开发的推荐编程语言,Android官方提出了一些代码规范:Kotlin代码风格指导,而kotlin自己的官方语言教程里面其实也有各种各样的代码规范。
也就是说,想要自己写出更规范和健壮(稳定)的kotlin代码,就需要熟悉所有相关的规则规范和kotlin一些语言教程的文档
这好像是一句正确的废话...
image
当然,熟读完并且记住所有的规则规范然后写代码的时候不出错,显然有些强人所难了,因此,我们需要一个插件来记住所有的代码规则规范,然后扫描我们的代码,然后帮助我们分析自己的kotlin代码。
kotlin编码规范最全的还是 ktlint,ktlint项目不仅参考了Android官方的Kotlin style guide,而且还有kotlin官方的编码规范等等。因此ktlint是一个不错的选择。
但是,一段好的代码不仅仅是代码格式的规范,代码本身应该具备稳定性,即代码运行没有性能或崩溃隐患,所以代码分析插件最好能指出哪些代码片段会影响代码稳定性,而ktlint主要能力还是检查编码规范,无法扫描kotlin代码中的性能问题和隐患代码,因此不算完美。
好了,不卖关子了,介绍下detekt。目前来讲,它相对更全面的Kotlin代码分析插件。
detekt是一款kotlin静态代码分析工具,它可以检查kotlin的编码规范,也能检查代码的性能开销和隐患,而且,你可以自定义自己的代码分析规则体系,这样,你就不必全盘接受代码所有代码规范,可以去掉那些无关紧要的规则检查,让开发相对灵活一些。
detekt使用简介
安装
参考官网,其实安装使用的方式有很多种,这里介绍一种。
- 单独gradle文件集成
以下配置写在一个单独的gradle文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | repositories { // if you 'gradle install' all detekt modules mavenLocal() // or when all modules should be provided maven { url "http://dl.bintray.com/arturbosch/code-analysis" } } configurations { detekt } task detekt(type: JavaExec) { main = "io.gitlab.arturbosch.detekt.cli.Main" classpath = configurations.detekt def input = "$project.projectDir.absolutePath" // detekt.yml就是我们可自定义的代码分析规则的配置文档,后面会讲 def config = "$project.projectDir/detekt.yml" def filters = ".*test.*" ... ... // 输出结果的文件,可选html,xml,或txt等其他格式 def output = "$project.projectDir/reports/detekt/detekt-report.html" def outputXml = "$project.projectDir/reports/detekt/detekt-report.xml" def params = [ '-p', input, '-c', config, '-f', filters, '-r', "html:$output",'-r', "xml:$outputXml"] args(params) } dependencies { detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.0.0.[CURRENT_MILESTONE]' detekt 'io.gitlab.arturbosch.detekt:detekt-formatting:1.0.0.[CURRENT_MILESTONE]' } |
然后命令行运行gradle detekt即可,默认输出文件在build文件夹下,当然我们也可以自己配置输出目录地址。
代码分析规则
上面提到的输入文件detekt.yml就是detekt分析kotlin代码的分析规则依据,我们可以自定义编写规则,detekt可以定义的规则类型分为9类
- comments 注释文档规范检查
- complexity 复杂度检查
- empty-blocks 空block检查
- exceptions 表达式规范检查
- formatting 格式规范检查
- naming 命名规范检查
- performance 性能检查
- potential-bugs 潜在bug检查
- style 代码风格检查
举个例子,以下是糗百项目中使用的部分规则配置(其实主要是根据默认配置文件来选择自己需要的规则配置)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | test-pattern: # Configure exclusions for test sources active: true patterns: # Test file regexes - '.*/test/.*' - '.*/androidTest/.*' - '.*Test.kt' - '.*Spec.kt' - '.*Spek.kt' exclude-rule-sets: - 'comments' exclude-rules: - 'NamingRules' - 'WildcardImport' - 'MagicNumber' - 'MaxLineLength' - 'LateinitUsage' build: maxIssues: 1 # 发现超过多少个问题时,task返回结果失败 weights: #比重 # complexity: 2 # LongParameterList: 1 # style: 1 # comments: 1 comments: active: false // 是否激活该规则 CommentOverPrivateFunction: active: false CommentOverPrivateProperty: active: false EndOfSentenceFormat: active: false endOfSentenceFormat: ([.?!][ f<])|([.?!]$) UndocumentedPublicClass: active: false searchInNestedClass: true searchInInnerClass: true searchInInnerObject: true searchInInnerInterface: true UndocumentedPublicFunction: active: false complexity: active: true ComplexCondition: #条件是否过于复杂 active: true threshold: 4 临界值 ComplexInterface: active: false threshold: 10 includeStaticDeclarations: false ComplexMethod: #方法复杂难懂 active: false threshold: 10 ignoreSingleWhenExpression: false ignoreSimpleWhenEntries: false NestedBlockDepth: # 嵌套深度检查 active: true threshold: 4 #阈值 StringLiteralDuplication: active: false threshold: 3 ignoreAnnotation: true excludeStringsWithLessThan5Characters: true ignoreStringsRegex: '$^' TooManyFunctions: # 单个文件/对象内部的方法数限定,功能单一原则 active: false thresholdInFiles: 11 thresholdInClasses: 11 thresholdInInterfaces: 11 thresholdInObjects: 11 thresholdInEnums: 11 ignoreDeprecated: false ignorePrivate: false ignoreOverridden: false empty-blocks: active: true EmptyCatchBlock: active: true allowedExceptionNameRegex: "^(_|(ignore|expected).*)" EmptyClassBlock: # 空的class,不需要{} active: true exceptions: active: true ExceptionRaisedInUnexpectedLocation: active: false methodNames: 'toString,hashCode,equals,finalize' ThrowingNewInstanceOfSameException: active: false TooGenericExceptionCaught: #异常捕获范围太广 active: false exceptionNames: - ArrayIndexOutOfBoundsException - Error - Exception - IllegalMonitorStateException - NullPointerException - IndexOutOfBoundsException - RuntimeException - Throwable allowedExceptionNameRegex: "^(_|(ignore|expected).*)" formatting: active: true android: false autoCorrect: true MaximumLineLength: # 单行最长的长度,暂时不启用检查 active: false maxLineLength: 120 ModifierOrdering: # 修饰符一致性 active: true autoCorrect: true NoBlankLineBeforeRbrace: active: false autoCorrect: true NoConsecutiveBlankLines: # 没有连续的空行 active: true autoCorrect: true NoWildcardImports: # 没有通配符的倒导入 active: true autoCorrect: true # PackageName: # active: true # autoCorrect: true ParameterListWrapping: active: true autoCorrect: true indentSize: 4 naming: active: true ClassNaming: # class name 首字母大写 active: true classPattern: '[A-Z$][a-zA-Z0-9$]*' FunctionMinLength: active: false minimumFunctionNameLength: 3 FunctionNaming: #fun命名规则 active: true functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' excludeClassPattern: '$^' ignoreOverridden: true FunctionParameterNaming: #fun param 命名规则 驼峰 active: true parameterPattern: '[a-z][A-Za-z0-9]*' excludeClassPattern: '$^' ignoreOverriddenFunctions: true MatchingDeclarationName: # kt文件中,只有一个类的情况下,最好保持类名文件名一致,一个文件多个类的情况下,选择能描述这些类的文件名称 active: true MemberNameEqualsClassName: # 成员名和类名混淆,暂时不起用 active: false ignoreOverriddenFunction: true ObjectPropertyNaming: # 对象属性命名规则 active: true constantPattern: '[A-Za-z][_A-Za-z0-9]*' propertyPattern: '[A-Za-z][_A-Za-z0-9]*' privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' VariableNaming: active: true variablePattern: '[a-z][A-Za-z0-9]*' privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' excludeClassPattern: '$^' ignoreOverridden: true performance: active: true ArrayPrimitive: # 数组类型避免开装箱开销 active: true ForEachOnRange: # ForEach循环代码的检查 active: true SpreadOperator: active: false UnnecessaryTemporaryInstantiation: #类型转化的性能检查 active: true potential-bugs: active: true ExplicitGarbageCollectionCall: # 垃圾回收的代码检查 active: true InvalidRange: #非法的range active: false IteratorHasNextCallsNextMethod: #迭代器代码检查 active: true IteratorNotThrowingNoSuchElementException: # 迭代器实现规范 active: false MissingWhenCase: #when的case条件不全 active: true LateinitUsage: active: true excludeAnnotatedProperties: "" ignoreOnClassesPattern: "" UnsafeCallOnNullableType: # 不安全的空指针判断 active: true UnsafeCast: #不安全的类型转换 active: true UselessPostfixExpression: # 无用的后缀表达式 active: true |
以上这些定制规则,只是截取的一部分,大家使用detekt时,可以根据自己的需要来选择。
规则文档
输出结果
当你在命令行运行gradlew detekt之后,代码检查的结果会出现在你之前配置的路径下,比如build目录下:
image
输出的代码检查报告有不同的格式:xml,html,txt等,本质上是对代码检查结果的不同组织形式。
一下时html格式在浏览器中打开的样子如下:
image
这样,你就很方便的看到项目中所有kotlin代码的问题了,根据它的提示一一改正之后,重新运行代码分析插件直到不再有错误即可。