SonrLint常见解决方案

 

  • Sonar是什么?

   Sonar是一个用于代码质量管理的开源平台,用于管理源代码的质量 通过插件形式,可以支持包括java,C#,C/C++,PL/SQL,Cobol,JavaScrip,Groovy等等二十几种编程语言的代码质量管理与检测

 

Sonar可以从以下七个维度检测代码质量,而作为开发人员至少需要处理前5种代码质量问题

 

1. 不遵循代码标准 sonar可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具规范代码编写

 

2. 潜在的缺陷 sonar可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具检测出潜在的缺陷

 

3. 糟糕的复杂度分布 文件、类、方法等,如果复杂度过高将难以改变,这会使得开发人员难以理解它们 且如果没有自动化的单元测试,对于程序中的任何组件的改变都将可能导致需要全面的回归测试

 

4. 重复 显然程序中包含大量复制粘贴的代码是质量低下的,sonar可以展示源码中重复严重的地方

 

5. 注释不足或者过多 没有注释将使代码可读性变差,特别是当不可避免地出现人员变动时,程序的可读性将大幅下降 而过多的注释又会使得开发人员将精力过多地花费在阅读注释上,亦违背初衷

 

6. 缺乏单元测试 sonar可以很方便地统计并展示单元测试覆盖率

 

7. 糟糕的设计  通过sonar可以找出循环,展示包与包、类与类之间相互依赖关系,可以检测自定义的架构规则 通过sonar可以管理第三方的jar包,可以利用LCOM4检测单个任务规则的应用情况, 检测耦合。   

 

 

更多代码分析工具可以查看:常用 Java 静态代码分析工具的分析与比较 https://www.oschina.net/question/129540_23043

 

  • SonrLint 安装与使用

        https://www.cnblogs.com/qiumingcheng/p/7253917.html

  • sonar 常见解决方案

1.

Parentheses should be removed from a single lambda input parameter when its type is inferred

在推断单个lambda输入参数的类型时,应将其移除

 

 

There are two possible syntaxes for a lambda having only one input parameter with an inferred type: with and without parentheses around that single parameter. The simpler syntax, without parentheses, is more compact and readable than the one with parentheses, and is therefore preferred.

lambda有两种可能的语法,一种只有一个具有推断类型的输入参数:在该单个参数周围有括号,另一种没有括号。不带括号的简单语法比带括号的更紧凑、更易读,因此是首选语法。

 

Compliant Solution(统一解决方案):

 这里将 (t) 的括号去掉即可

2.

String literals should not be duplicated  字符串文本不应重复


Duplicated string literals make the process of refactoring error-prone, since you must be sure to update all occurrences.

On the other hand, constants can be referenced from many places, but only need to be updated in a single place.

 

重复的字符串文本使重构过程容易出错,因为必须确保更新所有出现的情况。

另一方面,常数可以从许多地方引用,但只需要在一个地方更新。

 

Compliant Solution(统一解决方案):

  相同的文本在多个地方使用的时候,需要统一定义同一个公共的常量参数

3.

Lambdas should be replaced with method references (lambda应替换为方法引用)

 

Method/constructor references are more compact and readable than using lambdas, and are therefore preferred. Similarly, null checks can be replaced with references to the Objects::isNull and Objects::nonNull methods.

Note that this rule is automatically disabled when the project's sonar.java.source is lower than 8.

 

方法/构造函数引用比使用lambda更紧凑和可读,因此是首选的。类似地,可以将空检查替换为对 Objects::isNull 和 Objects::nonNull  方法的引用。

 

请注意,当项目的sonar.java.source低于8时,此规则会自动禁用。

 

Compliant Solution(统一解决方案):

  这里可以将 w -> w.getItemNumId() 改成 PosStyleSkuVO :: getItemNumId

4.

不应使用同步类vector、hashtable、stack和stringbuffer

Synchronized classes Vector, Hashtable, Stack and StringBuffer should not be used

不应使用Synchronized 类如: vector、hashtable、stack和stringbuffer

 

 

Early classes of the Java API, such as Vector, Hashtable and StringBuffer, were synchronized to make them thread-safe. Unfortunately, synchronization has a big negative impact on performance, even when using these collections from a single thread.

 

Java API的早期类,如vector、HasTabe和StringBuffer,被使用 synchronized 来使它们线程安全。但是不幸的是,同步对性能有很大的负面影响,即使在从单个线程使用这些集合时也是如此。

 

It is better to use their new unsynchronized replacements:(最好使用新的非同步替换)

使用ArrayList or LinkedList 来替代 Vector

使用Deque 来替代 Stack

使用HashMap 来替代 Hashtable

使用StringBuilder 来替代 StringBuffer

 

 

Compliant Solution(统一解决方案):

  这里可以可以使用 StringBuilder 而不是StringBuffer

5.

Unused method parameters should be removed (应删除未使用的方法参数)

 

Unused parameters are misleading. Whatever the values passed to such parameters, the behavior will be the same.

未使用的参数具有误导性。无论传递给这些参数的值是什么,行为都是相同的。

 

Compliant Solution(统一解决方案):

  这里可以建议去除掉没有必要的参数

6.

Lamdbas containing only one statement should not nest this statement in a block

仅包含一条语句的lamdba不应将此语句嵌套在块中

 

 

 

There are two ways to write lambdas that contain single statement, but one is definitely more compact and readable than the other.

 

 

有两种方法可以编写包含单个语句的lambda,但是一种方法绝对比另一种方法更紧凑和可读。

 

Compliant Solution(统一解决方案):

  这里可以去除掉 {} 和后面的 ; 号

7.

Cognitive Complexity of methods should not be too high

方法的认知复杂性不应太高。

 

 

Cognitive Complexity is a measure of how hard the control flow of a method is to understand. Methods with high Cognitive Complexity will be difficult to maintain.

认知复杂性是衡量一种方法的控制流程理解难度的指标。认知复杂性高的方法难以别的开发人员去维护。

 

 

Compliant Solution(统一解决方案):

  对应这种if-else 过多方法,我们主要目的是要消除 if-else ,每多一个 else 那么就会多一个逻辑分叉,代码的易读性会急速降低,这里收集总结了一些地址,需要的同学可以去看一下:

减少该死的 if else 嵌套 
java如何消除繁琐的if else 语句? 
如何无痛降低 if else 面条代码复杂度 
用设计模式来代替臃肿的ifelse层层判断 

8.

Map values should not be replaced unconditionally

不应无条件替换映射值

 

It is highly suspicious when a value is saved for a key or index and then unconditionally overwritten. Such replacements are likely in error.

 

当为键或索引保存一个值,然后无条件地覆盖时,它是高度可疑的。这种替代品可能是错误的。

 

Compliant Solution(统一解决方案):

   去除一个相同的key 的put

9.

Printf-style format strings should be used correctly

应正确使用printf样式的格式字符串

 

Because printf-style format strings are interpreted(编译解释) at runtime, rather than validated(使生效) by the compiler, they can contain errors that result in the wrong strings being created. This rule statically validates the correlation of printf-style format strings to their arguments when calling the format(...) methods of java.util.Formatter, java.lang.String, java.io.PrintStream, MessageFormat, and java.io.PrintWriter classes and the printf(...) methods of java.io.PrintStream or java.io.PrintWriter classes.

因为 printf-style 格式字符串是在运行时编译解释的,而不是由编译时生效的,所以它们可能包含导致创建错误字符串的错误。当调用java.util.formatter、java.lang.string、java.io.printstream、messageformat和java.io.printwriter类的format(...)方法以及java.io.printstream或java.io.printwriter类的format(...)方法时,此规则静态地证实了 printf-style 的 字符串 和 其参数的相关性(这句话的说白了就是,string.format 方法的与其参数息息相关,参数和主体字符串关系具有一定的关系,不要乱来)

 

Noncompliant Code Example (不符合的规则示例):

 

  1. String.format("First {0} and then {1}", "foo", "bar"); //Noncompliant. Looks like there is a confusion with the use of {{java.text.MessageFormat}}, parameters "foo" and "bar" will be simply ignored here  
  2. String.format("Display %3$d and then %d", 1, 2, 3); //Noncompliant; the second argument '2' is unused  
  3. String.format("Too many arguments %d and %d", 1, 2, 3); //Noncompliant; the third argument '3' is unused  
  4. String.format("First Line\n"); //Noncompliant; %n should be used in place of \n to produce the platform-specific line separator  
  5. String.format("Is myObject null ? %b", myObject); //Noncompliant; when a non-boolean argument is formatted with %b, it prints true for any nonnull value, and false for null. Even if intended, this is misleading. It's better to directly inject the boolean value (myObject == null in this case)
  6. String.format("value is " + value); // Noncompliant  
  7. String s = String.format("string without arguments"); // Noncompliant    
  8. MessageFormat.format("Result '{0}'.", value); // Noncompliant; String contains no format specifiers. (quote are discarding format specifiers)
  9. MessageFormat.format("Result {0}.", value, value); // Noncompliant; 2nd argument is not used  

10> MessageFormat.format("Result {0}.", myObject.toString()); // Noncompliant; no need to call toString() on objects    

11> java.util.Logger logger;

 logger.log(java.util.logging.Level.SEVERE, "Result {0}.", myObject.toString()); // Noncompliant; no need to call toString() on objects  

  1. logger.log(java.util.logging.Level.SEVERE, "Result.", new Exception()); // compliant, parameter is an exception  
  2. logger.log(java.util.logging.Level.SEVERE, "Result '{0}'", 14); // Noncompliant {{String contains no format specifiers.}}  
  3.  org.slf4j.Logger slf4jLog;

 org.slf4j.Marker marker;

slf4jLog.debug(marker, "message {}");  

slf4jLog.debug(marker, "message ", 1); // Noncompliant {{String contains no format specifiers.}}  

 

Compliant Solution(统一解决方案):

  String.format("First %s and then %s", "foo", "bar");

String.format("Display %2$d and then %d", 1, 3);

String.format("Too many arguments %d %d", 1, 2);

String.format("First Line%n");

String.format("Is myObject null ? %b", myObject == null);

String.format("value is %d", value);

String s = "string without arguments";

MessageFormat.format("Result {0}.", value);

MessageFormat.format("Result '{0}' = {0}", value);

MessageFormat.format("Result {0}.", myObject);

java.util.Logger logger;

logger.log(java.util.logging.Level.SEVERE,"Result{0}.",myObject);

logger.log(java.util.logging.Level.SEVERE,"Result{0}'",14);

org.slf4j.Logger slf4jLog;

org.slf4j.Marker marker;

slf4jLog.debug(marker, "message {}");

 slf4jLog.debug(marker, "message {}", 1);

这里的异常是主体字符串标识符只有一个{},但是却有两个参数,这个是不符合规则的

10.

String function use should be optimized for single characters

字符串函数的使用应针对单个字符进行优化

 

 

An indexOf or lastIndexOf call with a single letter String can be made more performant by switching to a call with a char argument.

 

使用 char 类型的参数可以提高单字母字符串的indexof或lastindexof调用的性能。

 

Compliant Solution(统一解决方案):

   将result.indexOf(".") 改成 result.indexOf('.')

11.

Empty arrays and collections should be returned instead of null

应返回空数组和集合,而不是 null

 

Returning null instead of an actual array or collection forces callers of the method to explicitly test for nullity, making them more complex and less readable.

Moreover, in many cases, null is used as a synonym for empty.

 

返回null来替代 实际的数组或集合 会强制是该方法的”调用方”很明确的去测试为null的情况,从而使它们更复杂,可读性更低。此外,在许多情况下,null 也用作 empty 的同义词;

 

Compliant Solution(统一解决方案):

这里将return null; 改为Collections.emptyList();

12.

 Collapsible "if" statements should be merged

应该合并可折叠的“if”语句

 

 

Merging collapsible if statements increases the code's readability.

 

合并可折叠的if语句可以提高代码的可读性。

 

Compliant Solution(统一解决方案):

这里将:

else if(shop.getType() == 2) {

//过滤门店自定义无库存tab

if(!filterNoGoodsTabBySearch(shop)) {

continue;

}

}

改为

//过滤门店自定义无库存tab

else if(shop.getType() == 2 && !filterNoGoodsTabBySearch(shop)) { continue;

}

这里其实不改的话 可读性更高点,具体要不要修改要视实际情况而定!

13.

Dead stores should be removed

应移除废弃存储

 

A dead store happens when a local variable is assigned a value that is not read by any subsequent instruction. Calculating or retrieving a value only to then overwrite it or throw it away, could indicate a serious error in the code. Even if it's not an error, it is at best a waste of resources. Therefore all calculated values should be used.

当一个局部变量被分配一个值,而该值不被任何后续的指令读取时,就会发生死区。计算或检索一个值,然后覆盖或丢弃它,可能表示代码中存在严重错误。即使这不是一个错误,也充其量只是浪费资源。因此,应使用所有计算值。

 

Compliant Solution(统一解决方案):

 这里将 Long[] memberIds =new Long[6];

List<Long> ids = this.getRecentShopCommentMember(shopId);

memberIds = new Long[ids.size()];

memberIds = ids.toArray(memberIds);

改为:    List<Long> ids = this.getRecentShopCommentMember(shopId);

Long[] memberIds =  new Long[ids.size()];

memberIds = ids.toArray(memberIds);

14.

Collection.isEmpty() should be used to test for emptiness

collection.isEmpty()应用于测试是否为空

 

 

Using Collection.size() to test for emptiness works, but using Collection.isEmpty() makes the code more readable and can be more performant. The time complexity of any isEmpty() method implementation should be O(1) whereas some implementations of size() can be O(n).

使用collection.size()测试空性是可行的,但是使用collection.isEmpty() 可以使代码更可读,更具性能。任何isEmpty() 方法实现的时间复杂性都应该是O(1),而某些size() 的实现可以是O(n)。

 

Compliant Solution(统一解决方案):

 这里工具建议使用 collection 的 isEmpty() 方法,但是实际上 collection 是否为null ,这个也是我们需要判断的,所以我们可以使用 CollectionUtils.isNotEmpty()方法

Ps:

list.size()>0 :

list.size()>0这个方法会先计算一下list里元素的个数,然后再和0进行比较

list.isEmpty()

判断list里是否有元素,list不需要计算元素个数,直接看一下是否为空

即查size时间复杂度是o(n) ,如果是empty o(1);所以判断集合是否为空一般用list.isEmpty()来判断;

CollectionUtils.isEmpty() 正是如此

另外对于某些明显已经实例化的collection ,我们其实也不用全部调用CollectionUtils.isEmpty 方法,这样依然能够满足需求

15.

布尔类型的返回值不需要去判断布尔文本

16.

Local variables should not be declared and then immediately returned  or thrown

不应声明局部变量,然后立即返回或者抛出它

 

 

Declaring a variable only to immediately return or throw it is a bad practice(实践;练习;惯例;)

Some developers argue that the practice improves code readability, because it enables them to explicitly name what is being returned. However, this variable is an internal implementation detail that is not exposed to the callers of the method. The method name should be sufficient for callers to know exactly what will be returned.

 

只声明一个变量以立即返回或抛出它是一种糟糕的惯例。

一些开发人员认为该惯例提高了代码的可读性,因为它使他们能够显式地命名返回的内容。但是,该变量是一个内部实现细节,我们完全不需要向方法的调用方公开内部细节。而且方法名应该足以让调用方确切知道将返回什么。

 

Compliant Solution(统一解决方案):

将:

Set<String> list = redisService.zreverage(key,0,5);

return list;

改为:

return redisService.zreverage(key,0,5);

17.

The diamond operator ("<>") should be used

应使用菱形运算符(“<>”)

 

Java 7 introduced the diamond operator (<>) to reduce the verbosity of generics code. For instance, instead of having to declare a List's type in both its declaration and its constructor, you can now simplify the constructor declaration with <>, and the compiler will infer the type.

Java 7引入了菱形运算符(<>)来减少泛型代码的冗长性。例如,不必在列表的声明和构造函数中同时声明列表的类型,现在可以用<>简化构造函数声明,编译器将推断该类型。

 

Compliant Solution(统一解决方案):

List<Long> ids = new ArrayList<>();

18.

The diamond operator ("<>") should be used

应使用菱形运算符(“<>”)

 

Java 7 introduced the diamond operator (<>) to reduce the verbosity of generics code. For instance, instead of having to declare a List's type in both its declaration and its constructor, you can now simplify the constructor declaration with <>, and the compiler will infer the type.

Java 7引入了菱形运算符(<>)来减少泛型代码的冗长性。例如,不必在列表的声明和构造函数中同时声明列表的类型,现在可以用<>简化构造函数声明,编译器将推断该类型。

 

Compliant Solution(统一解决方案):

List<Long> ids = new ArrayList<>();

19.

用Arrays.asList() 方法得到的List的长度是不可改变的,

当你向这个List添加或删除一个元素时(例如 list.add("d");)程序就会抛出异常:

Arrays.asList()源码如下

@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

这里需要注意这个new ArrayList<>(a)

这个ArrayList不是java.util包下的,而是java.util.Arrays.ArrayList

它是Arrays类自己定义的一个静态内部类,这个内部类没有实现add()、remove()方法,而是直接使用它的父类AbstractList的相应方法,对应的set add remove 方法如下:

public E set(int index, E element) {
 throw new UnsupportedOperationException();
}
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}
public E remove(int index) {
    throw new UnsupportedOperationException();
}

所以如果后续需要对该参数进行添加移除等操作的时候,就不要使用Arrays.asList() 了 ,老老实实用Lists.newArrayList()吧。

20.

"BigDecimal(double)" should not be used

不应使用“BigDecimal(double)”。

Because of floating point imprecision, you're unlikely to get the value you expect from the BigDecimal(double) constructor.

由于浮点不精确,您不太可能从bigdecimal(double)构造函数获得预期的值。

javase/7/docs

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

 

这个构造函数的结果可能有些不可预测。人们可以假设在Java中创建一个新的BigDeCimple(0.1)创建一个完全等于0.1的BigDecimal(一个未缩放的值为1,具有1的规模),但实际上它等于0.100000 000 000 000 555 1112312757 827 0211815834045 41015625。这是因为0.1不能精确地表示为一个双精度数(double)(或者就此而言,不能精确地表示为任何有限长度的二分之一)。因此,虽然看起来外观如此都是0.1,但是实际上传递给构造函数的值并不完全等于0.1。

 

 

PS: 目前收集和整理了大概这些,后续还会不定期补充,这里为什么依然使用英文不用汉化版的插件,这里就不解释了,部分翻译是我根据自己的理解自己补充的,大家看看理解就行,不必太在意这个!

        整理不易,如果对你有帮助记得留个赞再走呀!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章