美文网首页Java语言
改善 Java 程序的151个建议之数组和集合(二)

改善 Java 程序的151个建议之数组和集合(二)

作者: AaronSimon | 来源:发表于2019-04-14 12:38 被阅读34次

    1.推荐使用subList处理局部列表

    需求:一个列表100个元素,现在要删除索引位置为20-30的元素,如果使用循环,代码如下:

    public static void main(String[] arg){
        //初始化一个固定长度不可变列表
        List<Integer> initData = Collections.nCopies(100,0);
        //转化为可变列表
        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);
        //转化为可变列表
        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的源码(原因出现在构造参数的修改计数器上)
    • 可以通过list = Collection.unmodiflagList(list)设置原列表为只读状态,避免subList后对原列表的更改
    • 如果subList生成的试图有多个,那么子列表也不可以修改

    3.使用Comparator进行排序

    在Java中要想给数据排序有两种实现方式,一种是实现Comparable接口,一种是实现Comparator接口,这两种有什么区别呢?

    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
        //根据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);
    

    那么我们如果想要按照职位position进行排序,那该怎么办?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使用前必须对列表进行排序,这是二分法的首要条件
    • 对列表排序会打破有规则的业务数据,慎用
    • 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
        //根据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;
            //根据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
    }
    

    为什么结果不一样呢?indexOf是使用equals判断的,binarySearch是通过compareTo方法,而这两个方法并不一致,所以结果不一样

    6.集合运算使用更优雅的方式

    • 并集:list1.addAll(list2)
    • 交集:list1.retainAll(list2)
    • 差集:list1.removeAll(list2)
    • 无重复并集:list2.removeAll(list1);list1.addAll(list2)

    相关文章

      网友评论

        本文标题:改善 Java 程序的151个建议之数组和集合(二)

        本文链接:https://www.haomeiwen.com/subject/dabjwqtx.html