Error-prone,Google出品的Java和Android Bug分析利器

vsgdk5557 8年前
   <h2>是什么</h2>    <ul>     <li>静态的Java和Android bug分析利器</li>     <li>由Google出品</li>     <li>由error-prone接管compiler,在代码编译时进行检查,并抛出错误中断执行</li>     <li>在抛出错误的同时给出具体的原因和相应方案</li>     <li>error-prone github 地址为 <a href="/misc/goto?guid=4959646057977272031" rel="nofollow,noindex">https://github.com/google/error-prone</a></li>    </ul>    <h2>举几个例子</h2>    <pre>  <code class="language-java">private void testCollectionIncompatibleType() {      Set<Short> set = new HashSet<>();      set.add(Short.valueOf("1"));      set.remove(0);  }  </code></pre>    <p>上面的代码中</p>    <ul>     <li>set是一个接受Short类型的集合</li>     <li>我们想通过类似从List.remove(index)方式删除一个元素</li>     <li>但是Set没有remove(index)方法,有的只是remove(Object)方法,普通编译器不会报错,而error-prone则会发现</li>    </ul>    <p>报出的错误信息为</p>    <pre>  <code class="language-java">/Users/jishuxiaoheiwu/github/ErrorProneSample/app/src/main/java/com/example/jishuxiaoheiwu/errorpronesample/MainActivity.java:24:  error: [CollectionIncompatibleType] Argument '0' should not be passed to this method; its type int is not compatible with its collection's type argument Short          set.remove(0);                    ^      (see http://errorprone.info/bugpattern/CollectionIncompatibleType)  </code></pre>    <p>再举一个例子</p>    <pre>  <code class="language-java">"hello World".getBytes().toString();  </code></pre>    <p>报出的错误是</p>    <pre>  <code class="language-java">/Users/jishuxiaoheiwu/github/ErrorProneSample/app/src/main/java/com/example/jishuxiaoheiwu/errorpronesample/MainActivity.java:16:  error: [ArrayToString] Calling toString on an array does not provide useful information          "hello World".getBytes().toString();                                           ^      (see http://errorprone.info/bugpattern/ArrayToString)  </code></pre>    <p>提示上面的byte[].toString()方法打印没有有用信息。</p>    <h2>BugPattern</h2>    <p>Error-prone是基于BugPattern来发现问题的,覆盖范围不仅限于Java还包含Android代码。一些比较常见的BugPattern有如下这些</p>    <ul>     <li>ArrayToString 直接调用数组的toString方法打印不出有用信息</li>     <li>DivZero 0不能做除数,即分母</li>     <li>DefaultCharset 调用系统默认的Charset</li>     <li>MissingDefault switch中缺少default</li>     <li>MislabeledAndroidString Android中的字符串命名和内容不匹配,具有误导性</li>     <li>HardCodedSdCardPath 硬编码sd卡路径</li>     <li>IsLoggableTagLength log tag字符数量过长</li>     <li>其他</li>     <li>更多的bug pattern请参考 <a href="/misc/goto?guid=4959747035377412390" rel="nofollow,noindex">bugpatterns</a></li>    </ul>    <p>BugPattern有三种严重程度,如下</p>    <ul>     <li>ERROR</li>     <li>WARNING</li>     <li>SUGGESTION</li>    </ul>    <p>只有ERROR的严重程度才会中断当前的编译,其他情况都会以日志输出形式展现。</p>    <h2>如何配置</h2>    <p>error-prone有对应的gradle插件,只需要应用即可。需要的操作很简单,只需要三步</p>    <ul>     <li>增加相应的maven repo</li>     <li>在依赖中设置error-prone plugin classpath</li>     <li>应用error-prone plugin</li>    </ul>    <p>一个完整的代码示例如下,修改的文件为Project的build.gradle文件</p>    <pre>  <code class="language-java">buildscript {      repositories {          jcenter()          // error-prone相关配置          maven {              url "https://plugins.gradle.org/m2/"          }      }      dependencies {          classpath 'com.android.tools.build:gradle:2.2.3'          // NOTE: Do not place your application dependencies here; they belong          // in the individual module build.gradle files          // error-prone相关配置          classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.9"      }  }    allprojects {      repositories {          jcenter()      }      //error-prone相关配置      apply plugin: "net.ltgt.errorprone"  }  </code></pre>    <ul>     <li>具体参考 <a href="/misc/goto?guid=4959747035459873085" rel="nofollow,noindex">net.ltgt.errorprone</a></li>     <li>其他配置方法 <a href="/misc/goto?guid=4959747035548885162" rel="nofollow,noindex">Maven, Ant等</a></li>    </ul>    <h2>开启/关闭部分检查</h2>    <p>Error-prone plugin提供了方法允许我们配置bugpattern的处理方式。</p>    <p>基本的做法是</p>    <pre>  <code class="language-java">tasks.withType(JavaCompile) {    options.compilerArgs += [ '-Xep:<checkName>[:severity]' ]  }  </code></pre>    <p>比如我们想要将ArrayToString从ERROR转成WARNING,我们可以这样做</p>    <pre>  <code class="language-java">tasks.withType(JavaCompile) {      options.compilerArgs += [ '-Xep:ArrayToString:WARN' ]  }  </code></pre>    <p>除此之外还有一些特殊的参数</p>    <ul>     <li>-XepAllErrorsAsWarnings 将全部的Error转成WARNING</li>     <li>-XepAllDisabledChecksAsWarnings 开启全部的check,之前禁止的作为WARNING级别处理</li>     <li>-XepDisableAllChecks 关闭所有的check</li>    </ul>    <h2>分条件开启error-prone插件</h2>    <p>理论上,error-prone在编译时期进行代码分析并检查,会延长了编译时间,加之Gradle编译本来就很慢,为了不对我们日常的构建造成影响,我们可以分条件开启error-prone,即</p>    <ul>     <li>在日常开发构建,禁止应用error-prone插件,不对构建时间影响</li>     <li>在特殊场景,比如持续集成时应用error-prone插件,用来发现问题。</li>    </ul>    <p>具体的做法是通过想gradle传递参数来实现。简易代码如下。</p>    <pre>  <code class="language-java">allprojects {      repositories {          jcenter()      }      //如果接受的参数有enableErrorProne则应用插件,否则不应用      if (project.hasProperty("enableErrorProne")) {          apply plugin: "net.ltgt.errorprone"      }  }  </code></pre>    <p>使用如下,则会开启应用插件</p>    <pre>  <code class="language-java">./gradlew assembleDebug -PenableErrorProne  </code></pre>    <h2>注意</h2>    <ul>     <li>由于是静态分析工具,即使问题代码不被执行也会检测出来。</li>     <li>一次编译过程中,error-prone可以报出多个错误</li>     <li>Android Studio也有对应的error-prone插件,大家也可以使用。</li>    </ul>    <p>以上就是关于error-prone的一些简单总结。Error-prone在Flipboard中已经应用很久,采用的方式为开发构建时不开启,在持续集成时开启。大家可根据自己和团队的需要选择并应用error-prone,来快速发现问题并改善代码的质量。</p>    <p> </p>    <p>来自:http://droidyue.com/blog/2017/04/09/error-prone-tool-for-java-and-android/</p>    <p> </p>