改善 Java 程序的151個建議之?dāng)?shù)組和集合(二)

1.推薦使用subList處理局部列表

需求:一個列表100個元素,現(xiàn)在要刪除索引位置為20-30的元素,如果使用循環(huán),代碼如下:

public static void main(String[] arg){
    //初始化一個固定長度不可變列表
    List<Integer> initData = Collections.nCopies(100,0);
    //轉(zhuǎn)化為可變列表
    List<Integer> list = new ArrayList<Integer>(initData);
    //遍歷
    for(int i=0;i < list.seze)();i++){
        if(i>=20 && i <30){
            list.remove(i);
        }
    }
}

其實我們可以使用subList來處理

public static void main(String[] arg){
    //初始化一個固定長度不可變列表
    List<Integer> initData = Collections.nCopies(100,0);
    //轉(zhuǎn)化為可變列表
    List<Integer> list = new ArrayList<Integer>(initData);
    
    list.subList(20,30).clear();
}

subList返回的是原始列表的一個試圖,輸出這個視圖中的所有元素最終會反映到原始列表

2.生成子列表后不要再操作原列表

public static void main(String[] arg){
    List<Integer> srcList = new ArrayList<>();
    srcList.add("a");
    srcList.add("b");
    srcList.add("c");
    
    List<Integer> subList = srcList.subList(0,2);
    //操作原列表 
    srcList.add("D");
    
    System.out.println("原列表長度:"+srcList.size());
    System.out.println("子列表長度:"+subList.size());
}

運行在subList.size()處報錯

  • 原列表變化后,subList取出的這子列表不會生成新的列表,詳細可查看subList的源碼(原因出現(xiàn)在構(gòu)造參數(shù)的修改計數(shù)器上)
  • 可以通過list = Collection.unmodiflagList(list)設(shè)置原列表為只讀狀態(tài),避免subList后對原列表的更改
  • 如果subList生成的試圖有多個,那么子列表也不可以修改

3.使用Comparator進行排序

在Java中要想給數(shù)據(jù)排序有兩種實現(xiàn)方式,一種是實現(xiàn)Comparable接口,一種是實現(xiàn)Comparator接口,這兩種有什么區(qū)別呢?

public class Employee implements Comparable<Employee>{
    private int id;
    private String name;
    private Postion position;
    public Employee(int _id,String _name,Position _position){
        this.id = _id;
        this.name= _name;
        this.position = _position;
    }
    //省略getter,setter
    //根據(jù)id進行排序
    @Override
    public int compareTo(Employee o){
        return new CompareToBuilder().append(id,o.id).toComparison();
    }
    
    @Override
    public String toString(){
        return ToStringBuilder.reflectionToString(this);
    }
    
}
public enum Position(){
    Boss,Manager,Staff
}

排序

List<Empoyee> list = new ArrayList<>();
//添加元素省略
//按照id排序
Collection.sort(list);

那么我們?nèi)绻胍凑章毼籶osition進行排序,那該怎么辦?Collection.sort有一個重載的方法Collection.sort(List<T> list,Comparator<? super T> c),代碼如下:

class PositionComparator implements Comparator<Employee>{
    @Override
    public int compare(Employee o1,Employee o2){
        return o1.getPosition().compareTo(o2.getPosition());
    }
}

那么倒序排列是否也要重寫排序器?不用

  • 直接使用Collection.reverse(List<?> list)
  • 通過Collection.sort<list,Collections.reverseOrder(new PositionComparator)>

那么如果職位相同再按照id排序該怎么處理:

public int compareTo(Employee o){
    return new CompareToBuilder
    .append(position,o.position).toComparison()
    .append(id,o.id).toComparison();
}

4.不推薦使用binarySearch對列表進行檢索

Collections.binarySearch:使用二分搜索法收縮指定列表以獲取指定對象,其功能與indexOf是相同的。但是使用binarySearch需要注意:

  • binarySearch使用前必須對列表進行排序,這是二分法的首要條件
  • 對列表排序會打破有規(guī)則的業(yè)務(wù)數(shù)據(jù),慎用
  • binarySearch在性能上相比indexOf是最好的選擇

5.集合中的元素必須做到compareTo與equals同步

public class city implements Comparable<city>{
    private int code;
    private String name;
    public Employee(int _code,String _name){
        this.id = _id;
        this.name= _name;
    }
    //省略getter,setter
    //根據(jù)name進行排序
    @Override
    public int compareTo(Employee o){
        return new CompareToBuilder().append(name,o.name).toComparison();
    }
    
    @Override
    public boolean equals(Object obj){
        if(onj == null){
            return false;
        }
        if(obj == this){
            return true;
        }
        if(obj.getClass() != getClass()){
            return false;
        }
        City city = (City) obj;
        //根據(jù)code判斷是否相等
        return new EqualsBuilder().append(code,city.code).isEquals();
    }
    
    @Override
    public String toString(){
        return ToStringBuilder.reflectionToString(this);
    }
    
}
public static void main(String[] arg){
    List<Integer> cities = new ArrayList<>();
    cities.add(new City("021","上海"));
    cities.add(new City("021","滬"));
    
    //排序
    Collections.sort(cities);
    
    //查找對象
    City city = new City("021","滬");
    List<Integer> subList = srcList.subList(0,2);
    //indexOf取得索引值
    int index1 = cities.indexOf(city);
    //binarySearch取得索引值
    int index2 = Collections.binarySearch(cities.city);
    
    
    System.out.println("indexOf取得索引值:"+ index1);// 0
    System.out.println("binarySearch取得索引值index2);// 1
}

為什么結(jié)果不一樣呢?indexOf是使用equals判斷的,binarySearch是通過compareTo方法,而這兩個方法并不一致,所以結(jié)果不一樣

6.集合運算使用更優(yōu)雅的方式

  • 并集:list1.addAll(list2)
  • 交集:list1.retainAll(list2)
  • 差集:list1.removeAll(list2)
  • 無重復(fù)并集:list2.removeAll(list1);list1.addAll(list2)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容