Java代碼規(guī)范小結(jié)(一)

前言

? ? ? 自學(xué)了4個多月的安卓,試著寫了一個小程序,雖然功能按照預(yù)想基本實現(xiàn)了,但是也很清楚代碼質(zhì)量肯定不好。在開源中國sonar平臺進行了一下代碼質(zhì)量分析。

技術(shù)債務(wù)金字塔

? ? ? 百度了一下技術(shù)債務(wù):術(shù)語”技術(shù)債務(wù)“是由Ward Cunningham首次提出,指的是開發(fā)團隊在設(shè)計或架構(gòu)選型時從短期效應(yīng)的角度選擇了一個易于實現(xiàn)的方案,但從長遠來看,這種方案會帶來更消極的影響,亦即開發(fā)團隊所欠的債務(wù)。(淚流滿面)

主要問題列表:

格式:問題名字+問題出現(xiàn)的次數(shù)

Resources should be closed2

資源未關(guān)閉,打開發(fā)現(xiàn)有兩處用到的IO流沒有關(guān)閉

Conditions should not unconditionally evaluate to "TRUE" or to "FALSE"1

if/else判斷里出現(xiàn)了重復(fù)判斷,比如在if(a>10)的執(zhí)行體里面又判斷if(a<0),而后者肯定不會是true

Exception handlers should preserve the original exception13

處理異常的時候應(yīng)該保留原始的異常情況,不要直接來個catch(Exception e)了事

Throwable.printStackTrace(...) should not be called7

不應(yīng)該直接調(diào)用e.printStackTrace(),而是用Loggers來處理(就是打Log)。

Loggers的優(yōu)勢是:Users are able to easily retrieve the logs.

The format of log messages is uniform and allow users to browse the logs easily.

Instance methods should not write to "static" fields6

不要用實例方法改變靜態(tài)成員,理想情況下,靜態(tài)變量只通過同步的靜態(tài)方法來改變

"public static" fields should be constant1

公共靜態(tài)成員應(yīng)該加上final,也就是public static final 一般不分家

Thread.run() and Runnable.run() should not be called directly1

不應(yīng)該直接調(diào)用Thread和Runnaale對象的run方法,直接調(diào)用run會使得run方法執(zhí)行在當前線程,失去了開啟新線程的意義。但有時候可能會這樣做,下面有個例子。

Generic exceptions should never be thrown1

不太理解,大意是說不要直接拋Error,RuntimeException/Throwable/Exception這樣的通用的異常。我的具體應(yīng)用是:throw new Error("Error copying database"),給出的建議是:Define and throw a dedicated exception instead of using a generic one(定義并拋出一個專用的異常來代替一個通用的異常)

Class variable fields should not have public accessibility64

類變量不要設(shè)置為public,而是設(shè)為private,再提供get和set方法。

Sections of code should not be "commented out"30

不要再注釋中出現(xiàn)大量的代碼段,會使代碼可讀性變差

Package declaration should match source file directory19

這個沒理解,包的聲明應(yīng)該與源文件目錄匹配。

Utility classes should not have public constructors16

工具類不應(yīng)該有公共的構(gòu)造器,也就是說至少要有一個private的構(gòu)造器,如果沒有,默認的構(gòu)造器是public的。

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

在定義集合的時候,等號右邊的<>內(nèi)不需要再寫上元素類型,直接空著就行。

Lambdas and anonymous classes should not have too many lines9

Lambdas表達式和匿名內(nèi)部類不要寫太多行,一般最多寫20行。

Anonymous inner classes containing only one method should become lambdas8

只包含一個方法的匿名內(nèi)部類應(yīng)該寫成Lambdas表達式的形式,增強代碼可讀性

Try-with-resources should be used8

用Try-with-resources的形式取代try/catch/finally的形式,這個有待于以后學(xué)習(xí)。

Methods should not be empty7

不要寫空方法,除非這種情況:An abstract class may have empty methods, in order to provide default implementations for child classes.

Source files should not have any duplicated blocks7

源文件中不要出現(xiàn)任何重復(fù)的代碼段或行或字符串等。沒理解。

"switch case" clauses should not have too many lines6

"switch case"?每個case里面的代碼不要太長,太長的話可以考慮寫個方法代替,主要是為了增強代碼可讀性

Nested blocks of code should not be left empty6

嵌套代碼塊不要是空的,比如 if( a > 0 ) { ?doSomething() ?} else { },這時候應(yīng)該把后面的else{}去掉。

Methods should not be too complex6

方法不要太復(fù)雜,否則難以理解和維護。

Unused private fields should be removed5

沒有使用的private的成員變量應(yīng)該移除掉。

Dead stores should be removed5

沒有用到的本地變量或其他死存儲應(yīng)該移除掉,也就是寫方法的時候,定義的變量如果后來發(fā)現(xiàn)根本用不到,要記得刪掉那行代碼。

"switch" statements should end with a "default" clause4

switch語句應(yīng)該以default結(jié)束,這是一種defensive programming思想

Unused method parameters should be removed4

沒有用到的方法參數(shù)應(yīng)該移除掉

Control flow statements "if", "for", "while", "switch" and "try" should not be nested too deeply4

if /for/while/try這樣的嵌套不要太復(fù)雜

Useless parentheses around expressions should be removed to prevent any misunderstanding3

沒有意義的括號不要隨便加,以免造成誤解,比如"="兩邊對象類型是相同的,就不要強轉(zhuǎn)。

"for" loop stop conditions should be invariant3

for循環(huán)的結(jié)果條件不能是變量,而應(yīng)該是常量

"static" members should be accessed statically2

static成員是與類、靜態(tài)方法相聯(lián)系的。

Catches should be combined2

具體參考下面的18,我還沒理解

Primitives should not be boxed just for "String" conversion2

不要使用 4+" "這樣的方式將int值轉(zhuǎn)變?yōu)樽址鞘褂?Integer.toString(4)這樣的方式。

就像Integer.parseInt("我是字符串")這樣,不要偷懶。

Classes should not be empty2

不要寫空類

Unused local variables should be removed2

沒有用到的本地變量要刪掉

"entrySet()" should be iterated when both the key and value are needed2

直接看英文更直接:When only the keys from a map are needed in a loop, iterating the keySet makes sense. But when both the key and the value are needed, it's more efficient to iterate theentrySet, which will give access to both the key and value, instead.

也就是說,如果只需要Map的Key,那么直接iterate這個Map的keySet就可以了,但是如果Key和value都需要,就iterate這個Map。具體看下面的19.

Method parameters, caught exceptions and foreach variables should not be reassigned2

方法參數(shù)/捕獲的異常/foreach的變量不應(yīng)該被重新賦值。

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

當判斷集合是否為空的時候,不要使用if (myCollection.size() == 0) 這樣的方式,而是使用if (myCollection.isEmpty()這樣的方式,后者性能更高。

Standard outputs should not be used directly to log anything2

標準輸出不直接打印任何東西,也就是打log的時候,不要使用System.out.println("My Message")這樣的方式,而是使用logger.log("My Message")這種方式。

Generic wildcard types should not be used in return parameters1

通配符不應(yīng)該出現(xiàn)在返回聲明中。比如這句:List <? extends Animal>getAnimals(){...}, 我們無法知道“是否可以把a Dog, a Cat 等加進去”,等之后用到這個方法的時候,我們沒必要去考慮這種問題(前面引號里面的)。

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

不要使用同步的Vector/HashTable/Stack/StringBuffer等。在早期,出于線程安全問題考慮,java API?提供了這些類。但是同步會極大影響性能,即使是在同一個線程中使用他們。

通常可以這樣取代:

ArrayList ?or ?LinkedList ? instead of ?Vector

Deque ?instead of ?Stack

HashMap ?instead of ?Hashtable

StringBuilder ?instead of ?StringBuffer

Exit methods should not be called

盡量不要調(diào)用system.exit()方法。

Local Variables should not be declared and then immediately returned or thrown7

本地變量如果賦值之后直接return了,那就直接return本地變量的賦值語句。

Field names should comply with a naming convention6

命名要規(guī)范

Local variable and method parameter names should comply with a naming convention6

命名要規(guī)范

String literals should not be duplicated5

字符串不應(yīng)該重復(fù),如果多次用到同一字符串,建議將該字符串定義為字符串常量,再引用。

Return of boolean expressions should not be wrapped into an "if-then-else" statement3

不要寫if ( ?a > 4 ?) { ?return false ?} else { return true }這樣的代碼,直接寫return a > 4。

Static non-final field names should comply with a naming convention2

命名要規(guī)范

Modifiers should be declared in the correct order2

修飾符等要按約定俗成的順序書寫 ,例如,寫成public static 而不是static public?

The members of an interface declaration or class should appear in a pre-defined order2

與前面的一個問題類似,根據(jù)Oracle定義的Java代碼規(guī)范中,不同代碼的出現(xiàn)位置應(yīng)該如下所示:

class and instance variables--Constructors--Methods

Array designators "[]" should be on the type, not the variable2

數(shù)組的括號要寫在類型后面,而不是變量后面,例如 int[] a 而不是int a[]

Multiple variables should not be declared on the same line1

不要在同一行定義多個變量

"switch" statements should have at least 3 "case" clauses1

當至少有3種或者3種以上的情況時,才考慮用switch,否則用if/else的形式。

Overriding methods should do more than simply call the same method in the super class1

既然在子類中重寫了父類的某個方法,那就再這個方法中做些與父類方法不同的事情,否則沒必要重寫。

Statements should be on separate lines1

不要把這樣的代碼寫在同一行:if(someCondition) ? ?doSomething();而是應(yīng)該寫成下面的形式

if(someCondition) {

doSomething()

}

Method names should comply with a naming convention1

命名要規(guī)范

"TODO" tags should be handle? ? TODO標簽要及時處理,該做的事情不要忘了做


部分規(guī)則詳細說明

1.The members of an interface declaration or class should appear in a pre-defined order


正確的順序如下所示:靜態(tài)成員變量→成員變量→構(gòu)造器→方法

public class Foo{

public static final int OPEN = 4; ?//Class and instance variables

private int field = 0;

public Foo() {...} ? ?//Constructors

public boolean isTrue() {...} ? ?//Methods

}

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

Noncompliant Code Example:不規(guī)范的示例

List<String> ?strings = new ArrayList<String>();? // Noncompliant

Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();? // Noncompliant

Compliant Solution :規(guī)范的示例

List<String> strings = new ArrayList<>();

Map<String, List<Integer>> map = new HashMap<>();

3.Sections of code should not be "commented out"

代碼片段不應(yīng)該出現(xiàn)在注釋中,這樣會bloat程序,可讀性變差

Programmers should not comment out code as it bloats programs and reduces readability.

Unused code should be deleted and can be retrieved from source control history if required.

4.Utility classes should not have public constructors

工具類不應(yīng)該有public的構(gòu)造器,也就是工具類至少要定義一個non-public的構(gòu)造器

Utility classes, which are a collection of static members, are not meant to be instantiated. Even abstract utility classes, which can be extended, should not have public constructors.

Java adds an implicit public constructor to every class which does not define at least one explicitly. Hence, at least one non-public constructor should be defined.

class StringUtils { // Noncompliant Code Example

? ? public static String concatenate(String s1, String s2) {

? ? ? ? ? return s1 + s2;

? ? }

}

class StringUtils { //Compliant Solution

? ? private StringUtils() {

? ? }

? ? public static String concatenate(String s1, String s2) {

? ? return s1 + s2;

? ? }

}

5."public static" fields should be constant

公共的靜態(tài)成員應(yīng)該加上final來修飾

There is no good reason to declare a field "public" and "static" without also declaring it "final". Most of the time this is a kludge to share a state among several objects. But with this approach, any object can do whatever it wants with the shared state, such as setting it to null.

public static Foo foo = new Foo();//不規(guī)范的

public static final Foo FOO = new Foo();//規(guī)范的

6.Class variable fields should not have public accessibility

public class MyClass {

public static final int SOME_CONSTANT = 0;? ? // Compliant - constants are not checked

public String firstName;? ? ? ? ? ? ? ? ? ? ? // Noncompliant

}

public class MyClass {

public static final int SOME_CONSTANT = 0;? ? // Compliant - constants are not checked

private String firstName;? ? ? ? ? ? ? ? ? ? ? // Compliant

public String getFirstName() {

return firstName;

}

public void setFirstName(String firstName) {

this.firstName = firstName;

}

}

7.Static non-final field names should comply with a naming convention

public final class MyClass {//Noncompliant Code Example

? ? ? private static String foo_bar;

}

class MyClass {//Compliant Solution

private static String fooBar;

}

8."switch" statements should have at least 3 "case" clauses

當有3種或3種情況以上的時候,才用switch,否則用if/else

switch statements are useful when there are many different cases depending on the value of the same expression.

For just one or two cases however, the code will be more readable with if statements.

9.String literals should not be duplicated

prepare("action1"); ? ? // Noncompliant - "action1" is duplicated 3 times

execute("action1");

release("action1");


private static final String ACTION_1 = "action1";? // Compliant

prepare(ACTION_1); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// Compliant

execute(ACTION_1);

release(ACTION_1);

10.Return of boolean expressions should not be wrapped into an "if-then-else" statement

if (expression) {//Noncompliant Code Example

? ? ? return true;

} else {

? ? ?return false;

}


return expression;//Compliant Solution

return !!expression;

11.Method parameters, caught exceptions and foreach variables should not be reassigned

方法參數(shù),捕獲的異常,foreach里的變量,都不應(yīng)該重新賦值


class MyClass {//Noncompliant Code Example:不規(guī)范代碼示例

? ? public String name;

? ? public MyClass(String name) {

? ? ? ? ? ? name = name; ? ? ? ? ?// Noncompliant - useless identity assignment

? ? }

? ? public int add(int a, int b) {

? ? ? ? a = a + b; ? ? ? ? ? ? ? ?// Noncompliant

? ? ? ? return a; ? ? ? ? ? ? ? ? // Seems like the parameter is returned as is, what is the point?

? ?}

? ? public static void main(String[] args) {

? ? ? ? MyClass foo = new MyClass();

? ? ? ? int a = 40;

? ? ? ? int b = 2;

? ? ? ? foo.add(a, b);? ? ? ? ? ? ? ? ? // Variable "a" will still hold 40 after this call

? ? }

}


class MyClass {//Compliant Solution:規(guī)范代碼示例

? ? public String name;

? ? public MyClass(String name) {

? ? ? ? ?this.name = name;? ? ? ? ? ? ? // Compliant

? ? }

? ? public int add(int a, int b) {

? ? ? ? return a + b;? ? ? ? ? ? ? ? ? // Compliant

? ? }

? ? public static void main(String[] args) {

? ? MyClass foo = new MyClass();

? ? ? ? int a = 40;

? ? ? ? int b = 2;

? ? ? ? foo.add(a, b);

? ? ?}

}

12.Local Variables should not be declared and then immediately returned or thrown

Noncompliant Code Example:不規(guī)范代碼示例

public long computeDurationInMilliseconds() {

long duration = (((hours * 60) + minutes) * 60 + seconds ) * 1000 ;

return duration;

}

public void doSomething() {

RuntimeException myException = new RuntimeException();

throw myException;

}


Compliant Solution:規(guī)范代碼示例

public long computeDurationInMilliseconds() {

return (((hours * 60) + minutes) * 60 + seconds ) * 1000 ;

}

public void doSomething() {

throw new RuntimeException();

}

13.Thread.run() and Runnable.run() should not be called directly

The purpose of theThread.run()andRunnable.run()methods is to execute code in a separate, dedicated thread. Calling those methods directly doesn't make sense because it causes their code to be executed in the current thread.

Thread和Runnable里面的run方法設(shè)計的目的是讓run方法里面的代碼在不同的線程中執(zhí)行。如果直接調(diào)用run方法,就會導(dǎo)致run方法里的代碼在當前線程中執(zhí)行,失去意義

Noncompliant Code Example:不規(guī)范的代碼示例

Thread myThread = new Thread(runnable);

myThread.run(); // Noncompliant


Compliant Solution:規(guī)范代碼示例

Thread myThread = new Thread(runnable);

myThread.start(); // Compliant

這部分內(nèi)容為個人理解,可以略過

但在有些情況,也會直接調(diào)用Runnable的run方法,

下面這個postTaskSafely方法會保證task永遠在主線程中執(zhí)行

public static void postTaskInMainThread(Runnable task) {

? ? ?int curThreadId= android.os.Process.myTid();//得到當前線程的id

? ? if(curThreadId==getMainThreadId()) {// 如果當前線程是主線程

? ? ? ? ? ? task.run();//直接執(zhí)行

? ? }else{// 如果當前線程不是主線程

? ? ? ? getMainThreadHandler().post(task);//用主線程的Handler來post

}

14.Lambdas and anonymous classes should not have too many lines

Anonymous classes and lambdas (with Java 8) are a very convenient and compact way to inject a behavior without having to create a dedicated class. But those anonymous inner classes and lambdas should be used only if the behavior to be injected can be defined in a few lines of code, otherwise the source code can quickly become unreadable.

anonymous class number of lines : at most 20

15.Resources should be closed:該關(guān)閉的一定記得關(guān)閉

Java's garbage collection cannot be relied on to clean up everything. Specifically, connections, streams, files and other classes that implement theCloseableinterface or it's super-interface,AutoCloseable, must be manually closed after creation. Failure to do so will result in a resource leak which could bring first the application and then perhaps the box it's on to their knees.

Noncompliant Code Example:不規(guī)范的代碼示例

? ? OutputStream stream = null;

? ? try{

? ? ? ? for (String property : propertyList) {

? ? ? ? stream = new FileOutputStream("myfile.txt");? // Noncompliant

? ? ? ? // ...

? ? ? ? }

? ? }catch(Exception e){

? ? ? ? // ...

? ? }finally{

? ? ? ? stream.close();? // Multiple streams were opened. Only the last is closed.

? ? }


Compliant Solution:規(guī)范代碼示例

? ? OutputStream stream = null;

? ? try{

? ? ? ? stream = new FileOutputStream("myfile.txt");

? ? ? ? for (String property : propertyList) {

? ? ? ? ? ? // ...

? ? ? ? }

? ?}catch(Exception e){

? ? ? ? // ...

? ?}finally{

? ? ? ?stream.close();

? ?}

16.Exception handlers should preserve the original exception

Noncompliant Code Example:不規(guī)范的代碼示例

// Noncompliant - exception is lost

try { /* ... */ } catch (Exception e) { LOGGER.info("context"); }

// Noncompliant - exception is lost (only message is preserved)

try { /* ... */ } catch (Exception e) { LOGGER.info(e.getMessage()); }

// Noncompliant - exception is lost

try { /* ... */ } catch (Exception e) { throw new RuntimeException("context"); }


Compliant Solution:規(guī)范的代碼示例

try { /* ... */ } catch (Exception e) { LOGGER.info(e); }

try { /* ... */ } catch (Exception e) { throw new RuntimeException(e); }

try {

/* ... */

} catch (RuntimeException e) {

doSomething();

throw e;

} catch (Exception e) {

// Conversion into unchecked exception is also allowed

throw new RuntimeException(e);

}

17.Catches should be combined

Since Java 7 it has been possible to catch multiple exceptions at once. Therefore, when multiplecatchblocks have the same code, they should be combined for better readability.

Note?that this rule is automatically disabled when the project'ssonar.java.sourceis lower than7.

Noncompliant Code Example:不規(guī)范代碼示例

catch (IOException e) {

? ? doCleanup();

? ? logger.log(e);

}catch (SQLException e) { //Noncompliant

? ? doCleanup();

? ? logger.log(e);

?}catch (TimeoutException e) {? // Compliant; block contents are different

? ? ?doCleanup();

? ? ?throw e;

?}


Compliant Solution:規(guī)范代碼示例

catch (IOException|SQLException e) {

? ? doCleanup();

? ? logger.log(e);

?}catch (TimeoutException e) {

? ? doCleanup();

? ? throw e;

}

18."entrySet()" should be iterated when both the key and value are needed

Noncompliant Code Example:不規(guī)范的代碼示例

public void doSomethingWithMap(Map map) {

for (String key : map.keySet()) {? // Noncompliant; for each key the value is retrieved

Object value = map.get(key);

// ...

} ??

} ??


Compliant SolutionL:規(guī)范代碼示例

public void doSomethingWithMap(Map map) {

for (Map.Entry entry : map.entrySet()) {

String key = entry.getKey();

Object value = entry.getValue();

// ...

} ??

} ??


以上內(nèi)容是按照自己的理解,整理歸納,錯誤和不當之處,歡迎指出,非常感謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,993評論 19 139
  • NAME dnsmasq - A lightweight DHCP and caching DNS server....
    ximitc閱讀 2,936評論 0 0
  • **2014真題Directions:Read the following text. Choose the be...
    又是夜半驚坐起閱讀 9,949評論 0 23
  • Correctness AdapterViewChildren Summary: AdapterViews can...
    MarcusMa閱讀 8,926評論 0 6
  • 忘記聽哪個家伙講的,又或者是上網(wǎng)有意無意看別人推薦的,這個叫侯勵的家伙趁家中沒有人連夜看完了《桃花期》。還未等他回...
    恕我能閱讀 395評論 0 1