Java基础 - 集合

类型概览

Collection (List 、 Set 、 Queue) 和 Map

集合

Collection 类型在每个槽中只能保存一个元素,包含List 、 Set 、 Queue

集合(Collection) :一个独立元素的序列,这些元素都服从一条或多条规则。
List 必须以插入的顺序保存元素
Set 不能包含重复元素
Queue 只能在集合一端插入对象,并从另一端移除对象。按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。

映射

Map 在每个槽中存放了两个元素,即键 (key)和与之关联的值 (value)

映射(Map) : 一组成对的“键值对”对象,允许使用键来查找值。 ArrayList 使用数字来查找对象,因此在某种意义上讲,它是将数字和对象关联在一起。 map 允许我们使用一个对象来查找另一个对象,它也被称作关联数组(associative array),因为它将对象和其它对象关联在一起;或者称作字典(dictionary),因为可以使用一个键对象来查找值对象,就像在字典中使用单词查找定义一样。 pp 是强大的编程工具。

Collection

构建集合

public static void main(String[] args) {
        buildCollection();
    }

    // 通过另一个collection构建
    private static void buildCollection() {
        Collection<String> collection =
                new ArrayList<>();
        collection.add("test");

        Collection<String> collection1 =
                new ArrayList<>(collection);
        System.out.println("buildCollection with another collection: " + collection1);
    }

不同的集合类型对于构建的方法都不相同

  • ArrayList
    调用Collection的toArray方法然后复制
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
  • LinkedList
    调用内部的addAll方法(转成数组,遍历添加)

  • 其他类型
    没有每个类型都看,就看了下ArrayDeque,HashSet,发现都是直接使用Collectionfor-in遍历添加

    为什么没有先toArray再遍历数组呢?

    个人理解:一般来说,构建时都是添加同类型的集合,
    List类型对于toArray方法都有自己的实现
    ArrayDeque,HashSet则是使用抽象父类(AbstractCollection)的toArray
    抽象父类中就是通过迭代器转换的,那我还不如直接用迭代器遍历新增,就没必要中间再用迭代器转一道数组了

addAll

 /**
     * 通过 Collections.addAll方法构建
     */
    private static void buildCollectionWithAddAll() {
         Collection<Integer> collection =
                new ArrayList<>();

        Collections.addAll(collection,1,2,3,4,5);
        System.out.println("buildCollectionWith Collections.addAll method: " + collection);

        Collection<Integer> anotherCollection =
                new ArrayList<>(Arrays.asList(1,2,3));

        collection.addAll(anotherCollection);
        System.out.println("buildCollectionWith instance addAll method: " + collection);
    }

工具类就是迭代器循环遍历添加了

 public static <T> boolean addAll(Collection<? super T> c, T... elements) {
        boolean result = false;
        for (T element : elements)
            result |= c.add(element);
        return result;
    }

Arrays.asList

    /**
     * 通过Arrays.asList构建
     */
    private static void buildCollectionWithArrays() {
        Collection<Integer> collection1 =
                new ArrayList<>(Arrays.asList(1,2,3,4,5));
        System.out.println("buildCollection with Arrays: " + collection1);
    }

Collection方法概览

标注为since 1.8的都在接口中有default默认实现


  • add,addAll


  • remove,removeAll,removeIf(since 1.8,使用了函数式接口Predicate),clear


  • 无,因为有的集合没有这个功能,例如Set,Queue


  • size,iterator(通过继承Iterable接口)
    没有获取某个元素的接口,因为不同集合获取元素的方法不一样(ListQueue),有的甚至没有获取元素的功能,例如Set

  • 判断
    isEmpty,contains,containsAll

  • 转数组
    toArray(),toArray(T[] a)

  • 流相关(since 1.8)
    stream,spliterator,parallelStream(通过继承Iterable

List

  • ArrayList ,擅长随机访问元素,但在 List 中间插入和删除元素时速度较慢。

  • LinkedList ,它通过代价较低的在 List 中间进行的插入和删除操作,提供了优化的顺序访问。 LinkedList 对于随机访问来说相对较慢

List 接口概览

这里列举一下比Collection多出来的


  • add,addAll
    都增加了从某个索引后添加的方法


  • remove,removeAll
    都增加了从某个索引后添加的方法


  • set,replaceAll(since 1.8)


  • 获取元素:get
    获取索引:indexOf,lastIndexOf
    遍历:iterator,listIterator

  • 排序
    sort (since 1.8)

  • 切片
    subList

listIterator

相比普通Iterator多了新增,修改的方法,还提供遍历元素的索引,还可以指定迭代器开始的位置

replaceAll

replaceAll就是通过listIterator修改每个元素,修改的方法由参数提供(函数式接口)

LinkedList

LinkedList 还添加了一些方法,使其可以被用作栈、队列或双端队列(deque)

  • getFirst() 和 element() 是相同的,它们都返回列表的头部(第一个元素)而并不删除它,如果 List 为空,则抛出 NoSuchElementException 异常。 peek() 方法与这两个方法只是稍有差异,它在列表为空时返回 null 。
  • removeFirst() 和 remove() 也是相同的,它们删除并返回列表的头部元素,并在列表为空时抛出 NoSuchElementException 异常。 poll() 稍有差异,它在列表为空时返回 null 。
  • addFirst() 在列表的开头插入一个元素。
  • offer() 与 add() 和 addLast() 相同。 它们都在列表的尾部(末尾)添加一个元素。
  • removeLast() 删除并返回列表的最后一个元素

Queue

一头进,一头出
小坑:ArrayQueue没有实现Queue......

Queue接口概览

  • 入队
    offer

  • 出队
    poll(返回null),remove(抛异常)

  • 查找队首元素
    peek(返回null),element(抛异常)

PriorityQueue

两种方式实现排序

  1. 队列元素实现Compable接口
  2. 构造时可以添加比较器(Comparator),用于对队列进行排序,在初始化或者入队出队时会重新进行排序

排序相关的基本都是这个套路,后面的TreeSetTreeMap也是如此

Deque

双端队列(Double Ended Queue) 队首可进可出,队尾同样可进可出
所以通过Deque可以实现栈的功能

Deque方法概览

Deque 也继承Queue,但不建议使用Queue的方法

  • 入队
    addFirst,offerFirst
    addLast,offerLast

  • 出队
    removeFirst,pollFirst
    pollFirst,pollLast

栈相关接口

  • 入栈
    push,通过队首入队实现(普通队列只能实现队尾入队,队首入队,其实就是插队。。)

  • 出栈
    pop,通过队首出队实现

question:能不能队尾入队,队尾出呢?

Stack

堆栈是“后进先出”(LIFO)集合

Java 1.0 中附带了一个 Stack 类,结果设计得很糟糕(为了向后兼容,我们被迫一直忍受 Java 中的旧设计错误)。Java 6 添加了 ArrayDeque ,其中包含直接实现堆栈功能的方法
Deque接口就是Java6之后提出的

由于ArrayDeque中由很多其他的方法,所以为了使用一个更好的Stack,我们可以自己编写一个Stack,然后使用组合的方式使用Deque的实现

Set

接口概览

相比Collection,没有新增的接口

集合操作

  • 交集 contains
  • 并集 addAll
  • 差集 removeAll

Set类型

  • HashSet
  • LinkedHashSet
  • TreeSet
    TreeSet中的元素需要实现Comparable接口

Map

  • HashMap
    顺序不是插入顺序,因为 HashMap 实现使用了非常快速的算法来控制顺序

  • LinkedHashMap
    在保持 HashMap 查找速度的同时按照键的插入顺序来排序

  • TreeMap
    把所有的键按照比较规则来排序
    key值必须实现Comparable接口,或者构建TreeMap时传入对应泛型类型的Comparator
    例如key值是User,就应该传入一个Comparator<? super User>的比较器,Comparator<User>或者Comparator<Object>

Map 接口概览

这里只列举常用的


  • put,putAll,putIfAbsent


  • remove


  • put,putAll,putIfAbsent,replace,merge


  • 获取元素:get,getOrDefault
    遍历:entrySet,keySet,values
    获取大小:size

  • 判断
    isEmpty

since1.8

Java8中对Map接口新增了很多方法,用于封装一些常见的逻辑判断


  • putIfAbsent

  • remove
    增加了一个重载的remove,remove(Object key, Object value)

 Object curValue = get(key);
    default boolean remove(Object key, Object value) {
    Object curValue = get(key);
    if (!Objects.equals(curValue, value) ||
        (curValue == null && !containsKey(key))) {
        return false;
    }
    remove(key);
    return true;
}
    • putIfAbsent
    • merge
    hashmap.merge(key, value, remappingFunction)
    

    如果 key 对应的 value 不存在,则返回该 value 值,如果存在,根据映射函数修改原来的值

    • replace
      存在才修改,不存在返回null
    • replaceAll
      遍历设值

  • getOrDefault

参考资料

《OnJava8》

posted @ 2021-05-01 15:35  calmbook  阅读(70)  评论(0编辑  收藏  举报