代码质量管理工具:SonarQube常见的问题及正确解决方案

2023-11-13

SonarQube 简介

Sonar 是一个用于代码质量管理的开放平台。通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具。

与持续集成工具(例如 Hudson/Jenkins 等)不同,Sonar 并不是简单地把不同的代码检查工具结果(例如 FindBugs,PMD 等)直接显示在 Web 页面上,而是通过不同的插件对这些结果进行再加工处理,通过量化的方式度量代码质量的变化,从而可以方便地对不同规模和种类的工程进行代码质量管理。

在对其他工具的支持方面,Sonar 不仅提供了对 IDE 的支持,可以在 Eclipse 和 IntelliJ IDEA 这些工具里联机查看结果;同时 Sonar 还对大量的持续集成工具提供了接口支持,可以很方便地在持续集成中使用 Sonar。

此外,Sonar 的插件还可以对 Java 以外的其他编程语言提供支持,对国际化以及报告文档化也有良好的支持

代码质量管理工具:SonarQube常见的问题及正确解决方案

Math operands should be cast before assignment-数字操作在操作或赋值前要分配

对整数执行算术运算时,结果将始终是整数。您可以通过自动类型转换将该结果分配给long,double或float类型,但是以int或long形式开始时,结果可能不会达到您的期望。

例如,如果将int除法的结果分配给浮点变量,则在分配之前将失去精度。同样,如果将乘法结果分配给long,则在分配之前它可能已经溢出。

不合规代码

float twoThirds = 2/3; // Noncompliant; int division. Yields 0.0
long millisInYear = 1_000*3_600*24*365; // Noncompliant; int multiplication. Yields 1471228928
long bigNum = Integer.MAX_VALUE + 2; // Noncompliant. Yields -2147483647
long bigNegNum =  Integer.MIN_VALUE-1; //Noncompliant, gives a positive result instead of a negative one.
Date myDate = new Date(seconds * 1_000); //Noncompliant, won't produce the expected result if seconds > 2_147_483
...
public long compute(int factor){
  return factor * 10_000;  //Noncompliant, won't produce the expected result if factor > 214_748
}

public float compute2(long factor){
  return factor / 123;  //Noncompliant, will be rounded to closest long integer
}

合规代码

float twoThirds = 2f/3; // 2 promoted to float. Yields 0.6666667
long millisInYear = 1_000L*3_600*24*365; // 1000 promoted to long. Yields 31_536_000_000
long bigNum = Integer.MAX_VALUE + 2L; // 2 promoted to long. Yields 2_147_483_649
long bigNegNum =  Integer.MIN_VALUE-1L; // Yields -2_147_483_649
Date myDate = new Date(seconds * 1_000L);
...
public long compute(int factor){
  return factor * 10_000L;
}

public float compute2(long factor){
  return factor / 123f;
}

或者是
float twoThirds = (float)2/3; // 2 cast to float
long millisInYear = (long)1_000*3_600*24*365; // 1_000 cast to long
long bigNum = (long)Integer.MAX_VALUE + 2;
long bigNegNum =  (long)Integer.MIN_VALUE-1;
Date myDate = new Date((long)seconds * 1_000);
...
public long compute(long factor){
  return factor * 10_000;
}

public float compute2(float factor){
  return factor / 123;
}

分析

本项sonar 规则,主要是Java 中 小类型可以向大的类型转换,如int 可以自动向long 转换。避免这种自动转换引发的问题,就是本规则的初衷。

让开发者可以明确的清楚当前数据的类型。

Strings and Boxed types should be compared using "equals()"

字符串和包装类型对比时应该使用equals方法。

使用引用相等==或!=比较java.lang.String或包装类型(如java.lang.Integer)的两个实例几乎总是false,因为它不是在比较实际值,而是在内存中的位置。

不合格的代码

String firstName = getFirstName(); // String overrides equals
String lastName = getLastName();

if (firstName == lastName) { ... }; // Non-compliant; false even if the strings have the same value

合规的代码

String firstName = getFirstName();
String lastName = getLastName();

if (firstName != null && firstName.equals(lastName)) { ... };

分析

在Java 中包装类型与基本数据类型存储位置不同。

Java 基本数据类型存放位置

  • 方法参数、局部变量存放在栈内存中的栈桢中的局部变量表

  • 常量存放在常量池中

包装类型如Integer存放位置

  • 常量池

  • 堆内存

Integer 存储在常量池中时可以使用==对比,但当在堆内存中时,使用==对比,实际对比的是两个内存地址而非值。

根据Integer源码,

代码质量管理工具:SonarQube常见的问题及正确解决方案

可以看出数值在-128-127时,会使用cache中的数据,其实也就是常量池。超过范围后新创建Integer,此时数据就无法使用==。

本项规则,主要就是为了避免对比内存地址而引发的错误判断。

Boxing and unboxing should not be immediately reversed

装箱(创建int/Integer类型值的对象)和拆箱(将对象中原始值解出来)不应连续操作。

由于在装箱和拆箱期间原始值保持不变,因此在不需要时进行任何操作都是没有意义的。这也适用于自动装箱和自动拆箱(当Java为您隐式处理原始/对象转换时)。


不合规代码
 

public void examineInt(int a) {
  //...
}

public void examineInteger(Integer a) {
  // ...
}

public void func() {
  int i = 0;
  Integer iger1 = Integer.valueOf(0);
  double d = 1.0;

  int dIntValue = new Double(d).intValue(); // Noncompliant

  examineInt(new Integer(i).intValue()); // Noncompliant; explicit box/unbox
  examineInt(Integer.valueOf(i));  // Noncompliant; boxed int will be auto-unboxed

  examineInteger(i); // Compliant; value is boxed but not then unboxed
  examineInteger(iger1.intValue()); // Noncompliant; unboxed int will be autoboxed

  Integer iger2 = new Integer(iger1); // Noncompliant; unnecessary unboxing, value can be reused
}

合规代码

public void examineInt(int a) {
  //...
}

public void examineInteger(Integer a) {
  // ...
}

public void func() {
  int i = 0;
  Integer iger1 = Integer.valueOf(0);
  double d = 1.0;

  int dIntValue = (int) d;

  examineInt(i);

  examineInteger(i);
  examineInteger(iger1);
}

分析

拆箱,与装箱数值没有发生变化,但在大数据量前提下是极其浪费时间。以下实例中,两者耗时相差10倍。此项目检查主要是提高性能。

 

Intermediate Stream methods should not be left unused

中间流方法不应该闲置,应该提供对应的终端操作(流操作有两种类型:中间操作(返回另一个流)和终端操作(返回比流更多的内容)。中间操作是惰性的,如果中间流操作的结果没有提供给终端操作,那么它就没有任何作用)

不合规

widgets.stream().filter(b -> b.getColor() == RED); // Noncompliant

合规

int sum = widgets.stream()
                      .filter(b -> b.getColor() == RED)
                      .mapToInt(b -> b.getWeight())
                      .sum();
Stream<Widget> pipeline = widgets.stream()
                                 .filter(b -> b.getColor() == GREEN)
                                 .mapToInt(b -> b.getWeight());
sum = pipeline.sum();


Loops with at most one iteration should be refactored

循环执行一次应该重构。

不合规

for (int i = 0; i < 10; i++) { // noncompliant, loop only executes once
  printf("i is %d", i);
  break;
}
...
for (int i = 0; i < 10; i++) { // noncompliant, loop only executes once
  if(i == x) {
    break;
  } else {
    printf("i is %d", i);
    return;
  }
}

不合规

for (int i = 0; i < 10; i++) {
  printf("i is %d", i);
}
...
for (int i = 0; i < 10; i++) {
  if(i == x) {
    break;
  } else {
    printf("i is %d", i);
  }
}

Non-thread-safe fields should not be static

非线程安全的属性不能设置为静态

不合规

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


合规

public class MyClass {
  private SimpleDateFormat format = new SimpleDateFormat("HH-mm-ss");
  private Calendar calendar = Calendar.getInstance();

分析

线程不安全的类型设置为静态后,对于静态变量来说,类在加载的时候会占用同一个存储区,而每个线程都是公用这个存储区的,因此存在线程安全的问题。

在多并发的过程中容易产生问题,而且问题原因不易跟踪。


"InterruptedException" should not be ignored

绝不应该在代码中忽略InterruptedExceptions,在这种情况下,只需将异常计数记录为“忽略”即可。抛出InterruptedException会清除Thread的中断状态,因此,如果未正确处理该异常,则该线程被中断的事实将丢失。相反,应该立即或在清除方法状态后重新抛出InterruptedExceptions-或应该通过调用Thread.interrupt()重新中断线程,即使这应该是单线程应用程序也是如此。任何其他措施可能会导致线程关闭延迟,并丢失该线程被中断的信息-可能未完成其任务。

合规代码

InterruptedExceptions should never be ignored in the code, and simply logging the exception counts in this case as "ignoring". The throwing of the InterruptedException clears the interrupted state of the Thread, so if the exception is not handled properly the fact that the thread was interrupted will be lost. Instead, InterruptedExceptions should either be rethrown - immediately or after cleaning up the method's state - or the thread should be re-interrupted by calling Thread.interrupt() even if this is supposed to be a single-threaded application. Any other course of action risks delaying thread shutdown and loses the information that the thread was interrupted - probably without finishing its task.

public void run () {
  try {
    while (true) {
      // do stuff
    }
  }catch (InterruptedException e) { // Noncompliant; logging is not enough
    LOGGER.log(Level.WARN, "Interrupted!", e);
  }
}

不合规

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

总结

sonarqube 进行代码质量检查,不仅可以分析当前代码已存在问题。也可以通过问题进行分析,把错误的代码习惯,改正。

长期使用sonarqube,可以培养开发者写优秀代码。降低bug率。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

代码质量管理工具:SonarQube常见的问题及正确解决方案 的相关文章

随机推荐

  • 2023智源大会议程公开丨视觉与多模态大模型论坛

    6月9日 2023北京智源大会 将邀请AI领域的探索者 实践者 以及关心智能科学的每个人 共同拉开未来舞台的帷幕 你准备好了吗 与会知名嘉宾包括 图灵奖得主Yann LeCun OpenAI创始人Sam Altman 图灵奖得主Geoffr
  • 第十六篇:关于Unity开发WebGL遇到的坑

    1 资源消耗问题 Unity开发Web 项目 发布出来的项目是很消耗内存资源的 这是Unity引擎决定 我们要做的就是尽可能的优化 通常的方法有降低模型面数 降低贴图的大小 减少点光源 减小烘焙贴图大小等 当然也可以使用three js开发
  • 机器人流程自动化(RPA):6大开源工具

    51CTO com快译 与实施许多新软件一样 开始使用机器人流程自动化 RPA 方面面临自建还是外购的选择 如果是自建 只要你有合适的人员 预算到位 可以从头开始编写自己的机器人 如果是外购 有一个新兴的商业软件供应商市场 它们提供各式各样
  • 数据链路层--以太网协议

    目录 以太网协议 认识以太网 以太网帧格式 认识MAC地址 认识MTU 数据跨网络传输的过程 ARP协议 ARP概念 ARP数据的格式 ARP协议的工作流程 ARP请求的过程 ARP应答的过程 ARP缓存表 在学习完ip协议后知道 网络层解
  • 大话设计模式学习 C++

    工厂模式 include bits stdc h using namespace std 基类 进行操作 class Operation protected data double numberA 0 double numberB 0 pu
  • SSM项目可以正常启动并访问,控制台无报错,但是项目调用controller层返回404

  • 18650锂电池保护板接线图_锂电池保护板几种接线方法介绍 - 全文

    锂电池保护板简介 锂电池保护板是对串联锂电池组的充放电保护 在充满电时能保证各单体电池之间的电压差异小于设定值 一般 20mV 实现电池组各单体电池的均充 有效地改善了串联充电方式下的充电效果 同时检测电池组中各个单体电池的过压 欠压 过流
  • Linux C++ 遍历子目录下的文件名称并保存到变量vector<string> 中

    遍历子目录下的文件名称并保存到变量vector 中 include
  • Java设计模式-原型模式

    原型模式 在有些系统中 存在大量相同或相似对象的创建问题 如果用传统的构造函数来创建对象 会比较复杂且耗时耗资源 用原型模式生成对象就很高效 原型模式的定义与特点 原型 Prototype 模式的定义如下 用一个已经创建的实例作为原型 通过
  • 华为鸿蒙os什么时候发布,华为鸿蒙OS发布,支持上百款机型(附推送名单),你会升级吗?...

    昨天晚上 万众期待的华为鸿蒙OS正式发布 对于国产操作系统具有跨时代的意义 首批支持上百款机型升级 意味着鸿蒙OS诞生之初便形成Android iOS 鸿蒙OS鼎足而立之势 鸿蒙OS并非拷贝Android和iOS系统 尤其Android特性
  • Java并发编程原理与实战课程(叶子猿)

    前4节官网免费看 txt 05线程的状态以及各状态之间的转换详解 mp4 06线程的初始化 中断以及其源码讲解 mp4 07多种创建线程的方式案例演示 一 带返回值的方式 mp4 08多种创建线程的方式案例演示 二 使用线程池 mp4 09
  • Java设计模式——桥接模式

    文章目录 桥接模式 桥接模式 桥接模式就是把事物和其具体实现分开 使他们可以各自独立的变化 桥接的用意是 将抽象化与实现化解耦 使得二者可以独立变化 像我们常用的JDBC桥DriverManager一样 JDBC进行连接数据库的时候 在各个
  • 华为FusionCompute之个人学习环境虚拟化嵌套部署方案

    华为FusionCompute之个人学习环境虚拟化嵌套部署方案 一 环境介绍 1 本次实践背景 2 物理机配置介绍 3 FC虚拟化部署方案介绍 4 虚拟化环境介绍 5 本次实践目的 二 检查本地环境 1 检查虚拟化环境 2 FC部署进度介绍
  • 软考-系统架构师-计算机与网络基础知识-系统性能

    文章目录 1 性能指标 2 性能计算 3 性能设计 4 性能评估 说明 系统性能是一个系统提供给用户的中国性能指标的集合 它包括硬件性能 软件性能 部件性能指标 综合性能指标 1 性能指标 性能指标是软 硬件的性能指标的集成 在硬件中包括计
  • EMC测试的那些项目,你都知道么?

    转载 EMC电磁兼容 2022 03 27 08 30 EMC检测 电磁兼容性检测 的全称是Electro Magnetic Compatibility 其定义为 设备和系统在其电磁环境中能正常工作且不对环境中任何事物构成不能承受的电磁骚扰
  • gethostbyname()函数详解

    基本概念 gethostbyname 函数主要作用 用域名或者主机名获取地址 操作系统提供的库函数 以下的讨论基于linux环境 域名系统 Domain Name System DNS 主要用于主机名字与IP地址之间的映射 每个组织机构往往
  • 【NLP】1、BERT

    文章目录 一 背景 二 方法 论文 BERT Pre training of Deep Bidirectional Transformers for Language Understanding 出处 Google 一 背景 在 BERT
  • flutter图片点击跳转_flutter页面跳转 Route 使用汇总

    一 push方式直接跳转 普通跳转 Navigator push context MaterialPageRoute builder BuildContext context gt Page1 复制代码 带参数跳转和接收参数 Navigat
  • Python习题四

    习题四 1 已知10个学生的成绩为68 75 32 99 78 45 88 72 83 78 请将成绩存放在列表中 请对其进行统计 输出优 100 89 良 89 80 中 79 60 差良 59 0 4个等级的人数 代码 运行 2 利用W
  • 代码质量管理工具:SonarQube常见的问题及正确解决方案

    SonarQube 简介 Sonar 是一个用于代码质量管理的开放平台 通过插件机制 Sonar 可以集成不同的测试工具 代码分析工具 以及持续集成工具 与持续集成工具 例如 Hudson Jenkins 等 不同 Sonar 并不是简单地