1.ArrayList

集合和数组的区别 :

  1. 共同点:都是存储数据的容器
  2. 不同点:数组的容量是固定的,集合的容量是可变的

1.1 -ArrayList的构造方法和添加方法

public ArrayList() 创建一个空的集合对象
public boolean add(E e) 将指定的元素追加到此集合的末尾
public void add(int index,E element) 在此集合中的指定位置插入指定的元素

ArrayList :

可调整大小的数组实现<br />是一种特殊的数据类型,泛型。

怎么用呢 ?

在出现E的地方我们使用引用数据类型替换即可<br />    举例:ArrayList, ArrayList

1.2ArrayList类常用方法

成员方法 :

public boolean remove(Object o) 删除指定的元素,返回删除是否成功
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中的元素的个数

示例代码 :

public class ArrayListDemo02 {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> array = new ArrayList<String>();

        //添加元素
        array.add("hello");
        array.add("world");
        array.add("java");

        //public boolean remove(Object o):删除指定的元素,返回删除是否成功
//        System.out.println(array.remove("world"));
//        System.out.println(array.remove("javaee"));

        //public E remove(int index):删除指定索引处的元素,返回被删除的元素
//        System.out.println(array.remove(1));

        //IndexOutOfBoundsException
//        System.out.println(array.remove(3));

        //public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
//        System.out.println(array.set(1,"javaee"));

        //IndexOutOfBoundsException
//        System.out.println(array.set(3,"javaee"));

        //public E get(int index):返回指定索引处的元素
//        System.out.println(array.get(0));
//        System.out.println(array.get(1));
//        System.out.println(array.get(2));
        //System.out.println(array.get(3)); //?????? 自己测试

        //public int size():返回集合中的元素的个数
        System.out.println(array.size());

        //输出集合
        System.out.println("array:" + array);
    }
}

1.3 ArrayList存储字符串并遍历

案例需求 :

创建一个存储字符串的集合,存储3个字符串元素,使用程序实现在控制台遍历该集合

实现步骤 :

1:创建集合对象
    2:往集合中添加字符串对象
    3:遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
    4:遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
    5:遍历集合的通用格式

代码实现 :

/*
    思路:
        1:创建集合对象
        2:往集合中添加字符串对象
        3:遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
        4:遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
        5:遍历集合的通用格式
 */
public class ArrayListTest01 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> array = new ArrayList<String>();

        //往集合中添加字符串对象
        array.add("刘正风");
        array.add("左冷禅");
        array.add("风清扬");

        //遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
//        System.out.println(array.size());

        //遍历集合的通用格式
        for(int i=0; i<array.size(); i++) {
            String s = array.get(i);
            System.out.println(s);
        }
    }
}

1.4 ArrayList存储学生对象并遍历

案例需求 :

创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合

实现步骤 :

1:定义学生类

2:创建集合对象

3:创建学生对象

4:添加学生对象到集合中

5:遍历集合,采用通用遍历格式实现

代码实现 :

/*
    思路:
        1:定义学生类
        2:创建集合对象
        3:创建学生对象
        4:添加学生对象到集合中
        5:遍历集合,采用通用遍历格式实现
 */
public class ArrayListTest02 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<Student> array = new ArrayList<>();

        //创建学生对象
        Student s1 = new Student("林青霞", 30);
        Student s2 = new Student("风清扬", 33);
        Student s3 = new Student("张曼玉", 18);

        //添加学生对象到集合中
        array.add(s1);
        array.add(s2);
        array.add(s3);

        //遍历集合,采用通用遍历格式实现
        for (int i = 0; i < array.size(); i++) {
            Student s = array.get(i);
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

1.5 键盘录入学生信息到集合

案例需求 :

创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合

    学生的姓名和年龄来自于键盘录入

实现步骤 :

1:定义学生类,为了键盘录入数据方便,把学生类中的成员变量都定义为String类型

2:创建集合对象

3:键盘录入学生对象所需要的数据

4:创建学生对象,把键盘录入的数据赋值给学生对象的成员变量

5:往集合中添加学生对象

6:遍历集合,采用通用遍历格式实现

代码实现 :

/*
    思路:
        1:定义学生类,为了键盘录入数据方便,把学生类中的成员变量都定义为String类型
        2:创建集合对象
        3:键盘录入学生对象所需要的数据
        4:创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
        5:往集合中添加学生对象
        6:遍历集合,采用通用遍历格式实现
 */
public class ArrayListTest {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<Student> array = new ArrayList<Student>();

        //为了提高代码的复用性,我们用方法来改进程序
        addStudent(array);
        addStudent(array);
        addStudent(array);

        //遍历集合,采用通用遍历格式实现
        for (int i = 0; i < array.size(); i++) {
            Student s = array.get(i);
            System.out.println(s.getName() + "," + s.getAge());
        }
    }

    /*
        两个明确:
            返回值类型:void
            参数:ArrayList<Student> array
     */
    public static void addStudent(ArrayList<Student> array) {
        //键盘录入学生对象所需要的数据
        Scanner sc = new Scanner(System.in);

        System.out.println("请输入学生姓名:");
        String name = sc.nextLine();

        System.out.println("请输入学生年龄:");
        String age = sc.nextLine();

        //创建学生对象,把键盘录入的数据赋值给学生对象的成员变量
        Student s = new Student();
        s.setName(name);
        s.setAge(age);

        //往集合中添加学生对象
        array.add(s);
    }
}

2.Collection集合

2.1数组和集合的区别

  • 相同点
    都是容器,可以存储多个数据
  • 不同点
    • 数组的长度是不可变的,集合的长度是可变的
    • 数组可以存基本数据类型和引用数据类型
      集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类

2.2集合类体系结构

01_集合类体系结构图.png

2.3Collection 集合概述和使用

  • Collection集合概述
    • 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
    • JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
  • 创建Collection集合的对象
    • 多态的方式
    • 具体的实现类ArrayList
  • Collection集合常用方法
    | 方法名 | 说明 | | —- | —- | | boolean add(E e) | 添加元素 | | boolean remove(Object o) | 从集合中移除指定的元素 | | boolean removeIf(Object o) | 根据条件进行移除 | | void clear() | 清空集合中的元素 | | boolean contains(Object o) | 判断集合中是否存在指定的元素 | | boolean isEmpty() | 判断集合是否为空 | | int size() | 集合的长度,也就是集合中元素的个数 |

2.4Collection集合的遍历

  • 迭代器介绍
    • 迭代器,集合的专用遍历方式
    • Iterator iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到
  • Iterator中的常用方法
    boolean hasNext(): 判断当前位置是否有元素可以被取出
    E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置
  • Collection集合的遍历

    public class IteratorDemo1 {
     public static void main(String[] args) {
         //创建集合对象
         Collection<String> c = new ArrayList<>();
    
         //添加元素
         c.add("hello");
         c.add("world");
         c.add("java");
         c.add("javaee");
    
         //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
         Iterator<String> it = c.iterator();
    
         //用while循环改进元素的判断和获取
         while (it.hasNext()) {
             String s = it.next();
             System.out.println(s);
         }
     }
    }
    
  • 迭代器中删除的方法
    void remove(): 删除迭代器对象当前指向的元素

    public class IteratorDemo2 {
     public static void main(String[] args) {
         ArrayList<String> list = new ArrayList<>();
         list.add("a");
         list.add("b");
         list.add("b");
         list.add("c");
         list.add("d");
    
         Iterator<String> it = list.iterator();
         while(it.hasNext()){
             String s = it.next();
             if("b".equals(s)){
                 //指向谁,那么此时就删除谁.
                 it.remove();
             }
         }
         System.out.println(list);
     }
    }
    

2.5增强for循环

  • 介绍
    • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器
    • 实现Iterable接口的类才可以使用迭代器和增强for
    • 简化数组和Collection集合的遍历
  • 格式
    for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {
    // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
    }
  • 代码

    public class MyCollectonDemo1 {
     public static void main(String[] args) {
         ArrayList<String> list =  new ArrayList<>();
         list.add("a");
         list.add("b");
         list.add("c");
         list.add("d");
         list.add("e");
         list.add("f");
    
         //1,数据类型一定是集合或者数组中元素的类型
         //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素
         //3,list就是要遍历的集合或者数组
         for(String str : list){
             System.out.println(str);
         }
     }
    }
    

3.List集合

3.1List集合的概述和特点

  • List集合的概述
    • 有序集合,这里的有序指的是存取顺序
    • 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
    • 与Set集合不同,列表通常允许重复的元素
  • List集合的特点
    • 存取有序
    • 可以重复
    • 有索引

3.2List集合的特有方法

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

4.数据结构

4.1数据结构之栈和队列

  • 栈结构
    先进后出
  • 队列结构
    先进先出

4.2数据结构之数组和链表

  • 数组结构
    查询快、增删慢
  • 链表结构
    查询慢、增删快

image.png

5.List集合的实现类

5.1List集合子类的特点

  • ArrayList集合
    底层是数组结构实现,查询快、增删慢
  • LinkedList集合
    底层是链表结构实现,查询慢、增删快

ArrayList第一次添加元素的源码解析.png
LinkedList添加元素源码解析.png

5.2LinkedList集合的特有功能

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

6.泛型

6.1泛型概述

  • 泛型的介绍
    泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制
  • 泛型的好处
    1. 把运行时期的问题提前到了编译期间
    2. 避免了强制类型转换
  • 泛型的定义格式
    • <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如:
    • <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如:

6.2泛型类

  • 定义格式
    修饰符 class 类名<类型> {  }
    
  • 示例代码

    • 泛型类

      public class Generic<T> {
      private T t;
      
      public T getT() {
        return t;
      }
      
      public void setT(T t) {
        this.t = t;
      }
      }
      
  • 测试类

    public class GenericDemo1 {
    public static void main(String[] args) {
      Generic<String> g1 = new Generic<String>();
      g1.setT("杨幂");
      System.out.println(g1.getT());
    
      Generic<Integer> g2 = new Generic<Integer>();
      g2.setT(30);
      System.out.println(g2.getT());
    
      Generic<Boolean> g3 = new Generic<Boolean>();
      g3.setT(true);
      System.out.println(g3.getT());
    }
    }
    

6.3泛型方法

  • 定义格式
    修饰符 <类型> 返回值类型 方法名(类型 变量名) {  }
    
  • 示例代码
    • 带有泛型方法的类
      public class Generic {
      public <T> void show(T t) {
        System.out.println(t);
      }
      }
      
  • 测试类
    public class GenericDemo2 {
    public static void main(String[] args) {
      Generic g = new Generic();
      g.show("柳岩");
      g.show(30);
      g.show(true);
      g.show(12.34);
    }
    }
    

6.4泛型接口

  • 定义格式
    修饰符 interface 接口名<类型> {  }
    
  • 示例代码
    • 泛型接口
      public interface Generic<T> {
      void show(T t);
      }
      
  • 泛型接口实现类1
    定义实现类时,定义和接口相同泛型,创建实现类对象时明确泛型的具体类型
    public class GenericImpl1<T> implements Generic<T> {
    @Override
    public void show(T t) {
      System.out.println(t);
    }
    }
    
  • 泛型接口实现类2
    定义实现类时,直接明确泛型的具体类型
    public class GenericImpl2 implements Generic<Integer>{
    @Override
    public void show(Integer t) {
        System.out.println(t);
    }
    }
    
  • 测试类

    public class GenericDemo3 {
    public static void main(String[] args) {
      GenericImpl1<String> g1 = new GenericImpl<String>();
      g1.show("林青霞");
      GenericImpl1<Integer> g2 = new GenericImpl<Integer>();
      g2.show(30);
    
      GenericImpl2 g3 = new GenericImpl2();
        g3.show(10);
    }
    }
    

6.5类型通配符

  • 类型通配符: <?>
    • ArrayList<?>: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
    • 但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型
  • 类型通配符上限: <? extends 类型>
    • ArrayListList <? extends Number>: 它表示的类型是Number或者其子类型
  • 类型通配符下限: <? super 类型>
    • ArrayListList <? super Number>: 它表示的类型是Number或者其父类型
  • 泛型通配符的使用 ```java public class GenericDemo4 { public static void main(String[] args) {

     ArrayList<Integer> list1 = new ArrayList<>();
     ArrayList<String> list2 = new ArrayList<>();
     ArrayList<Number> list3 = new ArrayList<>();
     ArrayList<Object> list4 = new ArrayList<>();
    
     method(list1);
     method(list2);
     method(list3);
     method(list4);
    
     getElement1(list1);
     getElement1(list2);//报错
     getElement1(list3);
     getElement1(list4);//报错
    
     getElement2(list1);//报错
     getElement2(list2);//报错
     getElement2(list3);
     getElement2(list4);
    

    }

    // 泛型通配符: 此时的泛型?,可以是任意类型 public static void method(ArrayList<?> list){} // 泛型的上限: 此时的泛型?,必须是Number类型或者Number类型的子类 public static void getElement1(ArrayList<? extends Number> list){} // 泛型的下限: 此时的泛型?,必须是Number类型或者Number类型的父类 public static void getElement2(ArrayList<? super Number> list){}

}



<a name="kUNmD"></a>
# 7.Set集合

<a name="sjEVG"></a>
## 7.1Set集合概述和特点

- 不可以存储重复元素
- 没有索引,不能使用普通for循环遍历

<a name="aNntb"></a>
## 7.2Set集合的使用

存储字符串并遍历

```java
public class MySet1 {
    public static void main(String[] args) {
          //创建集合对象
        Set<String> set = new TreeSet<>();
          //添加元素
        set.add("ccc");
        set.add("aaa");
        set.add("aaa");
        set.add("bbb");

//        for (int i = 0; i < set.size(); i++) {
//            //Set集合是没有索引的,所以不能使用通过索引获取元素的方法
//        }

          //遍历集合
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-----------------------------------");
        for (String s : set) {
            System.out.println(s);
        }
    }
}

7.3.TreeSet集合

7.3.1TreeSet集合概述和特点

  • 不可以存储重复元素
  • 没有索引
  • 可以将元素按照规则进行排序
    • TreeSet():根据其元素的自然排序进行排序
    • TreeSet(Comparator comparator) :根据指定的比较器进行排序

7.3.2TreeSet集合基本使用

存储Integer类型的整数并遍历

public class TreeSetDemo01 {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Integer> ts = new TreeSet<Integer>();

        //添加元素
        ts.add(10);
        ts.add(40);
        ts.add(30);
        ts.add(50);
        ts.add(20);

        ts.add(30);

        //遍历集合
        for(Integer i : ts) {
            System.out.println(i);
        }
    }
}

7.3.3自然排序Comparable的使用

  • 案例需求
    • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
  • 实现步骤
    1. 使用空参构造创建TreeSet集合
      • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
    2. 自定义的Student类实现Comparable接口
      • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
        • 如果返回值为负数,表示当前存入的元素是较小值,存左边
        • 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
        • 如果返回值为正数,表示当前存入的元素是较大值,存右边
    3. 重写接口中的compareTo方法
      • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
  • 代码实现
    学生类

    public class Student implements Comparable<Student>{
     private String name;
     private int age;
    
     public Student() {
     }
    
     public Student(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 "Student{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 '}';
     }
    
     @Override
     public int compareTo(Student o) {
         //按照对象的年龄进行排序
         //主要判断条件: 按照年龄从小到大排序
         int result = this.age - o.age;
         //次要判断条件: 年龄相同时,按照姓名的字母顺序排序
         result = result == 0 ? this.name.compareTo(o.getName()) : result;
         return result;
     }
    }
    


    测试类

7.3.4比较器排序Comparator的使用

  • 案例需求
    • 存储老师对象并遍历,创建TreeSet集合使用带参构造方法
    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
  • 实现步骤
    • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
    • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
  • 代码实现
    老师类

    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 +
                 '}';
     }
    }
    


    测试类

7.3.5 两种比较方式总结

  • 两种比较方式小结
    • 自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
    • 比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
    • 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
  • 两种方式中关于返回值的规则
    • 如果返回值为负数,表示当前存入的元素是较小值,存左边
    • 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
    • 如果返回值为正数,表示当前存入的元素是较大值,存右边

7.4.数据结构

7.4.1二叉树

  • 二叉树的特点
    • 二叉树中,任意一个节点的度要小于等于2
      • 节点: 在树结构中,每一个元素称之为节点
      • 度: 每一个节点的子节点数量称之为度
  • 二叉树结构图
    01_二叉树结构图.png

7.4.2二叉查找树

  • 二叉查找树的特点
    • 二叉查找树,又称二叉排序树或者二叉搜索树
    • 每一个节点上最多有两个子节点
    • 左子树上所有节点的值都小于根节点的值
    • 右子树上所有节点的值都大于根节点的值
  • 二叉查找树结构图
    02_二叉查找树结构图.png
  • 二叉查找树和二叉树对比结构图
    03_二叉查找树和二叉树对比结构图.png
  • 二叉查找树添加节点规则
    • 小的存左边
    • 大的存右边
    • 一样的不存

04_二叉查找树添加节点规则.png

7.4.3平衡二叉树

  • 平衡二叉树的特点
    • 二叉树左右两个子树的高度差不超过1
    • 任意节点的左右两个子树都是一颗平衡二叉树
  • 平衡二叉树旋转
    • 旋转触发时机
      • 当添加一个节点之后,该树不再是一颗平衡二叉树
    • 左旋
      • 就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

05_平衡二叉树左旋01.png
05_平衡二叉树左旋02.png

  • 右旋

    • 就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点
      06_平衡二叉树右旋01.png

                        ![06_平衡二叉树右旋02.png](https://cdn.nlark.com/yuque/0/2022/png/22908640/1648623368508-dc80f562-ee2d-4231-8626-386a769c35f9.png#clientId=u4d7b2b54-9a4c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=310&id=u1de496e0&name=06_%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91%E5%8F%B3%E6%97%8B02.png&originHeight=388&originWidth=913&originalType=binary&ratio=1&rotation=0&showTitle=false&size=28723&status=done&style=none&taskId=u9b478a56-e6aa-43f6-a55e-fd6b26dd430&title=&width=730.4)<br /> 
      
  • 平衡二叉树和二叉查找树对比结构图
    07_平衡二叉树和二叉查找树对比结构图.png
  • 平衡二叉树旋转的四种情况
    • 左左
      • 左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡
      • 如何旋转: 直接对整体进行右旋即可
        07_平衡二叉树和二叉查找树对比结构图.png
    • 左右
      • 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡
      • 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋
        09_平衡二叉树左右.png
    • 右右
      • 右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡
      • 如何旋转: 直接对整体进行左旋即可
        10_平衡二叉树右右.png
    • 右左
      • 右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡
      • 如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋
        10_平衡二叉树右右.png

7.4.4红黑树

  • 红黑树的特点
    • 平衡二叉B树
    • 每一个节点可以是红或者黑
    • 红黑树不是高度平衡的,它的平衡是通过”自己的红黑规则”进行实现的
  • 红黑树的红黑规则有哪些
    1. 每一个节点或是红色的,或者是黑色的
    2. 根节点必须是黑色
    3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
    4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)
    5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
      12_红黑树结构图.png
  • 红黑树添加节点的默认颜色
    • 添加节点时,默认为红色,效率高
      13_红黑树添加节点颜色.png
  • 红黑树添加节点后如何保持红黑规则
    • 根节点位置
      • 直接变为黑色
    • 非根节点位置
      • 父节点为黑色
        • 不需要任何操作,默认红色即可
      • 父节点为红色
        • 叔叔节点为红色
          1. 将”父节点”设为黑色,将”叔叔节点”设为黑色
          2. 将”祖父节点”设为红色
          3. 如果”祖父节点”为根节点,则将根节点再次变成黑色
        • 叔叔节点为黑色
          1. 将”父节点”设为黑色
          2. 将”祖父节点”设为红色
          3. 以”祖父节点”为支点进行旋转

image.png

7.4.5成绩排序案例

  • 案例需求
    • 用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩,英语成绩),并遍历该集合
    • 要求: 按照总分从高到低出现
  • 代码实现
    学生类

    public class Student implements Comparable<Student> {
     private String name;
     private int chinese;
     private int math;
     private int english;
    
     public Student() {
     }
    
     public Student(String name, int chinese, int math, int english) {
         this.name = name;
         this.chinese = chinese;
         this.math = math;
         this.english = english;
     }
    
     public String getName() {
         return name;
     }
    
     public void setName(String name) {
         this.name = name;
     }
    
     public int getChinese() {
         return chinese;
     }
    
     public void setChinese(int chinese) {
         this.chinese = chinese;
     }
    
     public int getMath() {
         return math;
     }
    
     public void setMath(int math) {
         this.math = math;
     }
    
     public int getEnglish() {
         return english;
     }
    
     public void setEnglish(int english) {
         this.english = english;
     }
    
     public int getSum() {
         return this.chinese + this.math + this.english;
     }
    
     @Override
     public int compareTo(Student o) {
         // 主要条件: 按照总分进行排序
         int result = o.getSum() - this.getSum();
         // 次要条件: 如果总分一样,就按照语文成绩排序
         result = result == 0 ? o.getChinese() - this.getChinese() : result;
         // 如果语文成绩也一样,就按照数学成绩排序
         result = result == 0 ? o.getMath() - this.getMath() : result;
         // 如果总分一样,各科成绩也都一样,就按照姓名排序
         result = result == 0 ? o.getName().compareTo(this.getName()) : result;
         return result;
     }
    }
    

7.5.HashSet集合

7.5.1HashSet集合概述和特点

  • 底层数据结构是哈希表
  • 存取无序
  • 不可以存储重复元素
  • 没有索引,不能使用普通for循环遍历

7.5.2HashSet集合的基本应用

存储字符串并遍历

public class HashSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        HashSet<String> set = new HashSet<String>();

        //添加元素
        set.add("hello");
        set.add("world");
        set.add("java");
        //不包含重复元素的集合
        set.add("world");

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

7.5.3哈希值

  • 哈希值简介
    是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
  • 如何获取哈希值
    Object类中的public int hashCode():返回对象的哈希码值
  • 哈希值的特点
    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
    • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同

7.5.4哈希表结构

  • JDK1.8以前
    数组 + 链表
    14_JKD8以前哈希表.png
  • JDK1.8以后
    • 节点个数少于等于8个
      数组 + 链表
    • 节点个数多于8个
      数组 + 红黑树

14_JKD8以前哈希表.png
image.png

7.5.5HashSet集合存储学生对象并遍历

  • 案例需求
    • 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
    • 要求:学生对象的成员变量值相同,我们就认为是同一个对象
  • 代码实现
    学生类

    public class Student {
     private String name;
     private int age;
    
     public Student() {
     }
    
     public Student(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 boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
    
         Student student = (Student) o;
    
         if (age != student.age) return false;
         return name != null ? name.equals(student.name) : student.name == null;
     }
    
     @Override
     public int hashCode() {
         int result = name != null ? name.hashCode() : 0;
         result = 31 * result + age;
         return result;
     }
    }
    


    测试类

  • 总结
    HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法

9.Map集合

9.1Map集合概述和特点

  • Map集合概述
    interface Map<K,V>  K:键的类型;V:值的类型
    
  • Map集合的特点
    • 双列集合,一个键对应一个值
    • 键不可以重复,值可以重复
  • Map集合的基本使用

    public class MapDemo01 {
     public static void main(String[] args) {
         //创建集合对象
         Map<String,String> map = new HashMap<String,String>();
    
         //V put(K key, V value) 将指定的值与该映射中的指定键相关联
         map.put("itheima001","林青霞");
         map.put("itheima002","张曼玉");
         map.put("itheima003","王祖贤");
         map.put("itheima003","柳岩");
    
         //输出集合对象
         System.out.println(map);
     }
    }
    

9.2Map集合的基本功能

  • 方法介绍
    | 方法名 | 说明 | | —- | —- | | V put(K key,V value) | 添加元素 | | V remove(Object key) | 根据键删除键值对元素 | | void clear() | 移除所有的键值对元素 | | boolean containsKey(Object key) | 判断集合是否包含指定的键 | | boolean containsValue(Object value) | 判断集合是否包含指定的值 | | boolean isEmpty() | 判断集合是否为空 | | int size() | 集合的长度,也就是集合中键值对的个数 |

  • 示例代码

    public class MapDemo02 {
     public static void main(String[] args) {
         //创建集合对象
         Map<String,String> map = new HashMap<String,String>();
    
         //V put(K key,V value):添加元素
         map.put("张无忌","赵敏");
         map.put("郭靖","黄蓉");
         map.put("杨过","小龙女");
    
         //V remove(Object key):根据键删除键值对元素
    //        System.out.println(map.remove("郭靖"));
    //        System.out.println(map.remove("郭襄"));
    
         //void clear():移除所有的键值对元素
    //        map.clear();
    
         //boolean containsKey(Object key):判断集合是否包含指定的键
    //        System.out.println(map.containsKey("郭靖"));
    //        System.out.println(map.containsKey("郭襄"));
    
         //boolean isEmpty():判断集合是否为空
    //        System.out.println(map.isEmpty());
    
         //int size():集合的长度,也就是集合中键值对的个数
         System.out.println(map.size());
    
         //输出集合对象
         System.out.println(map);
     }
    }
    

9.3Map集合的获取功能

  • 方法介绍
    | 方法名 | 说明 | | —- | —- | | V get(Object key) | 根据键获取值 | | Set keySet() | 获取所有键的集合 | | Collection values() | 获取所有值的集合 | | Set> entrySet() | 获取所有键值对对象的集合 |

  • 示例代码

    public class MapDemo03 {
     public static void main(String[] args) {
         //创建集合对象
         Map<String, String> map = new HashMap<String, String>();
    
         //添加元素
         map.put("张无忌", "赵敏");
         map.put("郭靖", "黄蓉");
         map.put("杨过", "小龙女");
    
         //V get(Object key):根据键获取值
    //        System.out.println(map.get("张无忌"));
    //        System.out.println(map.get("张三丰"));
    
         //Set<K> keySet():获取所有键的集合
    //        Set<String> keySet = map.keySet();
    //        for(String key : keySet) {
    //            System.out.println(key);
    //        }
    
         //Collection<V> values():获取所有值的集合
         Collection<String> values = map.values();
         for(String value : values) {
             System.out.println(value);
         }
     }
    }
    

9.4Map集合的遍历(方式1)

  • 遍历思路
    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 把所有的丈夫给集中起来
      • 遍历丈夫的集合,获取到每一个丈夫
      • 根据丈夫去找对应的妻子
  • 步骤分析
    • 获取所有键的集合。用keySet()方法实现
    • 遍历键的集合,获取到每一个键。用增强for实现
    • 根据键去找值。用get(Object key)方法实现
  • 代码实现

    public class MapDemo01 {
     public static void main(String[] args) {
         //创建集合对象
         Map<String, String> map = new HashMap<String, String>();
    
         //添加元素
         map.put("张无忌", "赵敏");
         map.put("郭靖", "黄蓉");
         map.put("杨过", "小龙女");
    
         //获取所有键的集合。用keySet()方法实现
         Set<String> keySet = map.keySet();
         //遍历键的集合,获取到每一个键。用增强for实现
         for (String key : keySet) {
             //根据键去找值。用get(Object key)方法实现
             String value = map.get(key);
             System.out.println(key + "," + value);
         }
     }
    }
    

9.5Map集合的遍历(方式2)

  • 遍历思路
    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 获取所有结婚证的集合
      • 遍历结婚证的集合,得到每一个结婚证
      • 根据结婚证获取丈夫和妻子
  • 步骤分析
    • 获取所有键值对对象的集合
      • Set> entrySet():获取所有键值对对象的集合
    • 遍历键值对对象的集合,得到每一个键值对对象
      • 用增强for实现,得到每一个Map.Entry
    • 根据键值对对象获取键和值
      • 用getKey()得到键
      • 用getValue()得到值
  • 代码实现

    public class MapDemo02 {
     public static void main(String[] args) {
         //创建集合对象
         Map<String, String> map = new HashMap<String, String>();
    
         //添加元素
         map.put("张无忌", "赵敏");
         map.put("郭靖", "黄蓉");
         map.put("杨过", "小龙女");
    
         //获取所有键值对对象的集合
         Set<Map.Entry<String, String>> entrySet = map.entrySet();
         //遍历键值对对象的集合,得到每一个键值对对象
         for (Map.Entry<String, String> me : entrySet) {
             //根据键值对对象获取键和值
             String key = me.getKey();
             String value = me.getValue();
             System.out.println(key + "," + value);
         }
     }
    }
    

9.6.HashMap集合

9.6.1HashMap集合概述和特点

  • HashMap底层是哈希表结构的
  • 依赖hashCode方法和equals方法保证键的唯一
  • 如果键要存储的是自定义对象,需要重写hashCode和equals方法

9.6.2HashMap集合应用案例

  • 案例需求
    • 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。
    • 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
  • 代码实现
    学生类

    public class Student {
     private String name;
     private int age;
    
     public Student() {
     }
    
     public Student(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 boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
    
         Student student = (Student) o;
    
         if (age != student.age) return false;
         return name != null ? name.equals(student.name) : student.name == null;
     }
    
     @Override
     public int hashCode() {
         int result = name != null ? name.hashCode() : 0;
         result = 31 * result + age;
         return result;
     }
    }
    


    测试类

9.7. TreeMap集合

9.7.1TreeMap集合概述和特点

  • TreeMap底层是红黑树结构
  • 依赖自然排序或者比较器排序,对键进行排序
  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

9.7.2TreeMap集合应用案例一

  • 案例需求
    • 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历
    • 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
  • 代码实现
    学生类

    public class Student implements Comparable<Student>{
     private String name;
     private int age;
    
     public Student() {
     }
    
     public Student(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 "Student{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 '}';
     }
    
     @Override
     public int compareTo(Student o) {
         //按照年龄进行排序
         int result = o.getAge() - this.getAge();
         //次要条件,按照姓名排序。
         result = result == 0 ? o.getName().compareTo(this.getName()) : result;
         return result;
     }
    }
    


    测试类

9.7.3TreeMap集合应用案例二

  • 案例需求
    • 给定一个字符串,要求统计字符串中每个字符出现的次数。
    • 举例: 给定字符串是“aababcabcdabcde”,在控制台输出: “a(5)b(4)c(3)d(2)e(1)”
  • 代码实现

    public class Test2 {
     public static void main(String[] args) {
           // 给定字符串
         String s = "aababcabcdabcde";
         // 创建TreeMap集合对象,键是Character,值是Integer
         TreeMap<Character,Integer> tm = new TreeMap<>();
    
         //遍历字符串,得到每一个字符
         for (int i = 0; i < s.length(); i++) {
             //c依次表示字符串中的每一个字符
             char c = s.charAt(i);
               // 判断当前遍历到的字符是否在集合中出现过
             if(!tm.containsKey(c)){
                 //表示当前字符是第一次出现。
                 tm.put(c,1);
             }else{
                 //存在,表示当前字符已经出现过了
                 //先获取这个字符已经出现的次数
                 Integer count = tm.get(c);
                 //自增,表示这个字符又出现了依次
                 count++;
                 //将自增后的结果再次添加到集合中。
                 tm.put(c,count);
             }
         }
         //  a(5)b(4)c(3)d(2)e(1)
         //System.out.println(tm);
         tm.forEach(
                 (Character key,Integer value)->{
                     System.out.print(key + "(" + value + ")");
                 }
         );
     }
    }
    

10.可变参数

10.1可变参数

  • 可变参数介绍
    • 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
    • 方法的参数类型已经确定,个数不确定,我们可以使用可变参数
  • 可变参数定义格式
    修饰符 返回值类型 方法名(数据类型… 变量名) {  }
    
  • 可变参数的注意事项
    • 这里的变量其实是一个数组
    • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
  • 可变参数的基本使用 ```java public class ArgsDemo01 { public static void main(String[] args) {

     System.out.println(sum(10, 20));
     System.out.println(sum(10, 20, 30));
     System.out.println(sum(10, 20, 30, 40));
    
     System.out.println(sum(10,20,30,40,50));
     System.out.println(sum(10,20,30,40,50,60));
     System.out.println(sum(10,20,30,40,50,60,70));
     System.out.println(sum(10,20,30,40,50,60,70,80,90,100));
    

    }

// public static int sum(int b,int… a) { // return 0; // }

public static int sum(int... a) {
    int sum = 0;
    for(int i : a) {
        sum += i;
    }
    return sum;
}

}



<a name="youkg"></a>
## 10.2创建不可变集合

-  方法介绍 
   - 在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合 
      - 这个集合不能添加,不能删除,不能修改
      - 但是可以结合集合的带参构造,实现集合的批量添加
   - 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性 
      - 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中
-  示例代码 
```java
public class MyVariableParameter4 {
    public static void main(String[] args) {
        // static <E>  List<E>  of(E…elements)  创建一个具有指定元素的List集合对象
        //static <E>  Set<E>  of(E…elements)    创建一个具有指定元素的Set集合对象
        //static <K , V>   Map<K,V>  of(E…elements) 创建一个具有指定元素的Map集合对象

        //method1();
        //method2();
        //method3();
        //method4();

    }

    private static void method4() {
        Map<String, String> map = Map.ofEntries(
                Map.entry("zhangsan", "江苏"),
                Map.entry("lisi", "北京"));
        System.out.println(map);
    }

    private static void method3() {
        Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京", "wangwu", "天津");
        System.out.println(map);
    }

    private static void method2() {
        //传递的参数当中,不能存在重复的元素。
        Set<String> set = Set.of("a", "b", "c", "d","a");
        System.out.println(set);
    }

    private static void method1() {
        List<String> list = List.of("a", "b", "c", "d");
        System.out.println(list);
        //list.add("Q");
        //list.remove("a");
        //list.set(0,"A");
        //System.out.println(list);

//        ArrayList<String> list2 = new ArrayList<>();
//        list2.add("aaa");
//        list2.add("aaa");
//        list2.add("aaa");
//        list2.add("aaa");

        //集合的批量添加。
        //首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
        //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。
        ArrayList<String> list3 = new ArrayList<>(List.of("a", "b", "c", "d"));
        System.out.println(list3);
    }
}

11.Stream流

11.1体验Stream流

  • 案例需求
    按照下面的要求完成集合的创建和遍历
    • 创建一个集合,存储多个字符串元素
    • 把集合中所有以”张”开头的元素存储到一个新的集合
    • 把”张”开头的集合中的长度为3的元素存储到一个新的集合
    • 遍历上一步得到的集合
  • 原始方式示例代码 ```java public class StreamDemo { public static void main(String[] args) {

     //创建一个集合,存储多个字符串元素
     ArrayList<String> list = new ArrayList<String>();
    
     list.add("林青霞");
     list.add("张曼玉");
     list.add("王祖贤");
     list.add("柳岩");
     list.add("张敏");
     list.add("张无忌");
    
     //把集合中所有以"张"开头的元素存储到一个新的集合
     ArrayList<String> zhangList = new ArrayList<String>();
    
     for(String s : list) {
         if(s.startsWith("张")) {
             zhangList.add(s);
         }
     }
    

// System.out.println(zhangList);

    //把"张"开头的集合中的长度为3的元素存储到一个新的集合
    ArrayList<String> threeList = new ArrayList<String>();

    for(String s : zhangList) {
        if(s.length() == 3) {
            threeList.add(s);
        }
    }

// System.out.println(threeList);

    //遍历上一步得到的集合
    for(String s : threeList) {
        System.out.println(s);
    }
    System.out.println("--------");

    //Stream流来改进

// list.stream().filter(s -> s.startsWith(“张”)).filter(s -> s.length() == 3).forEach(s -> System.out.println(s)); list.stream().filter(s -> s.startsWith(“张”)).filter(s -> s.length() == 3).forEach(System.out::println); } }



-  使用Stream流示例代码 
```java
public class StreamDemo {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //Stream流来改进
        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
    }
}
  • Stream流的好处
    • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
    • Stream流把真正的函数式编程风格引入到Java中
    • 代码简洁

11.2Stream流的常见生成方式

  • Stream流的思想
    01_Stream流思想.png
  • Stream流的三类方法
    • 获取Stream流
      • 创建一条流水线,并把数据放到流水线上准备进行操作
    • 中间方法
      • 流水线上的操作
      • 一次操作完毕之后,还可以继续进行其他操作
    • 终结方法
      • 一个Stream流只能有一个终结方法
      • 是流水线上的最后一个操作
  • 生成Stream流的方式
    • Collection体系集合
      使用默认方法stream()生成流, default Stream stream()
    • Map体系集合
      把Map转成Set集合,间接的生成流
    • 数组
      通过Arrays中的静态方法stream生成流
    • 同种数据类型的多个数据
      通过Stream接口的静态方法of(T… values)生成流
  • 代码演示

    public class StreamDemo {
     public static void main(String[] args) {
         //Collection体系的集合可以使用默认方法stream()生成流
         List<String> list = new ArrayList<String>();
         Stream<String> listStream = list.stream();
    
         Set<String> set = new HashSet<String>();
         Stream<String> setStream = set.stream();
    
         //Map体系的集合间接的生成流
         Map<String,Integer> map = new HashMap<String, Integer>();
         Stream<String> keyStream = map.keySet().stream();
         Stream<Integer> valueStream = map.values().stream();
         Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
    
         //数组可以通过Arrays中的静态方法stream生成流
         String[] strArray = {"hello","world","java"};
         Stream<String> strArrayStream = Arrays.stream(strArray);
    
           //同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流
         Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
         Stream<Integer> intStream = Stream.of(10, 20, 30);
     }
    }
    

11.3Stream流中间操作方法

  • 概念
    中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
  • 常见方法
    | 方法名 | 说明 | | —- | —- | | Stream filter(Predicate predicate) | 用于对流中的数据进行过滤 | | Stream limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 | | Stream skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 | | static Stream concat(Stream a, Stream b) | 合并a和b两个流为一个流 | | Stream distinct() | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |

  • filter代码演示

    public class StreamDemo01 {
     public static void main(String[] args) {
         //创建一个集合,存储多个字符串元素
         ArrayList<String> list = new ArrayList<String>();
    
         list.add("林青霞");
         list.add("张曼玉");
         list.add("王祖贤");
         list.add("柳岩");
         list.add("张敏");
         list.add("张无忌");
    
         //需求1:把list集合中以张开头的元素在控制台输出
         list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
         System.out.println("--------");
    
         //需求2:把list集合中长度为3的元素在控制台输出
         list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
         System.out.println("--------");
    
         //需求3:把list集合中以张开头的,长度为3的元素在控制台输出
         list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
     }
    }
    
  • limit&skip代码演示

    public class StreamDemo02 {
     public static void main(String[] args) {
         //创建一个集合,存储多个字符串元素
         ArrayList<String> list = new ArrayList<String>();
    
         list.add("林青霞");
         list.add("张曼玉");
         list.add("王祖贤");
         list.add("柳岩");
         list.add("张敏");
         list.add("张无忌");
    
         //需求1:取前3个数据在控制台输出
         list.stream().limit(3).forEach(System.out::println);
         System.out.println("--------");
    
         //需求2:跳过3个元素,把剩下的元素在控制台输出
         list.stream().skip(3).forEach(System.out::println);
         System.out.println("--------");
    
         //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
         list.stream().skip(2).limit(2).forEach(System.out::println);
     }
    }
    
  • concat&distinct代码演示

    public class StreamDemo03 {
     public static void main(String[] args) {
         //创建一个集合,存储多个字符串元素
         ArrayList<String> list = new ArrayList<String>();
    
         list.add("林青霞");
         list.add("张曼玉");
         list.add("王祖贤");
         list.add("柳岩");
         list.add("张敏");
         list.add("张无忌");
    
         //需求1:取前4个数据组成一个流
         Stream<String> s1 = list.stream().limit(4);
    
         //需求2:跳过2个数据组成一个流
         Stream<String> s2 = list.stream().skip(2);
    
         //需求3:合并需求1和需求2得到的流,并把结果在控制台输出
    //        Stream.concat(s1,s2).forEach(System.out::println);
    
         //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
         Stream.concat(s1,s2).distinct().forEach(System.out::println);
     }
    }
    

11.4Stream流终结操作方法

  • 概念
    终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
  • 常见方法
    | 方法名 | 说明 | | —- | —- | | void forEach(Consumer action) | 对此流的每个元素执行操作 | | long count() | 返回此流中的元素数 |

  • 代码演示

    public class StreamDemo {
     public static void main(String[] args) {
         //创建一个集合,存储多个字符串元素
         ArrayList<String> list = new ArrayList<String>();
    
         list.add("林青霞");
         list.add("张曼玉");
         list.add("王祖贤");
         list.add("柳岩");
         list.add("张敏");
         list.add("张无忌");
    
         //需求1:把集合中的元素在控制台输出
    //        list.stream().forEach(System.out::println);
    
         //需求2:统计集合中有几个以张开头的元素,并把统计结果在控制台输出
         long count = list.stream().filter(s -> s.startsWith("张")).count();
         System.out.println(count);
     }
    }
    

11.5Stream流的收集操作

  • 概念
    对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
  • 常用方法
    | 方法名 | 说明 | | —- | —- | | R collect(Collector collector) | 把结果收集到集合中 |

  • 工具类Collectors提供了具体的收集方式
    | 方法名 | 说明 | | —- | —- | | public static Collector toList() | 把元素收集到List集合中 | | public static Collector toSet() | 把元素收集到Set集合中 | | public static Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |

  • 代码演示

    public class CollectDemo {
     public static void main(String[] args) {
         //创建List集合对象
         List<String> list = new ArrayList<String>();
         list.add("林青霞");
         list.add("张曼玉");
         list.add("王祖贤");
         list.add("柳岩");
    
         /*
         //需求1:得到名字为3个字的流
         Stream<String> listStream = list.stream().filter(s -> s.length() == 3);
    
         //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历
         List<String> names = listStream.collect(Collectors.toList());
         for(String name : names) {
             System.out.println(name);
         }
         */
    
         //创建Set集合对象
         Set<Integer> set = new HashSet<Integer>();
         set.add(10);
         set.add(20);
         set.add(30);
         set.add(33);
         set.add(35);
    
         /*
         //需求3:得到年龄大于25的流
         Stream<Integer> setStream = set.stream().filter(age -> age > 25);
    
         //需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历
         Set<Integer> ages = setStream.collect(Collectors.toSet());
         for(Integer age : ages) {
             System.out.println(age);
         }
         */
         //定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成
         String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"};
    
         //需求5:得到字符串中年龄数据大于28的流
         Stream<String> arrayStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);
    
         //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值
         Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));
    
         Set<String> keySet = map.keySet();
         for (String key : keySet) {
             Integer value = map.get(key);
             System.out.println(key + "," + value);
         }
     }
    }
    

11.6Stream流综合练习

  • 案例需求
    现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
    • 男演员只要名字为3个字的前三人
    • 女演员只要姓林的,并且不要第一个
    • 把过滤后的男演员姓名和女演员姓名合并到一起
    • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法

  • 代码实现
    演员类

    public class Actor {
     private String name;
    
     public Actor(String name) {
         this.name = name;
     }
    
     public String getName() {
         return name;
     }
    
     public void setName(String name) {
         this.name = name;
     }
    }