学习:JAVASE_9 数据结构/泛型/可变参数/集合/排序查找算法/异常

数据结构

数据结构是计算机存储,组织数据的方式.是指相互之间存在一种或多种特定关系的数据元素的集合

通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率

栈:先进后出

队列:先进先出

数组:查询快,增删慢 是一块连续的内存空间

链表:增删快,查询慢 是不连续的内存空间

树结构:

  • 树结构特点

    • 每一个节点有零个或者多个子节点

    • 没有父节点的节点称之为根节点,一个树最多有一个根节点

    • 每一个非根节点有且只有一个父节点

  • 名词解释

    • 节点:指树中的一个元素

    • 节点的度:节点拥有的子树的个数,二叉树的度不大于2

    • 叶子结点:度为0的节点,也称为终端节点

    • 高度:叶子结点的高度为1,叶子结点的父节点高度为2,以此类推,根节点的高度最高

    • 层:根节点在第一层,以此类推

    • 父节点:若一个节点含有子节点,则这个节点称之为其子节点的父节点

    • 子节点:子节点是父节点的下一层节点

    • 兄弟节点:拥有共同父节点的节点互称为兄弟节点

  • 平衡二叉树

    • 结构特地啊

      • 左右两个子树的高度差绝对值不超过1,并且左右两个子树都是一颗平衡二叉树

      • 避免出现"瘸子"现象,减少树的高度,提高了搜索效率

  • 红黑树

    • 红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构

    • 结构特性

      • 根节点是黑色,其他节点是红色或黑色

      • 每个红色节点的两个子节点都是黑色

      • 如果一个节点没有儿子,我们称之为叶子结点,红黑树中,叶子被假定为null或空,每个叶子结点(Nil)是黑色的

      • 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点

    • 结构特点:趋近于平衡树,查询速度块

    • 平衡原理:

      • 红黑树的每一个节点上都有存储位表示接地那的颜色,可以是红或者黑

      • 添加元素原理:每一次插入完毕以后,使用红黑色规则进行校验,如果不满足红黑规则,就需要左旋和右旋来调整树,使其满足红黑规则

泛型

是JDK5中引入的特性,他提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型

他的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参.name参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,然后再使用/调用时传入具体的类型

这种参数类型可以用在类,方法,或接口中,分别称为泛型类,泛型方法,泛型接口

泛型定义格式:

  • <类型>:指定一种类型的格式,这里的类型可以看成是形参

  • <类型1,类型2...>:指定多种类型的格式,多种类型之间用逗号隔开,这里的类型可以看成是形参

  • 将来具体调用的时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

泛型的好处:

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

避免了强制类型转换

ArrayList objects = new ArrayList<>();
objects.add("11");
objects.add(11);
for (int i = 0; i < objects.size(); i++) {
String s = (String) objects.get(i); // 该处会报类型转换异常
}

ArrayList<String> strings = new ArrayList<>();
strings.add("11");
strings.add(11); // 添加了泛型后再编译期就会报错
for (String string : strings) {
System.out.println(string);
}
泛型类 
// 泛型类的定义格式
// 格式:修饰符 class 类名<类型>{}
// 此处T可以随便写任意标识,常见的如T,E,K,V等形式的参数常用语表示泛型
public class Generic <T>{
  // 在泛型类中定义泛型的数据类型变量,可以在创建对象的时候再进行指定需要的数据类型
  private T t;

  public Generic() {
  }

  public Generic(T t) {
    this.t = t;
  }
  public T getT() {
    return t;
  }

  public void setT(T t) {
    this.t = t;
  }
}

Generic<String> stringGeneric = new Generic<>();
stringGeneric.setT("string");
泛型方法 
// 泛型方法的定义格式
// 格式: 修饰符<类型> 返回值类型 方法名(类型 变量名) { }
public class Generic {
    public <T> void show(T t) {
        System.out.println(t);
    }
}
// 测试
Generic generic = new Generic();
generic.show("show");
generic.show(11);
泛型接口
// 泛型接口的定义格式
// 格式: 修饰符 interface 接口名<类型> {}
public interface InterfaceTest<T> {
    void show(T t);
}
// 实现类
public class InterfaceTestImpl<T> implements InterfaceTest<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
// 测试
InterfaceTest<String> interfaceTest = new InterfaceTestImpl();
interfaceTest.show("sss");
 
类型通配符

为了表示各种泛型List的父类,可以使用类型通配符

  • 类型通配符:<?>

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

  • 这种带通配符的List仅表示他是各种泛型List的父类,并不能把元素添加到其中

如果说我们不希望List<?>是任何泛型List的父类,只希望他代表某一泛型List的父类或子类,可以使用类型通配符的上限或下限

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

  • List<? extends Number>: 他表示类型是Number或者其子类型

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

  • List<? super Number>: 他表示类型是Number或者其父类型

ArrayList<? extends List> list = new ArrayList<ArrayList>();
ArrayList<? extends List> list2 = new ArrayList<List>();
ArrayList<? super List> list3 = new ArrayList<List>();
ArrayList<? super List> list4 = new ArrayList<Collection>();

可变参数

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

// 格式: 修饰符 返回值类型 方法名(数据类型...变量名){}
public void show(String... s){
// 可变参数会被封装到一个数组中
System.out.println(s.length);
}
// 可变参数的注意事项
// 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
// 一个方法只可以有一个可变参数

可变参数的使用

方法说明
Arrays工具类中的静态方法public static<T>List<T>asList(T...a)返回由指定数组支持的固定大小的列表
List接口中的静态方法JDK9新特性public static<E>List<E>of(E...elements)返回包含任意数量元素的不可变列表
Set接口中的静态方法JDK9新特性public static<E>Set<E>of(E...elements)返回一个包含任意数量元素的不可变集合
Collections工具类中的静态方法public static <T> boolean addAll(Collection<T> c,T... elements)将可变参数中所有的内容,都添加到指定集合中
// asList方法返回的集合不可以做增删操作,可以做修改操作
List<String> list1 = Arrays.asList("11", "22");
//        list1.add("33"); // UnsupportedOperationException
//        list1.remove(1); // UnsupportedOperationException
list1.set(1,"44");
// List接口中的of方法时JDK9的新特性,返回的集合不可以做增删改操作
List<String> list5 = List.of("11", "22", "33");
//        list5.add("44"); // UnsupportedOperationException
//        list5.remove("11"); // UnsupportedOperationException
//        list5.set(1,"88"); // UnsupportedOperationException
// Set接口中的of方法是JDK9的新特性,返回的集合不能做增删操作,没有修改的方法,在给元素的时候,不能给重复的元素
Set<String> set1 = Set.of("11", "33", "55");
//        Set<String> set2 = Set.of("11", "33", "55","22"); // UnsupportedOperationException
//        set1.add("11");// UnsupportedOperationException
//        set1.remove("11");// UnsupportedOperationException
}

集合

  • 特点:提供一种存储空间可变的存储模型,存储的数据容量可以发生改变

集合类的体系结构

  • 单列集合Collection接口

    • List接口:可重复

      • ArrayList实现类

      • LinkedList实现类

    • Set接口:不可重复

      • HashSet实现类

      • TreeSet实现类

  • 双列集合Map接口

    • HashMap实现类

Collection

Collection集合概述

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

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

Collection集合常用方法
方法名说明
boolean add(E e)添加元素
boolean remove(Object o)从集合中移除指定的元素
void clear()清空集合中的元素
boolean contains(Object o)判断集合中是否存在指定的元素
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中元素的个数
Iterator<E> iterator()返回此集合的迭代器
Collection集合的遍历

Iterator:迭代器,集合的专用遍历方式

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

  • 迭代器是通过集合的iterator()方法得到的,所以我们说他是依赖于集合而存在的

Iterator中的常用方法

方法说明
E next()返回迭代中的下一个元素
boolean hasNext()如果迭代具有更多元素,则返回true
default void remove()使用迭代器删除集合中的元素
// 创建集合,并往集合中添加元素
Collection<String> collection = new ArrayList<String>();
collection.add("hello");
collection.add("world");
collection.add("java");
// 获取集合的迭代器
Iterator<String> iterator = collection.iterator();
/*        System.out.println(iterator.next());
        System.out.println(iterator.next());
        System.out.println(iterator.next());
        System.out.println(iterator.next()); //NoSuchElementException*/

// 判断集合中是否还有元素,如果有的话就进行输出
while (iterator.hasNext()) {
  String next = iterator.next();
  System.out.println(next);
}
并发修改异常

使用集合获取迭代器后,使用迭代器的next()方法会去判断集合的可修改次数是否发生了改变,如果发生了改变就会报错

  • ConcurrentModificationException

  • 产生原因

  • 迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改至不一致

  • 解决方法

  • 用for循环遍历,然后用集合对象做对应的操作即可

增强for循环

增强for:简化数组和collection集合的遍历

  • 实现Iterable接口的类允许其对象称为增强型for语句的目标

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

增强for的格式

 

for(元素数据类型 变量名:数组或者Collection集合) {
// 在此处使用变量即可,该变量就是元素
}
int[] arr = {1, 2, 3};
for (int i : arr) {
  System.out.println(i);
}

Collection<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
list1.add("java");
for (String s : list1) {
  if (s.equals("hello")) {
    list1.add("javaee"); // ConcurrentModificationException 并发修改异常
  }
  System.out.println(s);
}
Set

不包含重复元素的集合

HashSet集合存储元素

  • 要保证元素唯一性,需要重写hashCode()和equals()方法

没有带索引的方法,所以不能使用普通for循环遍历

HashSet:对集合的迭代顺序不作任何保证

Set<String> set = new HashSet<>();
set.add("hello");
set.add("world");
set.add("java");
set.add("java");
for (String s : set) {
  System.out.println(s); //world java hello
}
// hashSet是通过hashCode和equals方法保证元素的唯一
// hashSet存储自定义对象,自定义对象需要重写hashCode和equals方法来保证元素的唯一

LinkedHashSet

特点

  • 哈希表和链表实现的Set接口,具有可预测的迭代次序

  • 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的

  • 由哈希表保证元素唯一,也就是说没有重复的元素

TreeSet

特点

  • 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法

  • 没有带索引的方法,所以不能使用普通for循环遍历

  • 由于是Set集合,所以不包含重复元素的集合

注意事项:

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

  • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(To)方法

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

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

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return age == student.age && Objects.equals(name, student.name);
  }

  @Override
  public int hashCode() {
    return Objects.hash(name, 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) {
    //按照年龄从小到大顺序排序,年龄相同时根据姓名的字母顺序进行排序
    // 返回值是正数的话就是从小到大排序,负数就是从大到小,返回值为0则不会向TreeSet中添加该元素
    int num = this.age - o.age;
    return  num == 0 ? this.name.compareTo(o.name) : num;

  }
}

// 测试类
Set<Student> set = new TreeSet<>();
set.add(new Student("2l",22));
set.add(new Student("1mz",22));
set.add(new Student("mlz",24));
set.add(new Student("zml",25));
for (Student s: set) {
  System.out.println(s);
}
// 如果自定义引用数据类型没有实现Comparator接口则可以使用带参构造方法来创建TreeSet集合
TreeSet<Student> students = new TreeSet<>(new Comparator<Student>() {
  @Override
  public int compare(Student o1, Student o2) {
    int num = o1.getAge() - o2.getAge();
    return num == 0 ? o1.getName().compareTo(o2.getName()) : num;
  }
});
students.add(new Student("test",22));
students.add(new Student("test",21));
students.add(new Student("test",23));
Iterator<Student> iterator = students.iterator();
while (iterator.hasNext()) {
  Student next = iterator.next();
  System.out.println(next);
}
构造方法说明
TreeSet()根据其元素的自然顺序进行排序
TreeSet(Comparator comparator)根据指定的比较器进行排序
哈希值

是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

Object类中有一个方法可以获取对象的哈希值

pubic int hashCode():返回对象的哈希码值

对象的哈希值特点

  • 同一个对象多次的调用hashCode()方法返回的哈希值是相同的

  • 默认情况下,不同对象的哈希值是不同的,而重写hashCode()方法.可以实现让不同对象的哈希值相同

哈希表

JDK8之前,底层采用数组+链表实现可以说是一个元素为链表的数组

JDK8以后,在长度比较长的时候,底层实现了优化

默认初始长度是16

List
  • 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置.用户可以通过整数索引访问元素,并搜索列表中的元素

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

特点:

  • 有序:存储和取出的元素顺序一致

  • 可重复:存储的元素可以重复

List集合常用子类:ArrayList,LinkedList

  • ArrayList:底层数据结构是数组,查询快,增删慢

  • LinkedList:底层数据结构是链表,查询慢,增删快

List集合中的特有方法:

方法名说明
void add(int index,E element)在此集合中的指定位置插入指定的元素
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index,E element)修改指定索引处的元素,返回被修改的元素
E get(int index)返回制定索引处的元素
int size()返回集合中元素的个数
ListIterator listIterator()返回list集合中的特有迭代器
public static <E>List<E>of(E...elements)返回包含任意数量元素的不可变列表
ListIterator

列表迭代器

  • 通过List集合的listIterator()方法得到,所以说他是List集合特有的迭代器

  • 用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置

ListIterator()中的常用方法

方法名说明
E next()返回迭代中的下一个元素
E previous()返回列表中的上一个元素
boolean hasNext()如果迭代具有更多元素则返回true
boolean hasPrevious()如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
void add(E e)将指定的元素插入列表

ListIterator中的add方法不会出现并发修改异常,因为在add方法中会将实际修改值赋值给预期修改值

LinkedList

LinkedList集合的特有功能

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

<!--Class ArrayList<E> 可以调整大小的数组实现 <E>是一种特殊的数据类型,泛型-->

构造方法
方法名说明
public ArrayList()创建一个空的集合对象
常用方法
方法名说明
public boolean add(E e)将指定元素追加到此集合的末尾
public void add(int index, E element)在此集合中的指定位置插入指定的元素
public int size()获取集合的长度
public E get(int index)获取集合中索引处的元素
public boolean remove(Object obj)删除指定的元素,返回删除是否成功
public E remove(int index)删除指定索引处的元素,返回被删除的元素
public E set(int index, E element)修改指定索引处的元素,返回被修改的元素
ArrayList<String> list = new ArrayList<String>(); // 后面的泛型可以省略,是JDK7以后的新特性
boolean hello = list.add("hello");
list.add("word");
list.add("java");
//        list.add(5,"javase");  IndexOutOfBoundsException
学生管理系统案例

 

/**
 *  学生类
 * @author zml
 * @date 2021年11月07日18:20:30
 */
public class Student {
    /**
     * 学号
     */
    private String sid;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private String age;
    /**
     * 居住地
     */
    private String address;

    public Student() {
    }

    public Student(String sid, String name, String age, String address) {
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
/**
 * 学生管理系统
 *
 * @author zml
 * @date 2021年11月07日18:25:18
 */
public class StudentManager {
    private static Scanner sc = new Scanner(System.in);
    private static ArrayList<Student> students = new ArrayList<>();

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

    /**
     * 首页
     */
    public static void homePage() {
        while (true) {
            System.out.println("-------欢迎来到学生管理系统-------");
            System.out.println("1:添加学生");
            System.out.println("2:删除学生");
            System.out.println("3:修改学生");
            System.out.println("4:查看所有学生");
            System.out.println("5: 退出");
            System.out.println("请输入你的选择");

            String num = sc.nextLine();
            switch (num) {
                case "1":
                    insertStudent();
                    break;
                case "2":
                    deleteStudent();
                    break;
                case "3":
                    updateStudent();
                    break;
                case "4":
                    showStudent();
                    break;
                case "5":
                    System.out.println("谢谢使用");
//                    System.exit(0);
                    return;
                default:
                    System.out.println("你输入的信息有误,请重新输入");
            }
        }
    }

    /**
     * 添加学生
     */
    public static void insertStudent() {
        String sid = "";
        boolean flag = true;
        while (flag) {
            System.out.println("请输入学生学号");
            sid = sc.nextLine();
            flag = checkStudentsId(sid);
            if (flag) {
                System.out.println("您输入的学号已存在,请重新输入");
            }
        }
        System.out.println("请输入学生姓名");
        String name = sc.nextLine();
        System.out.println("请输入学生年龄");
        String age = sc.nextLine();
        System.out.println("请输入学生居住地");
        String address = sc.nextLine();
        Student student = new Student(sid, name, age, address);
        students.add(student);
        System.out.println("添加学生成功");
    }

    public static void deleteStudent() {
        System.out.println("请输入你要删除的学生学号");
        ArrayList<String> names = new ArrayList<>();
        String sidNum = sc.nextLine();
        int flag = students.size();
        for (int i = students.size() - 1; i >= 0; i--) {
            Student student = students.get(i);
            String sid = student.getSid();
            if (sid.equals(sidNum)) {
                Student stu = students.remove(i);
                String name = stu.getName();
                names.add(name);
            }
        }
        if (students.size() < flag) {
            System.out.println("删除学生成功,删除的学生有:" + names);
        } else {
            System.out.println("你输入的学号不存在");
        }
    }

    public static void updateStudent() {
        System.out.println("请输入你要修改的学号");
        String sidNum = sc.nextLine();
        for (int i = 0; i < students.size(); i++) {
            Student student = students.get(i);
            if (student.getSid().equals(sidNum)) {
                System.out.println("请输入新学生姓名");
                String name = sc.nextLine();
                students.get(i).setName(name);
                System.out.println("请输入新学生年龄");
                String age = sc.nextLine();
                students.get(i).setAge(age);
                System.out.println("请输入新学生居住地");
                String address = sc.nextLine();
                students.get(i).setAddress(address);
//                Student stu = new Student(sidNum, name, age, address);
//                students.set(i, stu);
                System.out.println("修改学生信息成功");
            } else {
                System.out.println("你输入的学号不存在");
            }
        }
    }

    public static void showStudent() {
        if (students.size() == 0) {
            System.out.println("无学生,请先添加");
            return;
        }
        for (int i = 0; i < students.size(); i++) {
            Student student = students.get(i);
            System.out.println(student.getSid() + "\t\t" + student.getName()
                    + "\t" + student.getAge() + "\t" + student.getAddress());
        }
    }

    public static boolean checkStudentsId(String sid) {
        boolean flag = false;
        for (int i = 0; i < students.size(); i++) {
            String sid1 = students.get(i).getSid();
            if (sid.equals(sid1)) {
                flag = true;
            }
        }
        return flag;
    }
  public static void updateStudent() {
        System.out.println("请输入你要修改的学号");
        String sidNum = sc.nextLine();
        for (int i = 0; i < students.size(); i++) {
            Student student = students.get(i);
            if (student.getSid().equals(sidNum)) {
                System.out.println("请输入新学生姓名");
                String name = sc.nextLine();
                students.get(i).setName(name);
                System.out.println("请输入新学生年龄");
                String age = sc.nextLine();
                students.get(i).setAge(age);
                System.out.println("请输入新学生居住地");
                String address = sc.nextLine();
                students.get(i).setAddress(address);
//                Student stu = new Student(sidNum, name, age, address);
//                students.set(i, stu);
                System.out.println("修改学生信息成功");
            } else {
                System.out.println("你输入的学号不存在");
            }
        }
  }
}

// 此代码方法可以再进行抽取,有时间的话可以进行优化

 

Map

Map集合概述

  • Interface Map<K,V> K:键的类型;V:值得类型

  • 将键映射到值得对象;不能包含重复的键;每个键可以映射到最多一个值

  • 一般使用其实现类HashMap来创建对象,TreeMap是有序Map集合

  • 集合中的键相同的话,新的值会替换掉旧值

HashMap

HashMap在JDK1.7:是由数组加链表组成

多线程情况下+reHash会产生环形链表:多线程和扩容的时候

创建HashMap集合的时候直接初始化Hash表

JDK1.8的HashMap:是由数组加链表加红黑树组成O(n)-O(logn)

扰动函数:(h=key.hashCode())^(h>>>16)

路由寻址(n-1)&hash n:数组的长度

hash冲突(碰撞):通过hash值,计算出来位置之后,两个元素的位置相同

HashMap解决hash冲突使用的拉链法(尾插)

map集合的常用方法

方法名说明
V put(K key,V value)添加元素,K重复的情况下会使用新值替换掉旧值
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()获取所有键值对对象的集合

Map.Entry对象的方法

方法名说明
K getKey()获取键
V getValue()获取值
V setValue(V value)设置entry对象的值
// 创建map集合,并添加元素
Map<Integer,String> map = new HashMap<>();
map.put(1,"hello");
map.put(2,"world");
map.put(3,"java");
map.put(3,"javaee"); // map集合中的键重复的话,新值会取代旧值
System.out.println(map);

//        map.remove(1);  根据键删除map中的值
//        map.clear();    清空map集合
// 获取map中所有键的集合
Set<Integer> keys = map.keySet();
// 获取map中所有值得集合
Collection<String> values = map.values();
//map集合的遍历方法1:遍历键的集合,根据键到map中获取值
for (Integer key : keys) {
  System.out.println("map中的键是"+key+"map中的值是"+map.get(key));
}

// map集合的遍历方法2:获取map的键值对对象的集合,并进行遍历
Set<Map.Entry<Integer, String>> entries = map.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
  System.out.println(entry);
}
模拟斗地主案例
//模拟斗地主
//创建集合存储编号
ArrayList<Integer> arr = new ArrayList<>();
// 创建hashmap存储牌
HashMap<Integer, String> hm = new HashMap<>();
// 创建牌
String[] colors = {"♥", "♠", "♦", "♣"};
String[] numbers = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
// 定义一个变量作为编号
int index = 1;
for (int i = 0; i < numbers.length; i++) {
  for (int n = 0; n < colors.length; n++) {
    arr.add(index);
    hm.put(index, numbers[i] + colors[n]);
    index++;
  }
}
arr.add(index);
hm.put(index++, "小王");
arr.add(index);
hm.put(index, "大王");

Set<Map.Entry<Integer, String>> entries = hm.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
  System.out.println(entry);
}
// 使用Collections工具类进行洗牌
Collections.shuffle(arr);

// 创建三个人的牌加上底牌,为了保证编号是排序的,使用TreeSet集合
TreeSet<Integer> one = new TreeSet<>();
TreeSet<Integer> two = new TreeSet<>();
TreeSet<Integer> three = new TreeSet<>();
TreeSet<Integer> four = new TreeSet<>();
for (int i = 0; i < arr.size(); i++) {
  if (i > arr.size() - 4) {
    four.add(arr.get(i));
  } else if (i % 3 == 0) {
    one.add(arr.get(i));
  } else if (i % 3 == 1) {
    two.add(arr.get(i));
  } else if (i % 3 == 2) {
    three.add(arr.get(i));
  }
}

lookPoker("zml",one,hm);
lookPoker("zm",two,hm);
lookPoker("z",three,hm);
lookPoker("dp",four,hm);

}

/**
     * 定义看牌的方法
     * @param name 姓名
     * @param ts 牌的编号
     * @param hm 牌所对应的map集合
     */
public static void lookPoker(String name,TreeSet<Integer> ts,HashMap<Integer,String> hm) {
  System.out.print(name+"的牌是");
  for (Integer t : ts) {
    System.out.print(hm.get(t)+" ");
  }
  System.out.println();
}

排序查找算法

冒泡排序
int[] arr = {5, 4, 3, 2, 1};
/*
        关键点:
            外层循环-1:比较的轮数是长度-1
            内层循环:-1是为了防止索引越界
                -i:是为了提高效率
            谁和谁比较:j和j+1
         */
for (int i = 0; i < arr.length - 1; i++) {
  for (int j = 0; j < arr.length - 1 - i; j++) {
    if (arr[j] > arr[j + 1]) {
      int temp = arr[j];
      arr[j] = arr[j + 1];
      arr[j + 1] = temp;
    }
  }
}
System.out.println(Arrays.toString(arr));
选择排序
int[] arr = {5, 4, 3, 2, 1};
/*
        关键点:
            外层循环-1:比较的轮数是长度-1
            内层循环:
                j=i+1:是为了提高效率
            谁和谁比较:j和i
         */
for (int i = 0; i < arr.length - 1; i++) {
  for (int j = i + 1; j < arr.length; j++) {
    if (arr[i] > arr[j]) {
      int temp = arr[i];
      arr[i] = arr[j];
      arr[j] = temp;
    }
  }
}
System.out.println(Arrays.toString(arr));
二分查找

<!--前提,元素有序,可以不连续-->

int[] arr = {5, 4, 3, 2, 1};
// 定义要查找的数据
int target = 6;
// 定义开始索引
int start = 0;
// 定义结束索引
int end = arr.length - 1;
​
while (start <= end) {
  // 定义中间索引
  int mid = (start + end) / 2;
  if (arr[mid] > target) {
    end = mid - 1;
  } else if (arr[mid] < target) {
    start = mid + 1;
  } else {
    System.out.println(mid);
  }
}

异常

异常:就是程序出现了不正常的情况

Throwable:异常的顶级父类

  • Error:严重问题,不需要处理,一般为硬件问题

  • Exception:称为异常类,他表示程序本身可以处理的问题

    • RuntimeException:在编译期是不检查的,出现问题后,需要我们回来修改代码

    • 非RuntimeException:编译期就必须处理的,否则程序不能通过变异,就更不能正常运行了

虚拟机默认处理异常的方式:

  • 将异常类名,信息和位置,打印到控制台,程序停止运行

异常处理之throws

格式:throws 异常类名

注意:这个格式是跟在方法的括号后面的

  • 编译时异常必须要进行处理,两种处理方案:try...catch或者throws,如果采用throws这种方案,将来谁来调用谁处理

  • 运行时异常可以不处理,出现问题后,需要我们回来修改代码

异常处理之try...catch

IDEA快捷键:option+command+t

程序从try里面的代码开始执行

出现异常,会自动生成一个异常类对象,该异常类对象将被提交给Java运行时系统

当Java运行时系统接收到异常对象时,会到catch中去找匹配的异常类,找到后进行异常的处理

执行完毕后,程序还可以继续往下执行

// 格式
try {
			可能出现异常的代码;
} catch(异常类名 变量名) {
			异常的处理代码;
}
try {
  int[] arr = {1,2,3};
  System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException e) {
  System.out.println("你访问的数组的索引不存在");
  e.printStackTrace();
}
异常处理之try..catch...finally

finally:在异常处理时提供finally块来执行所有清除操作.比如IO流中的释放资源

特点:被finally控制的语句一定会执行,除非JVM退出

 

//格式
try{
  可能出现异常的代码;
}catch(异常名 变量名){
  异常的处理代码;
}finally{
  执行所有清除操作;
}
// 异常抓取
FileOutputStream fos = null;
try {
  fos = new FileOutputStream("/Users/zhumingli/Desktop/txt/java.txt", true);
  for (int i = 0; i < 10; i++) {
    fos.write("hello".getBytes());
    fos.write("\r\n".getBytes());
  }
} catch (IOException e) {
  e.printStackTrace();
} finally {
  if (fos != null) {
    try {
      fos.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

// JDK7之后针对流的异常改进方案
try(定义流对象){
  可能出现异常的代码;
}catch(异常类名 变量名){
  异常的处理代码;
}
资源会自动释放
 
//JDK9之后的异常改进方案
定义输入流对象;
定义输出流对象;
try(输入流对象;输出流对象){
  可能出现异常的代码
}catch(异常类名 变量名){
  异常的处理代码;
}
资源会自动释放
Throwable的成员方法
方法名说明
public String getMessage()返回此throwable的详细消息字符串
public String toString()返回此 可抛出的简短描述
public void printStackTrace()把异常的错误信息输出在控制台
自定义异常
// 创建异常类继承Exception,并给出构造方法
public class ScoreException extends Exception{
    public ScoreException() {
    }

    public ScoreException(String message) {
        super(message);
    }
}

// 测试类进行测试
public class ScoreTest {
    public static void main(String[] args) throws ScoreException {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你的分数");
        int i = sc.nextInt();
        if (i > 100 || i < 0) {
//            throw new ScoreException();
            throw new ScoreException("分数应该在0-100之间");
        } else {
            System.out.println("分数正常");
        }
    }
}
throws和throw的区别
throwsthrow
用在方法声明后面,跟的是异常类名用在方法体内,跟的是异常对象名
表示抛出异常,由该方法的调用者来处理表示抛出异常,有方法体内的语句处理
表示出现异常的一种可能性,并不一定会发生这些异常执行throw一定抛出了某种异常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值