編寫高品質代碼:改善Java程式的151個建議 --[78~92]

來源:互聯網
上載者:User

標籤:size   vat   不同   factory   類型   dal   public   耦合   exce   

編寫高品質代碼:改善Java程式的151個建議 --[78~92]HashMap中的hashCode應避免衝突多線程使用Vector或HashTable

Vector是ArrayList的多線程版本,HashTable是HashMap的多線程版本。

非穩定排序推薦使用List

對於變動的集合排序

  1. set=new TreeSet
  2. 使用TreeSet是希望實現自動排序,即使修改也能自動排序,既然它無法實現,那就用List來代替,然後使用Collections.sort()方法對List排序
import java.util.ArrayList;import java.util.SortedSet;import java.util.TreeSet;public class Client69 {    public static void main(String[] args) {        SortedSet<Person> set = new TreeSet<Person>();        // 身高180CM        set.add(new Person(180));        // 身高175CM        set.add(new Person(175));        set.first().setHeight(185);        set=new TreeSet<Person>(new ArrayList<Person>(set));        for (Person p : set) {            System.out.println("身高:" + p.getHeight());        }    }    static class Person implements Comparable<Person> {        // 身高        private int height;        public Person(int _height) {            height = _height;        }        public int getHeight() {            return height;        }        public void setHeight(int height) {            this.height = height;        }        // 按照身高排序        @Override        public int compareTo(Person o) {            return height - o.height;        }    }}
在項目中推薦使用枚舉常量代替介面常量或類常量
enum Season {        Spring, Summer, Autumn, Winter;        public static Season getComfortableSeason(){            return Spring;        }    }
使用建構函式協助描述枚舉項
enum Role {    Admin("管理員", new LifeTime(), new Scope()), User("普通使用者", new LifeTime(), new Scope());    private String name;    private LifeTime lifeTime;    private Scope scope;    /* setter和getter方法略 */    Role(String _name, LifeTime _lifeTime, Scope _scope) {        name = _name;        lifeTime = _lifeTime;        scope = _scope;    }}class LifeTime {}class Scope {}

name:表示的是該角色的中文名稱
lifeTime:表示的是該角色的生命週期,也就是多長時間該角色失效
scope:表示的該角色的許可權範圍

小心switch帶來的null 指標異常在switch的default代碼塊中增加AssertionError錯誤使用valueOf前必須進行校正

枚舉.valueOf(name)
沒有匹配找到指定值報錯:

Exception in thread "main" java.lang.IllegalArgumentException: No enum ...    at java.lang.Enum.valueOf(Unknown Source)

兩種避免的方式:
(1)、使用try......catch捕捉異常

try{       枚舉.valueOf(name)    }catch(Exception e){        e.printStackTrace();        System.out.println("無相關枚舉項");    }

(2)、擴充枚舉類

enum Season {        Spring, Summer, Autumn, Winter;        // 是否包含指定的枚舉項        public static boolean isContains(String name) {            // 所有的枚舉值            Season[] season = values();            for (Season s : season) {                if (s.name().equals(name)) {                    return true;                }            }            return false;        }    }
用枚舉實現Factory 方法模式更簡潔

枚舉非靜態方法實現Factory 方法模式

enum CarFactory {    // 定義生產類能生產汽車的類型    FordCar, BuickCar;    // 生產汽車    public Car create() {        switch (this) {        case FordCar:            return new FordCar();        case BuickCar:            return new BuickCar();        default:            throw new AssertionError("無效參數");        }    }}

通過抽象方法產生產品

enum CarFactory {    // 定義生產類能生產汽車的類型    FordCar{        public Car create(){            return new FordCar();        }    },    BuickCar{        public Car create(){            return new BuickCar();        }    };    //抽象生產方法    public abstract Car create();}

使用枚舉類型的Factory 方法模式三個優點:

  1. 避免錯誤調用的發生:一般Factory 方法模式中的生產方法(也就是createCar方法),可以接收三種類型的參數:型別參數(如我們的例子)、String參數(生產方法中判斷String參數是需要生產什麼產品)、int參數(根據int值判斷需要生產什麼類型的的產品),這三種參數都是寬泛的資料類型,很容易發生錯誤(比如邊界問題、null值問題),而且出現這類錯誤編譯器還不會警示。
  2. 效能好,使用簡潔:枚舉類型的計算時以int類型的計算為基礎的,這是最基本的操作,效能當然會快,至於使用便捷,注意看用戶端的調用。
  3. 降低類間耦合:不管生產方法接收的是Class、String還是int的參數,都會成為用戶端類的負擔,這些類並不是用戶端需要的,而是因為Factory 方法的限制必須輸入的,例如Class參數,對用戶端main方法來說,他需要傳遞一個FordCar.class參數才能生產一輛福特汽車,除了在create方法中傳遞參數外,業務類不需要改Car的實作類別。這嚴重違背了迪米特原則(Law of Demeter 簡稱LoD),也就是最少知識原則:一個對象應該對其它對象有最少的瞭解。
    而枚舉類型的Factory 方法就沒有這種問題了,它只需要依賴工廠類。
枚舉項的數量限制在64個以內

 為了更好地使用枚舉,Java提供了兩個枚舉集合:EnumSet和EnumMap,這兩個集合使用的方法都比較簡單,EnumSet表示其元素必須是某一枚舉的枚舉項,EnumMap表示Key值必須是某一枚舉的枚舉項,由於枚舉類型的執行個體數量固定並且有限,相對來說EnumSet和EnumMap的效率會比其它Set和Map要高。
當枚舉項數量小於等於64時,建立一個RegularEnumSet執行個體對象,大於64時則建立一個JumboEnumSet執行個體對象。
枚舉項數量不要超過64,否則建議拆分。

import java.util.EnumSet;public class EnumSetTest {    //普通枚舉項,數量等於64    enum Const{        A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,        AA,BB,CC,DD,EE,FF,GG,HH,II,JJ,KK,LL,MM,NN,OO,PP,QQ,RR,SS,TT,UU,VV,WW,XX,YY,ZZ,        AAA,BBB,CCC,DDD,EEE,FFF,GGG,HHH,III,JJJ,KKK,LLL    }    //大枚舉,數量超過64    enum LargeConst{        A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,        AA,BB,CC,DD,EE,FF,GG,HH,II,JJ,KK,LL,MM,NN,OO,PP,QQ,RR,SS,TT,UU,VV,WW,XX,YY,ZZ,        AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH,IIII,JJJJ,KKKK,LLLL,MMMM    }    public static void main(String[] args) {        EnumSet<Const> cs = EnumSet.allOf(Const.class);        EnumSet<LargeConst> lcs = EnumSet.allOf(LargeConst.class);        //列印出枚舉數量        System.out.println("Const的枚舉數量:"+cs.size());        System.out.println("LargeConst的枚舉數量:"+lcs.size());        //輸出兩個EnumSet的class        System.out.println(cs.getClass());        System.out.println(lcs.getClass());    }}

allOf調用noneOf

public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {        //產生一個空EnumSet        EnumSet<E> result = noneOf(elementType);        //加入所有的枚舉項        result.addAll();        return result;    }
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {       //獲得所有的枚舉項       Enum[] universe = getUniverse(elementType);       if (universe == null)           throw new ClassCastException(elementType + " not an enum");       //枚舉數量小於等於64       if (universe.length <= 64)           return new RegularEnumSet<>(elementType, universe);       else            //枚舉數量大於64           return new JumboEnumSet<>(elementType, universe);   }
注意@Override不同版本的區別
interface Foo {    public void doSomething();}class FooImpl implements Foo{    @Override    public void doSomething() {            }}

這段代碼在Java1.6版本上編譯沒問題,雖然doSomething方法只是實現了介面的定義,嚴格來說並不是覆寫,但@Override出現在這裡可減少代碼中出現的錯誤。

可如果在Java1.5版本上編譯此段代碼可能會出現錯誤:The method doSomeThing() of type FooImpl must override a superclass method。

Java1.5版本的@Override是嚴格遵守覆寫的定義:子類方法與父類方法必須具有相同的方法名、輸出參數、輸出參數(允許子類縮小)、存取權限(允許子類擴大),父類必須是一個類,不能是介面,否則不能算是覆寫。而這在Java1.6就開放了很多,實現介面的方法也可以加上@Override註解了,可以避免粗心大意導致方法名稱與介面不一致的情況發生。
Java1.6版本的程式移植到1.5版本環境中,就需要刪除實現介面方法上的@Override註解。

編寫高品質代碼:改善Java程式的151個建議 --[78~92]

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.