zoukankan      html  css  js  c++  java
  • ListUtils的简单集合操作和原理

    1 Maven依赖

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-collections4</artifactId>
        <version>4.0</version>
    </dependency>
    

    2 ListUtil实现集合的异或功能

    • 集合A(1,2,3)异或 集合B(2,3,4)等于 (1,4)
    @Test
    public void test1() {
        List<Integer> listA = new ArrayList<>();
        listA.add(1);
        listA.add(2);
        listA.add(3);
    
        List<Integer> listB = new ArrayList<>();
        listB.add(2);
        listB.add(3);
        listB.add(4);
    
        long start = System.currentTimeMillis();
        List<Integer> sub1 = ListUtils.subtract(listA, listB); // list1与list2的差集
        List<Integer> sub2 = ListUtils.subtract(listB, listA); // list2与list1的差集
        List<Integer> union = ListUtils.union(sub1, sub2); // sub1与sub2的并集
        long diff = System.currentTimeMillis() - start;
        log.info("sub1:{}", sub1); // sub1:[1]
        log.info("sub2:{}",sub2);  // sub2:[4]
        log.info("runtime:{}ms,unionList:{}", diff, union);// runtime:5ms, unionList:[1, 4]
    }
    

    3 ListUtil源码

    • ListUtils类
    public class ListUtils {    
        // 依赖HashBag类
        public static <E> List<E> subtract(final List<E> list1, final List<? extends E> list2) {
            final ArrayList<E> result = new ArrayList<E>();
            // 涉及HashBag,下面进行讲解
            final HashBag<E> bag = new HashBag<E>(list2);
            for (final E e : list1) {
                if (!bag.remove(e, 1)) {
                    result.add(e);
                }
            }
            return result;
        }
        
        // List的addAll功能
        public static <E> List<E> union(final List<? extends E> list1, final List<? extends E> list2) {
            final ArrayList<E> result = new ArrayList<E>(list1);
            result.addAll(list2);
            return result;
        }
    }
    

    4 Bag接口:背包

    • 从出发点(Bag接口)去思考(HashBag类)具体实现中操作的意思
    • 以一个实际生活的例子做解释:一个放球的背包
    public interface Bag<E> extends Collection<E> {
        // 当object为"红",背包中放了多少红球
        int getCount(Object object);
        // 当object为"蓝",往背包放一个蓝球
        boolean add(E object);
        // 当object为"蓝",往背包放nCopies个蓝球
        boolean add(E object, int nCopies);
        // 当object为"红",把所有红球从背包中取出
        boolean remove(Object object);
        // 当object为"红",把nCopies个红球从背包中取出
        boolean remove(Object object, int nCopies);
        // 背包中有哪几种球:如:1个红 2个蓝 -> 红 蓝
        Set<E> uniqueSet();
        // 总共多少球
        int size();
        // ...省略一些接口
    }
    

    5 HashBag源码与Demo

    • 源码
    public class HashBag<E> extends AbstractMapBag<E> implements Serializable {
       
        public HashBag() {
            super(new HashMap<E, MutableInteger>());
        }
    
        public HashBag(final Collection<? extends E> coll) {
            this();
            super.addAll(coll); // AbstractMapBag的addAll方法
        }
    }
    
    // 内部由一个Map实现
    public abstract class AbstractMapBag<E> implements Bag<E> {
    	/** 用一个Map来放球,key为球,value为数量 */
        private transient Map<E, MutableInteger> map;
        /** 背包有多少球 */
        private int size;
        /** fail fast iterators的安全机制 */
        private transient int modCount;
        /** 有哪几种球的 */
        private transient Set<E> uniqueSet;
    	
        public boolean add(final E object) {
            return add(object, 1);
        }
        
        // 很简单:如果map包含object,则取出value,并加上nCopies;不包含就新建即可。
        public boolean add(final E object, final int nCopies) {
            modCount++;
            if (nCopies > 0) {
                final MutableInteger mut = map.get(object);
                size += nCopies;
                if (mut == null) {
                    map.put(object, new MutableInteger(nCopies));
                    return true;
                }
                mut.value += nCopies;
                return false;
            }
            return false;
        }
        
        // 遍历删除
        public boolean addAll(final Collection<? extends E> coll) {
            boolean changed = false;
            final Iterator<? extends E> i = coll.iterator();
            while (i.hasNext()) {
                final boolean added = add(i.next());
                changed = changed || added;
            }
            return changed;
        }
        
        public boolean remove(final Object object, final int nCopies) {
            final MutableInteger mut = map.get(object);
            if (mut == null)   return false; // 不包含该object则返回false
            if (nCopies <= 0)  return false;
            modCount++;
            if (nCopies < mut.value) { // 如果背包中的数量比删除的数量多则相减
                mut.value -= nCopies;
                size -= nCopies;
            } else { // 如果背包中的数量比删除的数量少则直接删完
                map.remove(object);
                size -= mut.value;
            }
            return true;
        }
        
        // 集合类的toString都需要用到StringBuilder进行append,这样可以提升性能
        public String toString() {
            if (size() == 0) {
                return "[]";
            }
            final StringBuilder buf = new StringBuilder();
            buf.append('[');
            final Iterator<E> it = uniqueSet().iterator();
            while (it.hasNext()) {
                final Object current = it.next();
                final int count = getCount(current);
                buf.append(count);
                buf.append(':');
                buf.append(current);
                if (it.hasNext()) {
                    buf.append(',');
                }
            }
            buf.append(']');
            return buf.toString();
        }
        
        public int getCount(final Object object) {
            final MutableInteger count = map.get(object);
            return count == null ? 0 : count.value;
        }
    
    }
    
    • demo
    @Slf4j // lombok
    public class Main {
        public static void main(String[] args) {
            HashBag<Integer> bag = new HashBag<>();
            bag.add(1);
            bag.add(2);
            bag.add(3);
    
            System.out.println(bag); // [1:1,1:2,1:3] 第一个值为出现次数,第二个value值
            boolean remove2 = bag.remove(2, 1); // 删除2值1次,发现有并删除返回true
            boolean remove4 = bag.remove(4, 1); // 删除4值1次,发现没有返回false
            // remove2:true remove4:false
            log.info("remove2:{} remove4:{}",remove2,remove4);
            System.out.println(bag); // [1:1,1:3]
        }
    }
    

    6 HashCode重写

    • 设计Hash的容器类都需要重写equals方法和hashCode方法来实现自己希望的逻辑,如:HashBag、HashSet或者希望自定义对象作为HashMap的值
    public class Main {
        public static void main(String[] args) {
            Student student1 = new Student("andy", 11,99.5);
            Student student2 = new Student("andy", 11,99.5);
            System.out.println(student1.equals(student2)); // true
    
            Set<Student> set = new HashSet<>();
            set.add(student1);
            set.add(student2);
            System.out.println(set.size()); // 1
        }
    
        @Getter
        @Setter
        static class Student {
            private String name;
            private int age;
            private double score;
    
            public Student(String name, int age,double score) {
                this.name = name;
                this.age = age;
                this.score = score;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (obj == this) return true;
                if (obj.getClass() != this.getClass()) return false;
                Student student = (Student) obj;
                return student.name.equals(this.name)
                        && student.age == this.age
                        && student.score == this.score;
            }
    
            @Override
            public int hashCode() {
                int hash = 17;
                hash = hash * 31 + name.hashCode();
                hash = hash * 31 + age;
                hash = hash * 31 + Double.valueOf(score).hashCode();
                return hash;
            }
        }
    }
    
    • 注意:lombok的@Data注解会自动帮你重写equals和hashCode方法,不需要时请不要使用@Data注解,避免造成不必要的麻烦
  • 相关阅读:
    权重平等分布局And TableRow布局误区
    播放视频的框架Vitamio的使用问题
    Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读
    使用PullToRefresh实现下拉刷新和上拉加载
    如何安全退出已调用多个Activity的Application?
    Stirng,Stringbuffer,Stringbuild的区别浅淡
    python3 logging
    从集合中筛选数据
    python3 模块
    python3 字符串的 maketrans,translate 方法详解
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9810854.html
Copyright © 2011-2022 走看看