美文网首页
十、集合

十、集合

作者: blank_white | 来源:发表于2020-07-19 20:58 被阅读0次

十、集合

ArrayList 一种可以动态增长和缩减的索引序列
LinkedList 一种可以在任何位置进行高效地插人和删除操作的有序序列
ArrayDeque 一种用循环数组实现的双端队列
HashSet 一种没有重复元素的无序集合
TreeSet —种有序集
EnumSet 一种包含枚举类型值的集
LinkedHashSet 一种可以记住元素插人次序的集
PriorityQueue 一种允许高效删除最小元素的集合
HashMap 一种存储键 / 值关联的数据结构
TreeMap —种键值有序排列的映射表
EnumMap 一种键值属于枚举类型的映射表
LinkedHashMap 一种可以记住键 / 值项添加次序的映射表
WeakHashMap 一种其值无用武之地后可以被垃圾回收器回收的映射表
IdentityHashMap 一种用 = 而不是用 equals 比较键值的映射表
Collection
import org.example.Size;
import org.junit.Before;
import org.junit.Test;

import java.util.*;

public class CollectionTest {


    Collection collection;
    Collection A;
    Collection B;
    @Before
    public void b(){
        collection=new ArrayList();
        for (int i = 0; i < 5; i++) {
            collection.add(i);
        }
        A=new ArrayList();
        for (int i = 0; i < 5; i++) {
            A.add(i);
        }
        B=new ArrayList();
        for (int i = 4; i < 7; i++) {
            B.add(i);
        }
    }

    /**
     *  collection 的基本遍历
     */
    @Test
    public void t1(){


        collection.iterator().forEachRemaining( o -> System.out.print(o));
        System.out.println();
        collection.iterator().forEachRemaining( System.out::print);
        System.out.println();

        Iterator<Integer> iterator=collection.iterator();
        while (iterator.hasNext()){
            Integer i=iterator.next();
            if (i==2)iterator.remove();
            System.out.print(i);
        }
        System.out.println();
        for (Object o :collection){
            System.out.print(o);
        }
        
        System.out.println();
        collection.forEach(o -> {
            System.out.print(o);
        });
    }

    /**
     * collection 常用方法
     */
    @Test
    public void t2(){
        // 集合大小
        System.out.println(collection.size());
        // 集合是否为空
        System.out.println(collection.isEmpty());
        // 集合是否包含对象
        System.out.println(collection.contains(3));
        // 集合是否包含集合
        System.out.println(collection.containsAll(new ArrayList<>()));


        //可以看到这个方法改变了集合A中的元素,将存在于集合A中但不存在于集合B中的元素移除。
        //如果集合A的大小发生了改变,返回true,即使两个集合完全没有交集,也会返回true。
        //如果集合A的大小没有发生改变,返回false,即使两个集合完全相同,也会返回false。
        A.retainAll(B);

        // 注意这里是 Collection collection,A,B  名字没起好
        collection.remove(1);
        collection.removeAll(A);
        collection.addAll(A);
        
        
        
        System.out.println(collection);  // [0, 2, 3, 4]
        Integer[] integers=new Integer[6];
        // 集合转数组
        Object[] integers2=collection.toArray(integers);
        // Arrays.toString ,按一定格式将数组转化成字符串的
        System.out.println(Arrays.toString(integers)); // [0, 2, 3, 4, null, null]
        System.out.println(Arrays.toString(integers2));// [0, 2, 3, 4, null, null]

        Object[] integers3=  collection.toArray();
        System.out.println(Arrays.toString(integers3));// [0, 2, 3, 4]

        
        
        // 清空 
        collection.clear();
    }
    
}

集合转数组部分订正

        
        // 列表转换数组,
        // 数组类型不能强制转换,Object数组 类 和 Integer数组 类 是无法互相转换的
        // 这样用的时候不方便操作,   (Integer)obejects[0]
        Object[] objects=list.toArray();

       
        Integer[] nums2;
        // 可以传入一个指定类型的数组 将返回同类型数组
        // 如果传入数组长度不够,会新建一个同类型数组并返回
        nums2=list.toArray(new Integer[0]);
        // 如果传入数组长度够用,则直接填入到这个数组中并返回
        nums2=list.toArray(new Integer[10]);
LinkList
import org.junit.Test;

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

public class ListTest {

    @Test
    public void t1(){
        List<Integer> list=new LinkedList<>();
        for (int i = 0; i < 5; i++) {
            list.add(i);
        }

        ListIterator<Integer> iterator=list.listIterator();

        ///  以下都是 函数生效前 游标位置
        // next     返回游标 后面的元素,同时游标右移  之后如果使用 remove/set 操作的是 游标左侧元素
        // previous 返回游标 前面的元素,同时游标左移  之后如果使用 remove/set 操作的是 游标右侧元素
        // nextIndex返回游标 后面的元素位置
        // public int previousIndex() { return nextIndex - 1;}
        // previousIndex返回游标 前面的元素位置 = 后面的元素位置-1
        System.out.println(iterator.previousIndex());// -1
        System.out.println(iterator.nextIndex()); //0
        System.out.println(iterator.next()); // 0
        iterator.add(7);                     //
        System.out.println(iterator.next());// 1  在添加元素后 iterator previous() 是刚添加的元素,next() 是 刚添加的元素后面的元素
        System.out.println(iterator.previous());// 1
        iterator.remove();
        System.out.println(iterator.next()); // 2
        System.out.println(iterator.nextIndex());// 3       0 7 2 | 3  游标在这个位置


        iterator.set(6);

        iterator.hasNext();
        iterator.hasPrevious();

        System.out.println("*************");
        iterator=list.listIterator();
        for (int i = 0; i < 20; i++) {
            if (iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }

        System.out.println(list.get(1));

        // 元素第一次出现的位置 没有找到返回 -1
        System.out.println(list.indexOf(4));
        // 元素最后一次出现的位置 没有找到返回 -1
        System.out.println(list.lastIndexOf(4));
        
        LinkedList<Integer> list2=new LinkedList<>();
        list2.addFirst(1);
        list2.addLast(3);
        list2.getFirst();
        list2.getLast();
        list2.removeFirst();
        list2.removeLast();
        
    }
}

ArrayList

Vector 也可以实现动态数组

Vector 所有方法都是同步的,耗时

ArrayList 所有方法都是不同步的

HashSet
  • 桶:收集具有相同散列值的数据结构,具有相同散列值得放在一个桶里

  • 桶数:桶的数目,通常将桶的数目设置为预计元素个数的 75%~150%

  • 填装因子:(默认为 0.75) 当表中超过 75% 的位置已经被填充,就会用双倍的桶数进行再散列

  • 再散列:重新创建一个桶数更多的表,将原表元素插入新表,并舍弃旧的表

Map 的 key 是唯一的,从 HashSet 的源码中可以看到,HashSet 实际上是使用了 HashMap 的 key 作为元素

注释中说明了默认的 桶数为 16 ,填装因子为 0.75


    /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }

常用方法


        HashSet<String> hashSet=new HashSet<>();

        //  public HashSet(Collection<? extends E> c) {
        //  将集合全部元素添加到散列集
        new HashSet<String>(new ArrayList<String>());

        // 设置桶数
        new HashSet<String>(16);
        // 设置桶数和填装因子
        new HashSet<String>(16,0.75f);


        // 添加元素
        hashSet.add("zs");
        hashSet.add("ls");
        hashSet.add("zs");
        // 是否包含元素
        hashSet.contains("zs");
        hashSet.remove("zs");

        //
        // 对于要存于 散列集的对象要重写 hashCode() 方法 和 equals() 方法,
        // 并且要保证 若果 x.equals(y) 为 true 那么 x.hashCode()==y.hashCode 为true
        //
        "zs".hashCode();

        hashSet.iterator().forEachRemaining(System.out::println);

特点:

  • 集合元素可以是null,但只能放入一个null
  • 不是同步的
TreeSet
        // TreeSet 中的元素 在遍历时,是按顺序排列的,当前是使用 红黑树 实现的
        // TreeSet 实现了 SortedSet 接口
        // 使用树集  元素必须实现 Comparable 接口,(元素不能比较的话,没办法排序的),或者 new 的时候传入比较器
        TreeSet<String> set=new TreeSet<>();

        set.add("john");
        set.add("bob");
        set.add("carlos");
        set.add("bob");
        set.add("a");
        set.add("z");

        // 遍历
        for (String s : set) {
            System.out.println(s);
        }

        set.iterator().forEachRemaining(System.out::println);


        // 常用方法
        set.first();
        set.last();

        // NavigableSet 接口的方法
        // 返回 比  bz 大的元素中 最小的
        System.out.println(set.higher("bz"));  // carlos
        // 返回 比  bz 小的元素中 最大的
        System.out.println(set.lower("bz"));   // bob

        // 返回 比  bob 大或等于的元素中 最小的
        System.out.println(set.ceiling("bob"));
        // 返回 比  bob 小或等于的元素中 最大的
        System.out.println(set.floor("bob"));

        // 删出最小元素并返回
        set.pollFirst();
        // 删出最大元素并返回
        set.pollLast();

        System.out.println("*********");
        //  descendingIterator() 返回一个反向迭代器,用于逆序遍历
        set.descendingIterator().forEachRemaining(System.out::println);
Queue
  • 双端队列 Deque

    左往右的队列操作,右往左也支持

  • 优先级队列 PriorityQueue

    可以以任意顺序插入,但是始终是按顺序检索

    使用数据结构 堆(heap):一个可以自我调整的二叉树

常用方法

        Queue<Integer> queue=new ArrayDeque<>();
        queue.add(999);


        // 以下方法,每组 前面的 出错抛出异常,后面的 返回 false 或者 null

        // 添加元素 ,队列满了则无法添加
        queue.add(1); //抛出异常
        queue.offer(2); // 返回 false


        // 移除并返回头部元素
        queue.remove();
        queue.poll();

        // 返回头部元素,但不删除
        queue.element();
        queue.peek();
        
        
        // 双端队列
        // public interface Deque<E> extends Queue<E> {
        // ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>
        Deque<Integer> deque=new ArrayDeque<>();
        deque.add(999);

        // 头插 和  尾插
        deque.addFirst(1);  // 出错抛出异常
        deque.addLast(2);
        deque.offerFirst(3); // 出错返回 false
        deque.offerLast(4);

        // 移除并返回头/尾部元素
        deque.removeFirst();
        deque.removeLast();
        deque.pollFirst();
        deque.pollLast();


        // 返回头/尾部元素,但不删除
        deque.getFirst();
        deque.getLast();
        deque.peekFirst();
        deque.peekLast();

        // 设置初始容量,无参构造器 默认为 16
        // ArrayQueue 在满了的时候能自动扩充容量
        Queue<Integer> queue2=new ArrayDeque(8);


        // 优先级队列
        // 元素可以按任意顺序插入,但是总是按照排序的顺序进行检索
        // 使用了 数据结构 堆 (heap 一个可以自我调整的二叉树)
        // PriorityQueue<E> extends AbstractQueue<E>
        // AbstractQueue<E> extends AbstractCollection<E> implements Queue<E>
        Queue<Integer> queue3=new PriorityQueue<>();
        queue3.add(9);
        queue3.add(8);
        queue3.add(2);
        queue3.add(7);
        System.out.println(queue3); // [2, 7, 8, 9]

HashMap
Map<Integer,String> map=new HashMap<>();
        map.put(1,"1zs");
        map.put(2,"2ls");
        String name;
        name=map.get(1);
        // 获取失败时,用 无名氏 当作默认值返回
        name=map.getOrDefault(99,"无名氏");

        map.put(2,"2ls cover");

        //  void putAll(Map<? extends K, ? extends V> m);
        map.putAll(new HashMap<>());

        boolean b;
        // 查看 是否包含 键
        b=map.containsKey(1);
        // 查看 是否包含 值
        b=map.containsValue("2ls");

        // 对map中每组 键值对 都执行 某操作
        map.forEach((k,v)->{
            System.out.println("key "+ k+" : "+v);
        });

        new HashMap<>();
        // 初始化时设置桶数,和 Set 相同
        new HashMap<>(16);
        // 初始化时设置桶数和填装因子
        new HashMap<>(16,0.75f);
TreeMap

能自动按键排序的 Map


        TreeMap<Integer,String> treeMap=new TreeMap<>();

        // public TreeMap(Comparator<? super K> comparator) {
        // 注意 是  Comparator  不是  Comparable
        // 是  tor !  不是  able!
        // 可以传入一个比较器,作为 key 的比较方法,可以用 lambda 表达式写法,也可以 匿名类 或者写一个实现接口的类
        new TreeMap<Integer,String>((a,b)->{return 1;});
        
        treeMap.put(3,"3ww");
        treeMap.put(1,"1zs");
        treeMap.put(2,"2ls");
        treeMap.put(2,"2ls cover");


        // SortedMap 接口的方法
        // 返回最小 key 和 最大 key
        treeMap.firstKey();
        treeMap.lastKey();

        // 当原先 key 对应 value 不存在时 才放入新 value
        treeMap.putIfAbsent(1,"1 putIfAbsent");


        // 参数 1 key
        // 参数 2 新值
        // 参数 3 处理旧值和新值 的过程
        // get(key) 为 null 时,直接将参数 2 作为新value
        // 不为空的时候 用参数 3 处理 原value 和 参数 2 ,结果作为新value
        // 如果参数 3 处理结果为 null 则移除value 即 remove(key)
        // 不为空则  put(key ,newValue)
        // 详情见源码
        treeMap.merge(1,"merger",String::concat);  // 1:1zsmerger

        treeMap.merge(4,"--merger",(a,b)->{return a+b+"lambda";});// 4:--merger

        // 将 key 和 value 做一定处理 作为新的 value
        // 及时 get(key) 为空也会处理
        // 处理结果为 null 则会移除 remove(key)
        // 不为空则  put(key ,newValue)
        treeMap.compute(3,(k,v)->{return k+v+"lambda";}); // 3:33wwlambda

        treeMap.compute(9,(k,v)->{ return k+v+"lambda";});// 9:9nulllambda

        // 当 key 对应值 不为 null 时才做处理,否则直接返回
        treeMap.computeIfPresent(10,(k,v)->{ return k+v+"computeIfPresent";});

        // 当 key 对应值 为 null 时才做处理
        treeMap.computeIfAbsent(11,(k)->{ return k+"computeIfPresent";});


        // 将所有映射 都用函数处理
        treeMap.replaceAll((k,v)->{ return v;});

        treeMap.forEach((k,v)-> System.out.println(k+":"+v));

        System.out.println(null+"-hello"); // 输出 null-hello
Map映射视图
map.keySet();
map.values();
map.entrySet();

对 Map 做映射方便做一些操作,有点像 SQL 的视图

对三种映射视图通过 iterator 做 remove() 操作,都会同时影响到原 map

若能修改视图,则也会使 原来的 map 做出相应的修改

但是都不能使用 add() 方法,会抛异常

        Map<Integer,String> map=new HashMap<>();
        map.put(2,"2ls");
        map.put(3,"3ww");
        map.put(1,"1zs");
        map.put(4,"4zl");

        // 返回 键 集
        Set<Integer> integers = map.keySet();
        // 返回 值 的集合
        Collection<String> values = map.values();
        // 返回  键值组合的结构 Entry 的集
        Set<Map.Entry<Integer, String>> entries = map.entrySet();

        // 1=1zs
        // 2=2ls
        // ··········
        // 输出结果如上, toString() 方法会将  key 和  value 中间以等号拼接
        // static class Node<K,V> implements Map.Entry<K,V> {
        //       public final String toString() { return key + "=" + value; }
        entries.forEach(System.out::println);

        //  在键集视图上,用迭代器 remove() 方法删除键,会删除原来 map 中对应的 键和值
        Iterator iterator=integers.iterator();
        while (iterator.hasNext()){
            Integer i= (Integer) iterator.next();
            if (i==2){
                iterator.remove();
            }
        }


        //  在值集合视图上,用迭代器 remove() 方法删除键,会删除原来 map 中对应的 键和值
        Iterator<String> iterator2 = values.iterator();
        while (iterator2.hasNext()){
            String next = iterator2.next();
            if ("1zs".equals(next)){
                iterator2.remove();
            }
        }


        // 在键值集视图上,用迭代器 remove() 方法删除键,会删除原来 map 中对应的 键和值
        // 修改键对应的值,会使原来的 map 被相应的修改
        Iterator<Map.Entry<Integer, String>> iterator3 = entries.iterator();
        while (iterator3.hasNext()){
            Map.Entry<Integer, String> next = iterator3.next();

            if (3==next.getKey()){
                next.setValue("通过 Entry 被修改了");
            }
            if (4==next.getKey()){
                iterator3.remove();
            }


        }

        // map 中的 1 2 4 都被 被删除了
        // 键 3对应的值被修改为 : 3通过 Entry 被修改了
        map.forEach((k,v)-> System.out.println(k+v));

        // 三种映射视图都不能使用 add() 方法,会抛异常
        //integers.add(5);
        //values.add("5");
        //entries.add(null);

weakHashMap弱散列映射

能与垃圾回收器协同工作的 Map


        // WeakHashMap 使用弱引用保存键
        // 当对键的唯一引用,来自散列条目时,这一数据结构将与垃圾回收器协同工作,一起删除键值对
        WeakHashMap<Integer, String> weakHashMap = new WeakHashMap<>();

        // WeakHashMap 不是线程安全的 ,在并发场景下使用,可以使用  Collections.synchronizedMap(weakHashMap);
        // Map<Integer, String> map = Collections.synchronizedMap(weakHashMap);
        weakHashMap.put(1,"1zs");
        weakHashMap.put(2,"2zs");

LinkedHashSet LinkedHashMap

能按顺序(插入顺序或受影响顺序)遍历的 HashSet 和 HashMap


        // LinkedHashMap 会记住数据插入的顺序,可以按插入顺序迭代
        LinkedHashMap<Integer,String>  linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put(1,"1zs");
        linkedHashMap.put(3,"3zs");
        linkedHashMap.put(2,"2zs");
        linkedHashMap.put(4,"4zs");

        // 1 3 2 4
        linkedHashMap.forEach((k,v)->{System.out.println(k+" : "+v);});



        // 第三个参数  accessOder 默认为false,若设置为true ,
        // 则每当 调用get 或 put ,会将受影响的条目从当前位置移除,放置到条目链表的尾部
        // 这种特性可以应用于高速缓存的最近最少用原则,最前面的元素说明最近没有访问,有新数据要加入缓存可以移除靠前面的元素
        linkedHashMap = new LinkedHashMap<Integer,String>(16,0.75f,true);
        linkedHashMap.put(1,"1zs");
        linkedHashMap.put(3,"3zs");
        linkedHashMap.put(2,"2zs");
        linkedHashMap.put(4,"4zs");
        linkedHashMap.get(1);
        linkedHashMap.get(2);
        linkedHashMap.get(3);
        linkedHashMap.get(4);
        // 1 2 3 4
        linkedHashMap.forEach((k,v)->{System.out.println(k+" : "+v);});



        // 会记住插入顺序的 集,会以插入顺序进行遍历
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("1zs");
        linkedHashSet.add("3zs");
        linkedHashSet.add("2zs");
        linkedHashSet.add("4zs");
        linkedHashSet.contains("3zs");
        // 1 3 2 4
        linkedHashSet.forEach(System.out::println);

EnumSet EnumMap

针对枚举类型作为 集的元素 或者 Map 的 key 时

一种高效的 Set 和 Map

        // EnumSet 是 枚举类型 的集的高效实现
        // 没有 public 构造方法,需要使用静态工厂方法构造集

        EnumSet<Size> sizes ;
        // 返回一个包含所有枚举值的集
        sizes= EnumSet.allOf(Size.class);
        // 返回一个空集
        sizes= EnumSet.noneOf(Size.class);
        // 返回一个从 x 到 x 的枚举值的集
        sizes=EnumSet.range(Size.SMALL,Size.LARGE);
        // 返回一个包含 参数 1 ,参数 2,参数 3 ··· 的枚举值得值
        sizes=EnumSet.of(Size.SMALL,Size.LARGE);
        sizes.forEach(System.out::println);


        // EnumMap 是一个键类型是枚举类型的 map,它直接高效的用数组实现
        // 构造时需要指定键的枚举类型
        EnumMap<Size, Object> enumMap = new EnumMap<>(Size.class);
IdentityHashMap

根据对象的内存来判断 key 是否一致的 Map

        // IdentityHashMap
        // 这个类中键的散列值是使用 System.identityHashCode(Object o) 计算,(一种根据对象的内存地址来计算散列码的方式)
        // 而不是 hashCode()
        // 对象比较的时候,使用的是 == 而不是 equals

        String a="abcd";
        String b= "ab";

        // 避免 编译器优化,使 a,b 有不同的内存地址
        if (a.equals("abcd")){
            b+="cd";
        }

        System.out.println(a==b); //false
        System.out.println(a.equals(b));// true
        System.out.println(System.identityHashCode(a)==System.identityHashCode(b));//false


        IdentityHashMap<String,Integer> identityHashMap=new IdentityHashMap<>();
        identityHashMap.put(a,1);
        identityHashMap.put(b,2);


        identityHashMap.forEach((k,v)->{
            System.out.println(k+":"+v);
        });

        /*
        输出结果
        false
        true
        false
        abcd:1
        abcd:2
*/
视图与包装器

类似 HashMap 的 keySet() values() 还有一些其他视图

轻量级集合包装器
  • 数组包装成 List : Arrays.asList()
        // List = Arrays.asList()  可以修改数据,不能改变数组大小(不能对list添加删除)
        String[] strings={"1zs","2ls","3ww"};
        List<String> list = Arrays.asList(strings);

        list.set(0,"1-set");
        list.get(0);

        // 输出  1-set  2ls  3ww
        list.forEach(s -> {System.out.println(s);});
        //  [1-set, 2ls, 3ww]
        System.out.println(Arrays.toString(strings));

        // 任何改变 数组大小的操作如 add remove 都会抛出异常
        //list.add("ss");
  • 单一元素


        // List = Collections.nCopies(重复次数,要重复的Object)
        // 不允许修改数据
        List<String> list2 = Collections.nCopies(15, "你好");
        // 输出 15 组你好
        list2.forEach(System.out::print);
        System.out.println();

        // 不允许修改数据
        //list2.set(2,"不好");

        // 不允许改变
        //list2.add("xx");

        // 获得一个单一的元素集、列表、映射
        Set<String> singleton = Collections.singleton("1");
        List<String> singletonList = Collections.singletonList("1");
        Map<Integer, String> singletonMap = Collections.singletonMap(1, "1");
子范围
  • List 子范围

    获得一个范围内的子列表

        // List 子范围  List.subList(int fromIndex, int toIndex);
        // 可以将任何操作应用到子范围(包括 remove add)
        List<Integer> list3=new LinkedList<>();
        list3.add(1);
        list3.add(2);
        list3.add(3);
        list3.add(4);

        // 返回一个索引从 参数 1 (包括此索引) ,到 参数 2 (不包括此索引) 的 List
        // 用函数定义域理解就是 [ 1 ,3 )
        List<Integer> list4 = list3.subList(1, 3);

        list4.clear(); //  list3:[1,  4]
        list4.add(6);  //  list3:[1, 6, 4]

        System.out.println(list3);
  • SortedSet 子范围

    获得一个范围内的子元素集

// SortedSet 子范围
// 可以在 子范围内进行操作
SortedSet<String> sortedSet = new TreeSet<>();
sortedSet.add("az");
sortedSet.add("za");
sortedSet.add("gg");

// 返回 大于等与参数1 小于 参数2 的元素子集
// ["bb" ,"qq")
SortedSet<String> sortedSet2 = sortedSet.subSet("bb", "qq");
System.out.println(sortedSet2);// [gg]
sortedSet2.remove("gg");   // sortedSet:[az, za]

// 可以在子范围内操作 添加
sortedSet2.add("qa");  // sortedSet: [az, qa, za]

// "zz">"qq" 添加了超出子范围的 数据 会抛出异常
//sortedSet2.add("zz");
System.out.println(sortedSet);

// 返回 小于 "qa" 的元素子集
sortedSet.headSet("qa"); // [az]
// 返回 大于等于 "az" 的元素子集
sortedSet.tailSet("az"); // [az, qa, za]
不可修改的视图、同步视图、受查视图
  • 同步视图
    转换获得一个具有同步访问方法的 集合
  • 受查视图
    插入时检查 插入对象是否为给定类
        // 不可修改的视图
//        Collections.unmodifiableCollection
//        Collections.unmodifiableList
//        Collections.unmodifiableSet
//        Collections.unmodifiableSortedSet
//        Collections.unmodifiableNavigableSet
//        Collections.unmodifiableMap
//        Collections.unmodifiableSortedMap
//        Collections.unmodifiableNavigableMap

        Collection<String> strings1 = Collections.unmodifiableCollection(list);
        System.out.println(strings1);


        // 同步视图
        // 转换获得一个具有同步访问方法的 集合
        Collections.synchronizedCollection(list);

        // Collections.synchronizedList()
        // 其他方法同上省略 ········


        // 受查视图 
        // 插入时检查 插入对象是否为给定类

        // 如下代码
        ArrayList<String> list8=new ArrayList<>();
        ArrayList list9= list8;
        list9.add(new Date());

        // 在这里会报错 ,但是实际上出错的位置是在 add 处,无法正确检测到出错位置
        // String s= (String) list9.get(0);

        // 获得一个安全的列表视图,在 add 时候就会检查插入对象是否为给定类
        List<String> safeList=Collections.checkedList(list8,String.class);

        // Collections.checkedCollection()
        // 其他方法同上省略 ········
常用算法
  • 排序和混排

        List<Integer> list=new ArrayList<>();

        list.add(7);
        list.add(9);
        list.add(2);
        list.add(3);

        System.out.println(list);

        // 排序 默认升序
        Collections.sort(list);
        System.out.println(list); // [2, 3, 7, 9]

        // 自定义比较器
        list.sort((a,b)->{ return  b.compareTo(a);}); // [9, 7, 3, 2]
        list.sort(Integer::compareTo);  //  [2, 3, 7, 9]


        // public int compare(Comparable<Object> c1, Comparable<Object> c2) {return c2.compareTo(c1);}
        // 传入了一个 用 c2.compareTo(c1) 实现 compare 方法的比较器,因此排出来就是降序的了
        // 降序排列
        list.sort(Comparator.reverseOrder());
        System.out.println(list);   // [9, 7, 3, 2]

        // 将原数据转化成 double 在做逆序排列
        // Integer::doubleValue 是传入的 转化成 double 数据的方法
        list.sort(Comparator.comparingDouble(Integer::doubleValue).reversed());
        System.out.println(list);

        // 根据员工的工资 逆序排列员工
        //staff.sort(Comparator.compari ngDoubl e(Empl oyee::getSalary) . reversedO)

        // 打乱数组顺序
        Collections.shuffle(list);


        // 集合类库中使用的是归并排序,可以保证 通过比较器认为相同的两个元素,会按原有顺序排列
        // 比如 已经按照总分排好的 学生成绩表,在按照数学成绩排序时,数学成绩相同的学生,总分高的仍会排在前面
  • 二分查找

    使用二分查找必须先排序,否则会得出错误的结果

    二分查找 对支持随机访问的数据结构才有意义,如果提供的是 LinkedList 将自动变为线性查找


        List<Integer> list=new ArrayList<>();

        Integer[] nums={9,7,6,2,6,4,7,8,6,3,4};
        //for (Integer num : nums) { list.add(num);}
        list=Arrays.asList(nums);

        // 使用二分查找必须先排序,否则会得出错误的结果
        Collections.sort(list);
        System.out.println(list); // [2, 3, 4, 4, 6, 6, 6, 7, 7, 8, 9]

        // 返回找到元素的下标,如果元素重复,返回的是根据二分查找算法首次找到元素的下标,而不是重复元素的首个下标
        // 查找失败时返回负数 i ,-i-1 为查找元素应插入位置
        int index = Collections.binarySearch(list, 6);
        System.out.println(index);  // 5

        // 二分查找 对支持随机访问的数据结构才有意义,如果提供的是 LinkedList 将自动变为线性查找
  • Collections 提供的一些简单算法

        List<Integer> list=new ArrayList<>();
        Integer[] nums={9,7,6,2,6,4,7,8,6,3,4};
        //list=Arrays.asList(nums);
        for (Integer num : nums) { list.add(num);}

        int i;
        i=Collections.max(list);
        i=Collections.min(list);


        // Collection.copy 是浅拷贝
        // Collection.copy 方法要求目标列表的 size 必须大于 源列表的 size ,否则直接抛出IndexOutOfBoundsException
        // list 的size() 只有在 add 和 remove 的时候才会发生改变,所以先用空对象填充
        List<Integer> newList=new ArrayList(Arrays.asList(new Object[list.size()]));

        Collections.copy(newList,list);
        System.out.println(newList);



        // boolean List.addAll(Collection<? extends E> c);
        // 把一个集合的所有元素添加到 list 中 ,浅拷贝  添加的是引用
        List list3=new ArrayList();
        list3.addAll(list);


        // 将列表中所有位置,都用相同的元素填充
        Collections.fill(newList,2); // [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

        Collections.replaceAll(list,2,-2); // [9, 7, 6, -2, 6, 4, 7, 8, 6, 3, 4]

        Integer[] sub={2,2};
        List subList=Arrays.asList(sub);
        // 查找 子列表 首次出现时的索引
        i=Collections.indexOfSubList(newList,subList); // 0
        // 查找 子列表 最后一次出现时的索引
        i=Collections.lastIndexOfSubList(newList,subList);// 9

        // 交换 给定两个索引的元素 位置
        Collections.swap(list,0,1); // [7, 9, 6, -2, 6, 4, 7, 8, 6, 3, 4]

        // 逆置 列表中的元素
        Collections.reverse(list); // [4, 3, 6, 8, 7, 4, 6, -2, 6, 9, 7]

        // 旋转列表中的元素,将所有元素向右循环移动 d(2) 个位置, 即 i 移动到 (i+d)%list.size() 位置
        Collections.rotate(list,2); // [9, 7, 4, 3, 6, 8, 7, 4, 6, -2, 6]

        // 元素出现的次数
        i=Collections.frequency(list,6); // 3

        // 两个集合是否有没有交集 ,两个集合没有共同元素 返回 true
        boolean b=Collections.disjoint(list,newList);


        Collection<Integer> collection=list;

        // 条件删除
        collection.removeIf(t -> { return   t<0?true:false;}); // [9, 7, 4, 3, 6, 8, 7, 4, 6, 6]

        // 自定义对列表所有元素进行操作
        list.replaceAll( t->{ return -t;});  // [-9, -7, -4, -3, -6, -8, -7, -4, -6, -6]

        System.out.println(list);
  • 按批量作

        List<Integer> list=new ArrayList<>();
        Integer[] nums={9,7,6,2,6,4,7,8,6,3,4};
        //list=Arrays.asList(nums);  // 涉及到 add remove 不能使用!
        for (Integer num : nums) { list.add(num);}


        Collection collection=list;
        Collection collection2=new ArrayList();
        collection2.add(6);

        // 移除所有 出现在 collection2 的元素
        collection.removeAll(collection2); // [9, 7, 2, 4, 7, 8, 3, 4]

        // 移除所有 没有出现在 collection2 的元素
        collection.retainAll(collection2);  // []

        // 添加所有 collection2 的元素,浅拷贝
        collection.addAll(collection2); // [6]

        System.out.println(collection);
  • 集合和数组转换

        Integer[] nums={1,3,5,4,8};

        // 数组转换列表,详情参考视图和包装
        List<Integer> list=Arrays.asList(nums);


        // 列表转换数组,
        // 数组类型不能强制转换,Object数组 类 和 Integer数组 类 是无法互相转换的
        // 这样不方便操作,   (Integer)obejects[0]
        Object[] objects=list.toArray();


        Integer[] nums2;
        // 可以传入一个指定类型的数组 将返回同类型数组
        // 如果传入数组长度不够,会新建一个同类型数组并返回
        nums2=list.toArray(new Integer[0]);
        // 如果传入数组长度够用,则直接填入到这个数组中并返回
        nums2=list.toArray(new Integer[10]);
        nums2=list.toArray(new Integer[list.size()]);

相关文章

网友评论

      本文标题:十、集合

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