011_异常、泛型和集合框架

发布于:2025-04-09 ⋅ 阅读:(31) ⋅ 点赞:(0)

异常

  • 异常代表程序出现的问题。

Java的异常体系

  • Java.lang.Throwable
    • Error
    • Exception
      • RuntimeException
      • 其他异常…
  • Error:代表的系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun公司会把这些问题封装为Error对象给出来。
  • Exception:叫异常:它代表的才是我们程序可能出现的问题,所以通常会用Exception以及它的孩子来封装程序出现的问题。
  • 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常
  • 编译时异常:“其他异常…” 编译阶段就会出现错误提醒的。
  • 抛出异常(throws)
    • 在方法上使用throws关键字,可以将方法内部出现的异常抛出去给调用者处理。
方法 throws 异常1 ,异常2 ,异常3 ..{}
  • 捕获异常(try…catch)
    • 直接捕获程序出现的异常。
try{
    // 监视可能出现异常的代码!
}catch(异常类型1 变量){
    // 处理异常
}catch(异常类型2 变量){
    // 处理异常
}...

异常的作用

  • 异常使用来定位程序bug的关键信息。
  • 可以作为方法内部的一种特殊返回值,以便通知上层调用者,方法的执行问题。

自定义异常

  • Java无法为这个世界上全部的问题都提供异常类来代表, 如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
  • 自定义运行时异常
    • 定义一个异常继承RuntimeException。
    • 重写构造器。
    • 通过 throw new 异常类(xxx)来创建异常对象抛出
    • 特点:编译阶段不报错,运行时才可能出现,提醒不属于激进型。
  • 自定义编译时异常
    • 定义一个异常继承Exception。
    • 重写构造器。
    • 通过 throw new 异常类(xxx)创建异常对象并抛出。
    • 特点:编译阶段就报错,提醒比较激进。

异常的处理方案

  1. 方案一:底层异常层层往上抛出,最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提示。
  2. 方案二:最外层捕获异常后,尝试重新修复。

异常的两种处理方式

  • 抛出异常(throws)
方法 throws 异常1 ,异常2 ,异常3 ..{
       …
}
  • 捕获异常(try…catch)
try{
    // 监视可能出现异常的代码!
}catch(异常类型1 变量){
    // 处理异常
    
}catch(异常类型2 变量){
    // 处理异常
}...

泛型

  • 定义类、接口、方法是,同时声明了一个或多个类型变量(如:)
    • 称为泛型类、泛型接口、泛型方法,它们统称为泛型。
public class ArrayList<E>{
    . . .
}
  • 作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力. 这样可以避免强制类型转换,及其可能出现的异常。
  • 泛型的本质:把具体的数据类型作为参数给类型变量。

泛型类

修饰符 class 类名<类型变量,类型变量,…> { 
}
  • 类型变量建议用大写的英文字母,常用的有:E、T、K、V 等

泛型接口

修饰符 interface 接口名<类型变量,类型变量,…> { 
}

泛型方法、通配符和上下限

  • 泛型方法
修饰符 <类型变量,类型变量,…>  返回值类型 方法名(形参列表) { 
 }
  • 通配符
    • 就是 “?”,可以在 “使用泛型” 的时候代表一切类型; E T K V 是在定义泛型的时候使用。
  • 泛型的上下限:
    • 泛型上限:? extends Car: ? 能接收的必须是Car或者其子类 。
    • 泛型下限:? super Car:? 能接收的必须是Car或者其父类。

泛型支持的类型

  • 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
    • 可以使用基本数据类型的包装类。

集合框架

  • 集合是一种容器,用来装数据的,类似于数组,但集合的大小可变,开发中也非常常用。

集合体系结构

  • Collection 代表单列集合,每个元素(数据)只包括一个值。
  • Map 代表双列集合,每个元素包含两个值(键值对)。

Collection

  • Collection
    • List
      • ArrayList
      • LinkedList
    • Set
      • HashSet
        • LinkedHashSet
      • TreeSet
  • Collection集合特点
    • List系列集合:添加的元素是有序、可重复、有索引。
      • ArrayList、LinekdList:有序、可重复、无索引。
    • Set系列集合:添加的元素是无序、不重复、无索引。
      • HashSet:无序、不重复、无索引。
      • LinkedHashSet:有序、不重复、无索引。
      • TreeSet:按照大小默认升序排序、不重复、无索引。

Collection集合

  • Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。
方法名 说明
public boolean add(E e) 把给定的对象添加到当前集合中
public void clear() 清空集合中所有的元素
public boolean remove(E e) 把给定的对象在当前集合中删除
public boolean contains(Object obj) 判断当前集合中是否包含给定的对象
public boolean isEmpty() 判断当前集合是否为空
public int size() 返回集合中元素的个数。
public Object[] toArray() 把集合中的元素,存储到数组中

Collection的遍历方式

  1. 迭代器遍历
    • 迭代器是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator。
方法名称 说明
Iterator iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素
  • Iterator迭代器中的常用方法
方法名称 说明
boolean hasNext() 询问当前位置是否有元素存在,存在返回true ,不存在返回false
E next() 获取当前位置的元素,并同时将迭代器对象指向下一个元素处。
  1. 增强 for 循环
  • 增强for可以用来遍历集合或者数组
  • 增强for遍历集合,本质就是迭代器遍历集合的简化写法。
for (元素的数据类型 变量名 : 数组或者集合) {
}
  1. Lambda表达式
  • JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的方式来遍历集合。
方法名称 说明
default void forEach(Consumer<? super T> action) 结合lambda遍历集合
Collection<String> lists = new ArrayList<>();
...
lists.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
        }
});
  • 简化
Collection<String> lists = new ArrayList<>();
...
lists.forEach(s -> {
    System.out.println(s);
});
//  lists.forEach(s -> System.out.println(s));

认识并发修改异常问题

  • 遍历集合的同时又存在增删集合元素的行为时可能出现业务异常,这种现象被称之为并发修改异常问题。
解决并发修改异常问题的方案
  • 如果集合支持索引,可以使用for循环遍历,每删除数据后做 i–;或者可以倒着遍历。
  • 可以使用迭代器遍历,并用迭代器提供的删除方法删除数据。
  • 增强for循环/Lambda遍历均不能解决并发修改异常问题,因此增它们只适合做数据的遍历,不适合同时做增删操作。

List集合

  • ArrayList和LinkedList,底层实现不同,适应的场景不同。

List集合的特有方法

  • List集合因为支持索引,所以多了很多与索引相关的方法。
方法名称 说明
void add(int index,E element) 在此集合中的指定位置插入指定的元素
E remove(int index) 删除指定索引处的元素,返回被删除的元素
E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素
  • List集合支持的遍历方式
    • for循环
    • 迭代器
    • 增强for循环
    • Lambda表达式

ArrayList底层原理

  • ArrayList底层是基于数组存储数据的。
  • 数组的特点
    • 查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。

    • 增删数据效率低:可能需要把后面很多的数据进行前移。

LinkedList的底层原理

  • LinkedList底层是基于链表存储数据的。
    • 基于双链表实现的。
      • 特点:查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的。
  • 链表的特点:
    • 链表中的数据是一个一个独立的结点组成的,结点在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
    • 查询慢,无论查询哪个数据都要从头开始找。
    • 链表增删相对快.
  • 双链表:对首尾元素进行增删改查的速度是极快的。
  • LinkedList新增了很多首尾操作的特有方法。
方法名称 说明
public void addFirst(E e) 在该列表开头插入指定的元素
public void addLast(E e) 将指定的元素追加到此列表的末尾
public E getFirst() 返回此列表中的第一个元素
public E getLast() 返回此列表中的最后一个元素
public E removeFirst() 从此列表中删除并返回第一个元素
public E removeLast() 从此列表中删除并返回最后一个元素

LinkedList的应用场景

  • 用来设计队列
    • 队列的特点:先进先出,后进后出。
  • 用来设计栈
    • 栈的特点:后进先出,先进后出。
    • 数据进入栈模型的过程称为:压/进栈(push)
    • 数据离开栈模型的过程称为:弹/出栈(pop)
  • 使用首尾元素,用Linked来实现很合适。