Collection集合

数组和集合的区别

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

集合类体系结构

在这里插入图片描述

Collection集合概述和使用

  • Collection集合概述
    • 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
    • JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set()和List)实现。
  • 创建Collection集合对象
    • 多态的方式
    • 具体的实现类ArrayList
  • Collection集合常用方法
    在这里插入图片描述

Collection集合的遍历

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

removeIf方法

根据条件进行删除
将条件以Lambda表达式方式传入到方法中
满足就删除,不满足就不删除

collection.removeIf(
(String s)-> return s.length()==3);

满足条件s.length()==3则会删除元素。

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);
}
}
}

在迭代的过程中不能对集合长度进行就该,否则会抛出异常

例子

public static void main(String[] args) {
 Collection<String> arr=new ArrayList<String>();

 arr.add("张无忌");

 arr.add("张翠山");

 arr.add("赵敏");

 arr.add("杨不悔");
 Iterator<String> iterator = arr.iterator();
 while(iterator.hasNext()){
     String str = iterator.next();
     if(str.equals("张翠山")){
         arr.remove(str);  //这里就是对集合长度进行修改了
     }
     System.out.println(str);
 }

}
///修改后代码/
public static void main(String[] args) {
            Collection<String> arr = new ArrayList<String>();

            arr.add("张无忌");

            arr.add("张翠山");

            arr.add("赵敏");

            arr.add("杨不悔");
            Iterator<String> iterator = arr.iterator();
            while (iterator.hasNext()) {
                String str = iterator.next();
                if (str.equals("张翠山")) {
                    iterator.remove();
                }
               
            }
        System.out.println(arr);
        }

增强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);
}
}
}

单列可以使用增强for和迭代器,双列的不可以。

增强for技巧

list.for IDEA中直接生成

三种循环使用场景

- 如果需要操作索引,使用普通for循环
- 如果在遍历的过程中需要删除元素,请使用迭代器
- 如果仅仅想遍历,那么使用增强for

List集合

List集合的概述和特点

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

List集合特有方法

在这里插入图片描述

数据结构

  • 栈结构
    先进后出
  • 队列结构
    先进先出
  • 数组结构
    查询快、删除慢
  • 队列结构
    查询慢、增删快

List集合的实现类

特点

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

List集合概述

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

List集合特点
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复

LinkedList集合的特有功能

在这里插入图片描述

泛型

  • 提供了编译时类型安全检测机制
  • 范型的好处
    • 把运行时的问题提前到编译时期
    • 避免了强制转换类型
  • 范型的定义格式
    <类型>:指定一个类型的格式,尖括号里任意书写,一般只写一个字母
    <类型1,类型2.,>:指定多种类型的格式,多种类型之间用逗号隔开

泛型类

  • 定义格式
    修饰符 class 类名<类型>{}
public class Generic<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}

泛型方法

  • 定义格式
    修饰符 <类型> 返回值类型 方法名(类型 变量名){}
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);
}
}

泛型接口

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

public interface Generic<T> {
void show(T t);
}
  • 泛型接口实现类
    定义实现类时,定义和接口相同泛型,创建实现类对象时明确泛型的具体类型
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);
}
}

类型通配符

类型通配符: <?>
ArrayList<?>: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型
类型通配符上限: <? extends 类型>
ArrayListList <? extends Number>: 它表示的类型是Number或者其子类型
类型通配符下限: <? super 类型>
ArrayListList <? super Number>: 它表示的类型是Number或者其父类型
泛型通配符的使用
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){}
}

定义一个集合,并把集合(集合里面的元素是Integer)转成存有相同元素的数组,并将结果输出在控制台。(可以使用Object[]数组类型接收转换的数组)

public class CollectionTest03 {
    public static void main(String[] args) {
        //定义集合,添加数据
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(100);
        list.add(200);
        list.add(300);
        //Object[] toArray()转换成一个Object数组
        Object[] obj =  list.toArray();
        // 遍历数组
        for (int i = 0; i < obj.length; i++) {
            System.out.println(obj[i]);
        }
    }
}

Set

set集合概述和特点

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

集合的使用

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);
}
}
}

TreeSet

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

Treeset集合基本使用

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);
}
}
}

自然排序Commparable的使用

案例需求
存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
实现步骤

  1. 使用空参构造创建TreeSet集合
    用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
  2. 自定义的Student类实现Comparable接口
    自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
  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;
}
}
//测试类
public class MyTreeSet2 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<>();
//创建学生对象
Student s1 = new Student("zhangsan",28);
Student s2 = new Student("lisi",27);
Student s3 = new Student("wangwu",29);
Student s4 = new Student("zhaoliu",28);
Student s5 = new Student("qianqi",30);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
//遍历集合
for (Student student : ts) {
System.out.println(student);
}
}
}

自然排序的Comparable实现逻辑

@Override
public int compareTo(Student o) {
//按照对象的年龄进行排序
//主要判断条件: 按照年龄从小到大排序
int result = this.age ‐ o.age;   //这一条this表示当前存入的对象,o表示已经存入的对象.
//次要判断条件: 年龄相同时,按照姓名的字母顺序排序
result = result == 0 ? this.name.compareTo(o.getName()) : result;
return result;
}
}

自然排序简单原理图
- 如果返回值为负,表示当前存入的元素是较小值,存左边
- 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
- 如果返回值为正数,表示当前存入的元素是较大值,存右边.
在这里插入图片描述

比较器排序Comparator的使用

存储老师对象并遍历,创建TreeSet集合使用带参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
实现步骤
用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);
}
}
}

两种方法总结

两种比较方式小结
自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行
排序
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
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);
}
}
}
在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
两种方式中关于返回值的规则
如果返回值为负数,表示当前存入的元素是较小值,存左边
如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
如果返回值为正数,表示当前存入的元素是较大值,存右边

compareTo比较字符串

将从小到大变为从大到小,只需要将this和o对调就可
int result = o.age ‐ this.age;

HashSet

HashSet集合概述和特点

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

HashSet集合的基本应用

存储字符串并遍历


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);
        }
    }
}

哈希值

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

哈希表结构

数组+链表
在这里插入图片描述

  • JDK1.8以后
    • 节点个数少于等于8个
      数组+链表
    • 节点个数多余8个
      数组+红黑树
      在这里插入图片描述

Map集合

Map集合概述和特点

  • Map集合概述
    interface Map<K,V> K:键的类型;V:值的类型
  • Map集合的特点
    • 双列集合,一个键对应一个值
    • 键不可以重复,值可以重复
    • 无序的
  • Map集合的基本使用
public class MapDemon01 {
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);
}}

Map集合的基本功能

  • 方法介绍
    在这里插入图片描述

Map集合的获取功能

  • 方法介绍
    在这里插入图片描述
public class MapDemo03{
	public static void main(String[] args){
	//创建集合对象
	Map<String,String> map = new HashMap<String,String>();
	//添加元素
	map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        //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);}

}
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);
        }
    }
}

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()方法实现
	<String> keySet = map.keySet();
        //遍历键的集合,获取到每一个键。用增强for实现
        for (String key : keySet) {
            //根据键去找值。用get(Object key)方法实现
            String value = map.get(key);
            System.out.println(key + "," + value);
        }
    }
}

Map集合的遍历(方式2)
- 获取所有键值对对象的集合
- Set> entrySet():获取所有键值对对象的集合
- 遍历键值对对象的集合,得到每一个键值对对象
- 用增强for实现,得到每一个Map.Entry
根据键值对对象获取键和值
用getKey()得到键
用getValue()得到值
代码实现

    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);
        }
    }
}

HashMap集合

概述和特点
  • HashMap底层是哈希表结构
  • 依赖hashCode方法和equals方法保证键的唯一
  • 如果键要存储的是自定义对象,需要重写hashCode和equals方法
    在这里插入图片描述
    HashMap和HashSet是一样的存储方式,但是HashMap只会比较键的值,当不为nuii是添加,当计算的键值(比如Student对象)相同时,会比较键的属性值,如name,age.如果这也一样,就会替换到原先的value,如果key相同但是属性值不相同,就会将value挂在后边。这里比较的是Entry对象,键值对。但是计算hash值时只计算键的hash值,和值无关。
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;
    }
}

测试

 public  class HashMapDemo {
    public static void main(String[] args) {
        //创建HashMap集合对象
        HashMap<Student, String> hm = new HashMap<Student, String>();
 
        //创建学生对象
        Student s1 = new Student("林青霞", 30);
        Student s2 = new Student("张曼玉", 35);
        Student s3 = new Student("王祖贤", 33);
        Student s4 = new Student("王祖贤", 33);
 
        //把学生添加到集合
        hm.put(s1, "西安");
        hm.put(s2, "武汉");
        hm.put(s3, "郑州");
        hm.put(s4, "北京");
 
        //遍历集合
        Set<Student> keySet = hm.keySet();
        for (Student key : keySet) {
            String value = hm.get(key);
            System.out.println(key.getName() + "," + key.getAge() + "," + value);
        }
    }
}

forEach方法遍历Map

hm.forEach((Student key,String value)->{
System.out.println(key+value);});

在这里插入图片描述

TreeMap

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

TreeMap集合应用案例一

  • 创建一个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;
    }
     }

测试类

 class Test1 {
    public static void main(String[] args) {
       // 创建TreeMap集合对象   
        TreeMap<Student,String> tm = new TreeMap<>();
      
// 创建学生对象         
        Student s1 = new Student("xiaohei",23);
        Student s2 = new Student("dapang",22);
        Student s3 = new Student("xiaomei",22);
      
// 将学生对象添加到TreeMap集合中         
        tm.put(s1,"江苏");
        tm.put(s2,"北京");
        tm.put(s3,"天津");
      
// 遍历TreeMap集合,打印每个学生的信息         
        tm.forEach(
                (Student key, String value)‐>{
                    System.out.println(key + "‐‐‐" + value);
                }
        );
    }
}

比较器模式不需要实现接口,直接使用匿名内部类的方式实现。

可变参数

可变参数:就是形参的个数是可以变化的
- 格式:修饰符 返回值类型 方法名(数据类型… 变量名) { }
- 方法的参数类型已经确定,个数不确定,我们可以使用可变参数

可变参数注意事项
- 这里的变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

                //存在,表示当前字符已经出现过了
                //先获取这个字符已经出现的次数
                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 + ")");
                }
        );
    }
}
修饰符 返回值类型 方法名(数据类型… 变量名) {  }
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;
    }
}

创建不可变集合

方法介绍

  • 在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合
    - 这个集合不能添加,不能删除,不能修改
    - 但是可以结合集合的带参构造,实现集合的批量添加
  • 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性
    • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中
//    }
 
    public static int sum(int... a) {
        int sum = 0;
        for(int i : a) {
            sum += i;
        }
        return sum;
    }
}
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);
    }
}

Map遍历的原理

Map中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在Map中是一一对应关系,这一对对象又称做Map 中的一个Entry(项)。Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。

Stream流

Stream流的好处

  • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤、打印
  • Stream流把真正的函数式编程风格引入Java中
  • 代码简洁

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);
    }
}

Stream流中间操作方法

在这里插入图片描述
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);
    }
}
//filter中接口Predicate接口只有一个抽象方法test
list.stream().filter(new Predicate<String>() {
public boolean test(String s){
boolean result = s.startsWith("张");
return result;
}})
//所以我们可以用Lambda表达式来简化方法
//s表示流中的每一个数据,后边的表示条件
list.stream.filter(s->s.startwith("z")).forEach(s->System.out.println(s));

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);
    }
}

Stream流终结操作方法

终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
在这里插入图片描述
void forEach(Consumer action):对此流的每个元素执行操作

Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
//forEach方法的底层会循环获取到流中的每一个数据
//并循环调用accept方法,并把每一个数据传递给accept方法
//s就依次表示了流中的每一个数据
//所以我们要在accept方法中,写上处理逻辑就可
//Lambda表达式简化格式
//因为Consumer接口中,只有一个accept方法
long count = list.stream().filter(s ‐> s.startsWith("张")).count();
System.out.println(count);

Stream流,不能直接操作数据源如数组,集合中数据

Stream流的收集操作

对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
在这里插入图片描述
在这里插入图片描述

//collect负责收集数据
	//获取流中剩余数据,但他不负责创建容器,也不负责把数据添加到容器中
	//collectors.tolist():在底层创建一个list集合,并把所有的数据添加到list集合中
	List<Integer> list = list1 .stream().filter(number -. number %2 ==0).collect(collectors.toList());
	System.out.println(list);

代码示例

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);
        }
    }
}
/**
 * Stream流的收集方法
 *
 * 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
 * "zhangsan,23"
 * "lisi,24"
 * "wangwu,25"
 * 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
 */
 public class MyStream8 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("zhangsan,23");
        list.add("lisi,24");
        list.add("wangwu,25");
        Map<String, Integer> map = list.stream().filter(
                s -> {
                    String[] split = s.split(",");
                    int age = Integer.parseInt(split[1]);
                    return age >= 24;
                }
                //   collect方法只能获取到流中剩余的每一个数据.
         //在底层不能创建容器,也不能把数据添加到容器当中
         //Collectors.toMap 创建一个map集合并将数据添加到集合当中
          // s 依次表示流中的每一个数据
           //第一个lambda表达式就是如何获取到Map中的键
          //第二个lambda表达式就是如何获取Map中的值
        ).collect(Collectors.toMap(
                s -> s.split(",")[0],  //获取键
                s -> Integer.parseInt(s.split(",")[1]) ));//获取值
                System.out.println(map);
                }
                }
         

重写的hashCode()

意思是对于同一个类,他们的对象的哈希值是一样的,但是不同对象的hash值也可能是一样的,这种情况下会将值挂在原来哈希表存储位置的下边。

单列集合,双列集合,数组分别是如何获取Stream流对象的

1、java.util.Collection接口中加入了default方法stream()获取流对象,因此其所有实现类均可通过此方式获取流。

2、java.util.Map接口想要获取流,先通过keySet()、values()或entrySet()方法获取键、值或键值对的单列集合,再通过stream()获取流对象。

3、数组获取流,使用Stream接口中的的静态方法of(T...values)获取流。

public static void main(String[] args) {

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

  Stream<String> stream1 = list.stream();

  Set<String> set = new HashSet<>();

  Stream<String> stream2 = set.stream();

  Map<String, String> map = new HashMap<>();

  Stream<String> keyStream = map.keySet().stream();

  Stream<String> valueStream = map.values().stream();

  Stream<Map.Entry<String,String>>entryStream = map.entrySet().stream();

  String[] array = {"东邪", "西毒", "南帝", "北丐", "中神通"};

  Stream<String> stream = Stream.of(array);

 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值