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: 目前收集和整理了大概這些,後續還會不定期補充,這裏爲什麼依然使用英文不用漢化版的插件,這裏就不解釋了,部分翻譯是我根據自己的理解自己補充的,大家看看理解就行,不必太在意這個!

        整理不易,如果對你有幫助記得留個贊再走呀!!

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