集合框架及Stream流

本文详细介绍了Java集合框架,包括Collection接口、Set和List的子类及其特点,数据结构如栈、队列、数组、二叉树、红黑树和HashMap/TreeMap,以及泛型、Map的遍历和操作,不可变集合和Stream流的使用。
摘要由CSDN通过智能技术生成

知识网图:

集合类体系结构

1.Collection集合(接口)

1.1 概述

  • 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素

  • JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现

1.2  Collection常用方法

方法名说明
boolean add(E e)添加元素
boolean remove(Object o)从集合中移除指定的元素(指定的对象而非索引,因为Collection定义的是共性的内容)
boolean removeIf(Object o)根据条件进行移除
void clear()清空集合中的元素
boolean contains(Object o)判断集合中是否存在指定的元素
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中元素的个数

1.3 Collection集合遍历 

        1.3.1 迭代器遍历  

  • Iterator<E> iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到

  • 迭代器中常用方法:hasNext(): 判断当前位置是否有元素可以被取出;                                                                    next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置;

  • 注意:迭代器遍历完毕后指针不复位;循环中只能用一次next()方法;迭代器遍历时不能使用集合的方法进行增加或删除(只能使用迭代器的remove()方法: 删除迭代器对象当前指向的元素 )

        1.3.2 增强for遍历  

  • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

  • 实现Iterable接口的类才可以使用迭代器和增强for(所有单列集合和数组)

  • 简化数组和Collection集合的遍历

  • 格式(快捷键:集合名.for)

    for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {

    // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可}

        1.3.3 Lambda表达式遍历(forEach方法)

  • 格式:集合名.forEach( s -> sout(s) );

1.4 List集合 

        1.4.1 List集合的概述与特点

  • List集合的概述

    • 有序集合,这里的有序指的是存取顺序

    • 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素

    • 与Set集合不同,列表通常允许重复的元素

  • List集合的特点:存取有序,可以重复,有索引

        1.4.2 List集合的特有方法   

方法名描述
void add(int index,E element)在此集合中的指定位置插入指定的元素(可插入重复元素和null)
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index,E element)修改指定索引处的元素,返回被修改的元素
E get(int index)返回指定索引处的元素

        1.4.3 List集合的子类及其特点 

  • ArrayList集合

    底层是数组结构实现,查询修改快、增删慢

    线程不安全,效率高

    空参创建的集合开始时默认初始长度为0,添加第一个元素后长度才为10

    ArrayList自动扩容机制,新的容量为原有容量的基础上扩容1.5倍(容量>>1,右移一位,除以2),若不够则扩容为需要添加的内容的长度

  • LinkedList集合

    底层是链表结构实现,查询慢、增删快

  • Vector集合

    底层是数组(初始容量为10),线程安全效率低

LinkedList特有方法:

方法名说明
public void addFirst(E e)在该列表开头插入指定的元素
public void addLast(E e)将指定的元素追加到此列表的末尾
public E getFirst()返回此列表中的第一个元素
public E getLast()返回此列表中的最后一个元素
public E removeFirst()从此列表中删除并返回第一个元素
public E removeLast()从此列表中删除并返回最后一个元素

Vector特有方法:

方法名说明
public void addElement(E e)将指定的元素添加到此列表的末尾,将其大小增加1。
public void insertElementAt(E obj, int index)在指定的index插入元素
removeElementAt(int index)删除指定索引处的元素
removeAllElements()删除所有元素
setElementAt(E obj, int index)修改指定索引处的元素为obj
fistElement()/lastElement()/elementAt(int index)获取第一个元素/获取最后一个元素/获取指定索引处的元素

1.5 Set集合(基本操作继承自Collection)

        1.5.1 Set集合概述及其特点

  • 不可以存储重复元素

  • 无序,存取顺序不一致

  • 没有索引,不能使用普通for循环遍历

        1.5.2 Set集合子类及其特点

  • HashSet(底层是哈希表):存取无序,元素不重复,无索引

  • LinkedHashSet(底层是哈希表+双向链表,HashSet的子类):存取有序,元素不重复,无索引

  • TreeSet(底层是红黑树,实质是TreeMap集合):可排序,元素不重复,无索引

        1.5.3 哈希表结构

JDK1.8之前:数组+链表

JDK1.8之后:数组+红黑树(链表长度超过8,数组长度大于等于64时,链表自动转换为红黑树 )

注:上图步骤5处在1.8之后,新元素会直接挂在老元素的下方

        1.5.4 TreeSet集合

        特有排序:

  • 可以将元素按照规则进行排序(数值默认升序,字符默认ASCII表值升序,字符串则是挨个比较)

    • TreeSet():根据其元素的自然排序进行排序

    • TreeSet(Comparator comparator) :根据指定的比较器进行排序

  • 自然排序(Comparable):

  • 使用空参构造创建TreeSet集合:用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的

  • 自定义的Student类实现Comparable接口:自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法

  • 重写接口中的compareTo方法:重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

//用户类
public class Teacher {
    private String name;
    private int age;

    public Teacher() {
    }

    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 

  • 选择器排序(Compartor):   

  • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
  • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
//测试类
public class MyTreeSet4 {
    public static void main(String[] args) {
      	//创建集合对象
        TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
            @Override
            public int compare(Teacher o1, Teacher o2) {
                //o1表示现在要存入的那个元素
                //o2表示已经存入到集合中的元素
              
                //主要条件
                int result = o1.getAge() - o2.getAge();
                //次要条件
                result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
                return result;
            }
        });
		//创建老师对象
        Teacher t1 = new Teacher("zhangsan",23);
        Teacher t2 = new Teacher("lisi",22);
        Teacher t3 = new Teacher("wangwu",24);
        Teacher t4 = new Teacher("zhaoliu",24);
		//把老师添加到集合
        ts.add(t1);
        ts.add(t2);
        ts.add(t3);
        ts.add(t4);
		//遍历集合
        for (Teacher teacher : ts) {
            System.out.println(teacher);
        }
    }
}

2.数据结构

2.1 栈结构(先进后出)

2.2 队列结构(先进先出,查询慢,增删快)

2.3 数组结构(查询快,增删慢)

2.4 二叉树(任意一个节点的度要小于等于2 )

     2.4.1 二叉查找树(左子树上所有节点的值都小于根节点的值;右子树上所有节点的值都大于根节点的值 )   

      2.4.2 平衡二叉树(二叉树左右两个子树的高度差不超过1)

                平衡二叉树旋转

                左旋:

  • 就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

                右旋: 

就是将根节点的左侧往右拉,原先的左子节点变成新的父节点,并把多余的右子节点出让,给已经降级的根节点当左子节点

 

 

平衡二叉树旋转的四种情况

  • 左左(一次右旋解决)

    • 左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡

    • 如何旋转: 直接对整体进行右旋即可

  • 左右(局部左旋,整体右旋)

    • 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡

    • 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋

  • 右右(一次左旋)

    • 右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡

    • 如何旋转: 直接对整体进行左旋即可

  • 右左(局部右旋,整体左旋)

    • 右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡

    • 如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋

2.5 红黑树 (满足红黑规则的二叉查找树)       

红黑规则:(节点红或黑,根和叶(Nil)为黑,若红子为黑(两红不相连),点到叶节点路径上黑同)

  1. 每一个节点或是红色的,或者是黑色的

  2. 根节点必须是黑色

  3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的

  4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)

  5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

红黑数添加节点时默认为红色,提高效率 

3.泛型 

3.1 概念

  • 泛型的介绍

    泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制

  • 泛型的好处

    1. 把运行时期的问题提前到了编译期间

    2. 避免了强制类型转换

  • 泛型的定义格式

    • <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如: <E> <T>

    • <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>

  • 特点

    1.泛型中不能写基本数据类型

    2.指定泛型后,传递的数据只能是该泛型或其子类型

    3.不写泛型默认为Object

3.2 泛型类

  • 定义格式:修饰符 class 类名<类型> { }

3.3 泛型方法

  • 定义格式:修饰符 <类型> 返回值类型 方法名(类型 变量名) { }

3.4 泛型接口(具体泛型可以在定义实现类或实现类对象时指定)

  • 定义格式:修饰符 interface 接口名<类型> { }

3.5 类型通配符

  • 类型通配符: <?>

    • ArrayList<?>: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型

    • 但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型

  • 类型通配符上限: <? extends 类型>

    • ArrayListList <? extends Number>: 它表示的类型是Number或者其子类型

  • 类型通配符下限: <? super 类型>

    • ArrayListList <? super Number>: 它表示的类型是Number或者其父类型

4. Map集合(双列集合)

4.1 Map集合特点

  • 双列集合,一个键对应一个值

  • 存取无序,键不重复,无索引

4.2 Map集合的成员方法

方法名说明
V put(K key,V value)添加/覆盖元素(当添加时键存在了,则进行覆盖,并返回被覆盖的值)
V remove(Object key)根据键删除键值对元素
void clear()移除所有的键值对元素
boolean containsKey(Object key)判断集合是否包含指定的键
boolean containsValue(Object value)判断集合是否包含指定的值
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中键值对的个数
V get(Object key)根据键获取值
Set<K> keySet()获取所有键的集合
Collection<V> values()获取所有值的集合
Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合

 

4.3 Map集合遍历

        4.3.1 键找值

  • 步骤

    • 获取所有键的集合。用keySet()方法实现

    • 遍历键的集合,获取到每一个键。用增强for实现

    • 根据键去找值。用get(Object key)方法实现

        4.3.2 键值对

  • 步骤

    • 获取所有键值对对象的集合

      • Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合

    • 遍历键值对对象的集合,得到每一个键值对对象

      • 用增强for实现,得到每一个Map.Entry

    • 根据键值对对象获取键和值

      • 用getKey()得到键

      • 用getValue()得到值

4.4 HashMap集合

        特点:

  • HashMap底层是哈希表结构的

  • 依赖hashCode方法和equals方法保证键的唯一

  • 如果键要存储的是自定义类对象,需要重写hashCode和equals方法

4.5 TreeMap集合(排序方法同TreeSet)

        特点:

  • TreeMap底层是红黑树结构

  • 依赖自然排序或者比较器排序,对键进行排序

  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

5. 可变参数

  • 可变参数介绍

    • 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

    • 方法的参数类型已经确定,个数不确定,我们可以使用可变参数

  • 可变参数定义格式

    修饰符 返回值类型 方法名(数据类型… 变量名) {  }
  • 可变参数的注意事项

    • 这里的变量其实是一个数组

    • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后,且只能有一个

6. 不可变集合 

方法介绍

  • 在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合

    • 这个集合不能添加,不能删除,不能修改,创建Set和Map集合时元素不能重复,键不能重复

    • 但是可以结合集合的带参构造,实现集合的批量添加

  • 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性

    • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中

    • 创建Map集合时只能存储20个参数,即10个键值对

    • 若创建键值对数超过10个,则使用Map的ofEntries()方法,传入的是键值对对象,需要使用entrySet()方法先获取所有键值对对象,简单的可以直接使用copyOf()(java 10)

7.Stream流

  • Stream流的三类方法

    • 获取Stream流

      • 创建一条流水线,并把数据放到流水线上准备进行操作

      • 创建单列集合的Stream流直接调用stream()

      • 创建双列集合的Stream流需要先使用keySet()或entrySet()方法转为单列集合再调用stream()方法

      • 创建数组的Stream流需要使用Arrays.stream()方法

      • 若是创建的是一堆零散的数据的Stream流使用Stream.of()方法

    • 中间方法

      • 流水线上的操作

      • 一次操作完毕之后,还可以继续进行其他操作

    • 终结方法

      • 一个Stream流只能有一个终结方法

      • 是流水线上的最后一个操作

7.1 生成Stream流的方法

  • 生成Stream流的方式

    • Collection体系集合

      使用默认方法stream()生成流, default Stream<E> stream()

    • Map体系集合

      把Map转成Set集合,间接的生成流

    • 数组

      通过Arrays中的静态方法stream生成流

    • 同种数据类型的多个数据

      通过Stream接口的静态方法of(T... values)生成流

7.2 Stream流中间操作方法

方法名说明
Stream<T> filter(Predicate predicate)用于对流中的数据进行过滤
Stream<T> limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据(获取前几个)
Stream<T> skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流(跳过前几个)
static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
Stream<T> distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流(若是其它引用数据类型,需要重写hashCode()和equals()方法)
map(Function<? super T,? extends R> mapper)转换流中数据为指定类型

 

7.3 Stream的终结方法

注:执行完此方法之后,Stream流将不能再执行其他操作

方法名说明
void forEach(Consumer action)对此流的每个元素执行操作
long count()返回此流中的元素数

 

7.4 Stream的收集操作

  • 方法名说明
    R collect(Collector collector)把结果收集到集合中
  • 工具类Collectors提供了具体的收集方式

    方法名说明
    public static <T> Collector toList()把元素收集到List集合中
    public static <T> Collector toSet()把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中,keyMapper为键的生成规则,valueMapper为值的生成规则

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值