Java语言程序设计——篇十二


🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿

  • 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳🌳
    您的点赞👍、关注➕、收藏⭐️、评论📝、私信📧是我最大的支持与鼓舞!!!🌻🌻🌻

异常处理

主要内容

1️⃣异常与异常类(异常是什么?Java内部提供了哪些异常类)

2️⃣异常处理(如何处理异常?)

3️⃣自定义异常类(用户自己如何定义异常类?)

4️⃣ 断言(高级的异常处理形式)

1️⃣异常与异常类

异常

  • 异常(exception)是在程序运行过程中产生的使程序终止正常运行的错误对象。
  • 如数组下标越界、整数除法中零作除数、文件找不到等都可能使程序终止运行。

异常类

  • Java定义了多种异常类。都是java.lang.Throwable类的子类,它是Object类的直接子类。
  • Throwable类有两个子类
    ① Error类
    ② Exception类

2️⃣异常处理

异常的抛出与捕获

  • 方法运行过程中如果产生了异常,在这个方法中就生成一个代表该异常类的对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理该异常。这个过程称为抛出异常。
  • 运行时系统在方法的调用栈中查找,从产生异常的方法开始进行回溯,直到找到包含相应异常处理的方法为止,这一过程称为捕获异常。
  • 方法调用与回溯如图所示。

try-catch-finally语句

java 复制代码
try{
     // 需要处理的代码
} catch (ExceptionType1 exceptionObject){
    // 异常处理代码
}[catch (ExceptionType2 exceptionObject){
    // 异常处理代码
}
finally{
    // 最后处理代码
} ]

用catch捕获多个异常

  • 如果在多个catch块捕获的异常**使用相同的代码处理,**则可以仅用一个catch块处理,而不必单独捕获每个异常,这就减少了代码重复。
  • 要在一个catch语句中处理多个异常,需要使用"或"运算符(|)分隔多个异常。

声明方法抛出异常

  • 有时方法中产生的异常不需要在该方法中处理,可能需要由该方法的调用方法处理,这时可以在声明方法时用throws子句声明抛出异常,将异常传递给调用该方法的方法处理。
java 复制代码
 returnType methodName([paramlist]) 
                 throws ExceptionList{
         // 方法体
   } 

用throw语句抛出异常

  • 可以创建一个异常对象,然后用throw语句抛出,或者将捕获到的异常对象用throw语句再次抛出,throw语句的格式如下:
java 复制代码
  throw  exceptInstance;

使用try-with-resources语句

  • 在JDK 7之前,通常使用finally语句确保调用close()方法:
java 复制代码
 try{
          // 打开资源
  }catch(Exception e){
        // 处理异常
  }finally{
        // 关闭资源
  }
实战演练

下面是打开一个数据库连接的典型代码:

java 复制代码
Connection connection = null;
try{
    // 创建连接对象并执行操作
}catch(Exception e){
   // 处理异常
}finally{
   if(connection!=null){
     try{
         connection.close();
     }catch(SQLException e){  // 处理异常  }
   }
}   
  • JDK 7提供的自动关闭资源的功能为管理资源(如文件流、数据库连接等)提供了一种更加简便的方式。这种功能是通过一种新的try语句实现的,叫try-with-resources,有时称为自动资源管理。
  • try-with-resources的主要好处是可以避免在资源(如文件流)不需要时忘记将其关闭。
  • try-with-resources语句的基本形式如下:
java 复制代码
try(
        声明和创建某种资源 )//(只有实现了java.lang.AutoCloseable接口的那些资源才可自动关闭。)
{
     // 使用资源
}
 [catch(Exception  e){}]
 [finally{ 
 }]

3️⃣自定义异常

  • 编写自定义异常类实际上是继承一个标准异常类,通常继承Exception类,如下所示:
java 复制代码
 class CustomException extends Exception {   
     public CustomException(){}  
     public CustomException(String message) {  
        super(message);    
     }
  }
实战演练

问题描述:

程序中需要验证用户输入的数据值必须是正值。如果用户提供的是负值,程序抛出异常。

编写一个自定义异常类NegativeValueException,负值异常。

java 复制代码
// 自定义运行时异常类 NegativeValueException  
public class NegativeValueException extends RuntimeException {  
  
    // 可以添加一个无参构造器  
    public NegativeValueException() {  
        super("输入值不能为负!");  
    }  
  
    // 也可以添加一个带有详细错误信息的构造器  
    public NegativeValueException(String message) {  
        super(message);  
    }  
  
    // 还可以添加一个带有错误信息和原因的构造器  
    public NegativeValueException(String message, Throwable cause) {  
        super(message, cause);  
    }  
  
    // 还可以添加一个带有原因的构造器  
    public NegativeValueException(Throwable cause) {  
        super(cause);  
    }  
  
    // 根据需要,你也可以添加更多的构造器或方法  
}

然后,你可以在你的程序中使用这个异常类来验证用户输入的值。下面是一个简单的示例,展示了如何在用户输入负值时抛出NegativeValueException:

java 复制代码
import java.util.Scanner;  
  
public class Main {  
    public static void main(String[] args) {  
        Scanner scanner = new Scanner(System.in);  
  
        System.out.print("请输入一个正数: ");  
        double input = scanner.nextDouble();  
  
        try {  
            validatePositive(input);  
            System.out.println("输入有效,您输入的是: " + input);  
        } catch (NegativeValueException e) {  
            System.out.println(e.getMessage());  
        }  
  
        scanner.close();  
    }  
  
    // 验证输入是否为正数  
    public static void validatePositive(double number) throws NegativeValueException {  
        if (number < 0) {  
            throw new NegativeValueException("您输入了一个负数!");  
        }  
    }  
}

在这个示例中,validatePositive方法用于检查用户输入的值是否为正数。如果输入的是负数,它将抛出一个NegativeValueException。在main方法中,通过try-catch块捕获并处理这个异常。如果用户输入了负数,程序将输出错误消息而不是崩溃。

4️⃣断言

使用断言

  • 所谓断言(assertion)是一个Java语句,其中指定一个布尔表达式,程序员认为在程序执行时该表达式的值应该为true。
  • 程序通过计算该布尔表达式执行断言,若该表达式为false程序会报告一个错误。通过验证断言是true,能够使程序员确信程序的正确性。
  • 断言是通过assert关键字来声明的,断言的使用有两种格式:
java 复制代码
assert expression ;//如果该表达式值为false,抛出AssertionError异常
assert expression : detailMessage ;

开启和关闭断言

  • 编译带有断言的程序与一般程序相同。默认情况下,断言在运行时是关闭的,要开启断言功能,在运行程序时需要使用 --enableassertions或-ea选项,例如:

D:\study>java --ea AssertionDemo

  • 在Eclipse中要开启断言,按下列步骤操作:
    Run→ Run Configurations → 选择Arguments选项卡
    → Arguments文本框中输入--enableassertions 或-ea 然后执行程序

    何时使用断言

  • 通常来说,断言用于检查一些关键的值,并且这些值对整个应用程序或局部功能的实现有较大影响,并且当断言失败,这些错误是不容易恢复的。

  • 以下是一些使用断言的情况,它们可以使Java程序的可靠性更高。

    1. 检查控制流
      在if~else和switch~case结构中,可以在不应该发生的控制支流上加上assert false语句。如果这种情况发生了,断言就能够检查出来。
      例如,假设x的值只能取1、2或3,可以编写下面的代码:
java 复制代码
 switch (x) {
    case 1: ...;
    case 2: ...;
    case 3: ...;
    default: assert false : "x 值非法:" + x;
  }
    1. 检查前置条件(precondition)
      private修饰的方法前检查输入参数是否有效。
      例如,某方法可能要求输入的参数param不能为null,就可以在方法的开头加上下面语句:
java 复制代码
assert param != null:"参数不能为null";
    1. 检查后置条件(postcondition)
      在方法计算之后检查结果是否有效。对于一些计算方法,运行完成后,某些值需要保证一定的性质。
      例如,对计算绝对值的方法可以在方法的结束处使用下面语句进行检查:
java 复制代码
assert value >= 0:"结果应该大于等于0:" + value; 
    1. 检查程序不变量
      在程序的运行过程中这些变量的值是不变的,称为不变量。这些不变量可能是一个简单表达式,也可能是一个复杂表达式。对于一些关键的不变量,可以通过assert进行检查。
断言示例

问题描述

使用对象数组实现一个简单的栈类,在push()、pop()和topValue()方法中使用断言。

java 复制代码
public class SimpleStack<T> {  
    private Object[] elements;  
    private int size;  
    private int capacity;  
  
    public SimpleStack(int initialCapacity) {  
        capacity = initialCapacity;  
        elements = new Object[capacity];  
        size = 0;  
    }  
  
    // 向栈中添加元素  
    public void push(T item) {  
        assert size < capacity : "Stack is full, cannot push new item";  
        elements[size++] = item;  
    }  
  
    // 从栈中移除并返回顶部元素  
    @SuppressWarnings("unchecked")  
    public T pop() {  
        assert size > 0 : "Stack is empty, cannot pop item";  
        return (T) elements[--size];  
    }  
  
    // 返回栈顶元素但不移除  
    @SuppressWarnings("unchecked")  
    public T topValue() {  
        assert size > 0 : "Stack is empty, cannot access top value";  
        return (T) elements[size - 1];  
    }  
  
    // 获取栈的当前大小  
    public int getSize() {  
        return size;  
    }  
  
    // 获取栈的容量  
    public int getCapacity() {  
        return capacity;  
    }  
  
    // 为了简单起见,这里不实现扩容逻辑  
    // 在实际应用中,你可能需要在push时检查容量,并在需要时扩容  
}  
  
// 使用示例  
public class Main {  
    public static void main(String[] args) {  
        SimpleStack<Integer> stack = new SimpleStack<>(5);  
  
        stack.push(1);  
        stack.push(2);  
        stack.push(3);  
  
        System.out.println("Top value: " + stack.topValue()); // 应输出 3  
  
        stack.pop();  
        System.out.println("New top value: " + stack.topValue()); // 应输出 2  
  
        // 尝试在空栈上调用 pop() 或 topValue(),这将触发断言错误(如果启用了断言)  
        // 注意:在生产环境中,断言可能会被禁用,因此最好有额外的错误处理逻辑  
        // stack.pop(); // 这将引发 AssertionError,如果断言被启用  
    }  
}

博主用心写,读者点关注,互动传真情,只是不迷路。

相关推荐
taopi202434 分钟前
android java系统弹窗的基础模板
android·java·开发语言
釉色清风37 分钟前
【matlab】绘图 离散数据--->连续函数
开发语言·matlab
AIGC大时代40 分钟前
对比DeepSeek、ChatGPT和Kimi的学术写作撰写引言能力
数据库·论文阅读·人工智能·chatgpt·数据分析·prompt
如风暖阳1 小时前
Redis背景介绍
数据库·redis·缓存
松仔log1 小时前
Java多线程——对象的组合
java·开发语言·jvm
Qhumaing1 小时前
Python学习——函数参数详解
开发语言·python·学习
酷爱码1 小时前
springboot 动态配置定时任务
java·spring boot·后端
ElvInR2 小时前
【C语言】动态内存管理
c语言·开发语言
从未止步..2 小时前
Jenkins未在第一次登录后设置用户名,第二次登录不进去怎么办?
java·运维·jenkins
老马啸西风2 小时前
IM 即时通讯系统-42-基于netty实现的IM服务端,提供客户端jar包,可集成自己的登录系统
java