Exception、Error、运行时异常与一般异常有何异同

本文详细介绍了Java中的异常处理机制,包括Error和Exception的区别,运行时异常与一般异常的异同,以及异常处理的具体流程和最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Throwable是所有Java程序中错误处理的父类,有两种资类:Error和Exception。


1. Error:

表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形.应用程序不应该抛出这种类型的对象(一般是由虚拟机抛出).假如出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的.



2. Exception:

表示可恢复的例外,这是可捕捉到的。


Java提供了两类主要的异常:

runtime exception(行时异常)checked exception(一般异常)

checked exception用来指示一种调用方能够直接处理的异常情况。而runtime exception则用来指示一种调用方本身无法处理或恢复的程序错误。


checked 异常也就是我们经常遇到的IO异常,以及SQL异常都是这种异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。

这类异常一般是外部错误,例如试图从文件尾后读取数据等,这并不是程序本身的错误,而是在应用环境中出现的外部错误。


runtime exception,也称运行时异常,我们可以不处理。当出现这样的异常时,总是由虚拟机接管。

比如:我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一。RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等。

处理RuntimeException的原则是:假如出现RuntimeException,那么一定是程序员的错误。例如,可以通过检查数组下标和数组边界来避免数组越界访问异常.


出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有一般异常的特点,是可以被Catch块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。


如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常,或者是通过对异常的处理显式的控制程序退出。


异常处理的目标之一就是为了把程序从异常中恢复出来。


转自: java运行时异常与一般异常有何异同?


异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误.java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常.

   下面简单讲解一下有关JAVA异常的知识:

    1. 异常机制

    1.1

    异常机制是指当程序出现错误后,程序如何处理.具体来说,异常机制提供了程序退出的安全通道.当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器.

    1.2

    传统的处理异常的办法是,函数返回一个非凡的结果来表示出现异常(通常这个非凡结果是大家约定俗称的),调用该函数的程序负责检查并分析函数返回的结果. 这样做有如下的弊端:例如函数返回-1代表出现异常,但是假如函数确实要返回-1这个正确的值时就会出现混淆;可读性降低,将程序代码与处理异常的代码混 爹在一起;由调用函数的程序来分析错误,这就要求客户程序员对库函数有很深的了解.

    1.3 异常处理的流程

    1.3.1 碰到错误,方法立即结束,并不返回一个值;同时,抛出一个异常对象

    1.3.2 调用该方法的程序也不会继续执行下去,而是搜索一个可以处理该异常的异常处理器,并执行其中的代码

    2 异常的分类

    2.1 异常的分类

    2.1.1

    异常的继续结构:基类为Throwable,Error和Exception继续Throwable,RuntimeException和 IOException等继续Exception,具体的RuntimeException继续RuntimeException.

    2.1.2

    Error和RuntimeException及其子类成为未检查异常(unchecked),其它异常成为已检查异常(checked).

    2.2 每个类型的异常的特点

    2.2.1 Error体系

    Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形.应用程序不应该抛出这种类型的对象(一般是由虚拟机抛出).假如出现这种错误, 除了尽力使程序安全退出外,在其他方面是无能为力的.所以,在进行程序设计时,应该更关注Exception体系.

    2.2.2 Exception体系

    Exception体系包括RuntimeException体系和其他非RuntimeException的体系

    2.2.2.1 RuntimeException

    RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等.处理RuntimeException的原则是:假如出现 RuntimeException,那么一定是程序员的错误.例如,可以通过检查数组下标和数组边界来避免数组越界访问异常.

    2.2.2.2 其他(IOException等等)

    这类异常一般是外部错误,例如试图从文件尾后读取数据等,这并不是程序本身的错误,而是在应用环境中出现的外部错误.

    2.3 与C++异常分类的不同

    2.3.1

    其实,Java中RuntimeException这个类名起的并不恰当,因为任何异常都是运行时出现的.(在编译时出现的错误并不是异常,换句话说,异常就是为了解决程序运行时出现的的错误).

    2.3.2

    C++中logic_error与Java中的RuntimeException是等价的,而runtime_error与Java中非RuntimeException类型的异常是等价的.

    3 异常的使用方法

    3.1 声明方法抛出异常

    3.1.1 语法:throws(略)

    3.1.2 为什么要声明方法抛出异常?

    方法是否抛出异常与方法返回值的类型一样重要.假设方法抛出异常确没有声明该方法将抛出异常,那么客户程序员可以调用这个方法而且不用编写处理异常的代码.那么,一旦出现异常,那么这个异常就没有合适的异常控制器来解决.

    3.1.3 为什么抛出的异常一定是已检查异常?

    RuntimeException与Error可以在任何代码中产生,它们不需要由程序员显示的抛出,一旦出现错误,那么相应的异常会被自动抛出.而已检 查异常是由程序员抛出的,这分为两种情况:客户程序员调用会抛出异常的库函数(库函数的异常由库程序员抛出);客户程序员自己使用throw语句抛出异 常.碰到Error,程序员一般是无能为力的;碰到RuntimeException,那么一定是程序存在逻辑错误,要对程序进行修改(相当于调试的一种 方法);只有已检查异常才是程序员所关心的,程序应该且仅应该抛出或处理已检查异常.

    3.1.4

    注重:覆盖父类某方法的子类方法不能抛出比父类方法更多的异常,所以,有时设计父类的方法时会声明抛出异常,但实际的实现方法的代码却并不抛出异常,这样做的目的就是为了方便子类方法覆盖父类方法时可以抛出异常.

    3.2 如何抛出异常

    3.2.1 语法:throw(略)

    3.2.2 抛出什么异常?

    对于一个异常对象,真正有用的信息时异常的对象类型,而异常对象本身毫无意义.比如一个异常对象的类型是ClassCastException,那么这个类名就是唯一有用的信息.所以,在选择抛出什么异常时,最要害的就是选择异常的类名能够明确说明异常情况的类.

    3.2.3

    异常对象通常有两种构造函数:一种是无参数的构造函数;另一种是带一个字符串的构造函数,这个字符串将作为这个异常对象除了类型名以外的额外说明.

    3.2.4

    创建自己的异常:当Java内置的异常都不能明确的说明异常情况的时候,需要创建自己的异常.需要注重的是,唯一有用的就是类型名这个信息,所以不要在异常类的设计上花费精力.

    3.3 捕捉异常

    假如一个异常没有被处理,那么,对于一个非图形界面的程序而言,该程序会被中止并输出异常信息;对于一个图形界面程序,也会输出异常的信息,但是程序并不中止,而是返回用户界面处理循环中.

    3.3.1 语法:try、catch和finally(略)

    控制器模块必须紧接在try块后面.若掷出一个异常,异常控制机制会搜寻参数与异常类型相符的第一个控制器随后它会进入那个catch

    从句,并认为异常已得到控制.一旦catch 从句结束对控制器的搜索也会停止.

    3.3.1.1 捕捉多个异常(注重语法与捕捉的顺序)(略)

    3.3.1.2 finally的用法与异常处理流程(略)

    3.3.2 异常处理做什么?

    对于Java来说,由于有了垃圾收集,所以异常处理并不需要回收内存.但是依然有一些资源需要程序员来收集,比如文件、网络连接和图片等资源.

    3.3.3 应该声明方法抛出异常还是在方法中捕捉异常?

    原则:捕捉并处理哪些知道如何处理的异常,而传递哪些不知道如何处理的异常

    3.3.4 再次抛出异常

    3.3.4.1 为什么要再次抛出异常?

    在本级中,只能处理一部分内容,有些处理需要在更高一级的环境中完成,所以应该再次抛出异常.这样可以使每级的异常处理器处理它能够处理的异常.

    3.3.4.2 异常处理流程

    对应与同一try块的catch块将被忽略,抛出的异常将进入更高的一级.

    4 关于异常的其他问题

    4.1 过度使用异常

    首先,使用异常很方便,所以程序员一般不再愿意编写处理错误的代码,而仅仅是简简单单的抛出一个异常.这样做是不对的,对于完全已知的错误,应该编写处理这种错误的代码,增加程序的鲁棒性.另外,异常机制的效率很差.

    4.2 将异常与普通错误区分开

    对于普通的完全一致的错误,应该编写处理这种错误的代码,增加程序的鲁棒性.只有外部的不能确定和预知的运行时错误才需要使用异常.

    4.3 异常对象中包含的信息

    一般情况下,异常对象唯一有用的信息就是类型信息.但使用异常带字符串的构造函数时,这个字符串还可以作为额外的信息.调用异常对象的 getMessage()、toString()或者printStackTrace()方法可以分别得到异常对象的额外信息、类名和调用堆栈的信息.并 且后一种包含的信息是前一种的超集.


转自: 运行时异常与一般异常有何异同
<think>好的,用户现在想了解PostgreSQL和Oracle存储过程的异同点,特别是语法、功能和特性方面的对比。之前用户的问题是关于Java发送复杂邮件的内容,现在突然转到了数据库存储过程,可能是在开发过程中遇到了需要迁移数据库或者多数据库支持的需求,比如从Oracle迁移到PostgreSQL,或者需要同维护两种数据库的存储过程。用户提到参考的引用内容是关于存储过程移植性的问题,这说明用户可能关心的是两者之间的兼容性,以及迁移或跨平台使用需要做的修改。 首先,我需要回顾PostgreSQL和Oracle存储过程的基本结构。Oracle使用PL/SQL,而PostgreSQL使用PL/pgSQL,两者语法上有很多相似之处,但也有不同点。比如变量声明、控制结构、异常处理等方面可能有差异。同,功能上的区别,比如事务处理、返回结果的方式、内置函数等也需要比较。 用户可能需要详细的对比,包括具体例子,这样他们在迁移或开发可以参考。比如,在语法上,变量声明Oracle是变量名在前,类型在后,而PostgreSQL可能使用DECLARE块。函数或存储过程的创建语句也不同,Oracle是CREATE OR REPLACE PROCEDURE,而PostgreSQL可能是CREATE FUNCTION加上不同的语言选项。 另外,功能特性方面,Oracle的存储过程在事务控制上可能更灵活,允许自治事务,而PostgreSQL可能需要使用特定的命令或者扩展来实现类似功能。异常处理机制两者也可能不同,比如Oracle的EXCEPTION块和PostgreSQL的EXCEPTION子句。 还需要考虑性能优化方面的差异,比如Oracle的优化器特性PostgreSQL的不同,索引类型、游标处理等。此外,高级功能如包(Oracle特有的)在PostgreSQL中如实现,或者是否有替代方案。 用户可能还想了解移植的具体步骤,常见问题及解决方案,比如如处理无法直接移植的语法,是否有工具可以辅助转换,或者最佳实践建议。 在回答,需要结构清晰,分点对比,并提供代码示例说明两者的不同,这样用户更容易理解和应用。同,根据之前的引用内容,强调移植性问题和需要修改的地方,帮助用户预见可能的挑战。最后,生成的相关问题应围绕用户可能进一步的需求,比如迁移工具、性能对比、调试方法等。</think>以下是PostgreSQLOracle存储过程在语法、功能和特性方面的详细对比分析,结合具体代码示例说明核心差异: --- ### 一、语法差异对比 #### 1. **基本结构定义** - **Oracle (PL/SQL)** ```sql CREATE OR REPLACE PROCEDURE proc_name ( p_param1 IN NUMBER, p_param2 OUT VARCHAR2 ) AS v_local_var NUMBER := 0; -- 变量声明 BEGIN -- 逻辑代码 SELECT column INTO p_param2 FROM table WHERE id = p_param1; EXCEPTION WHEN NO_DATA_FOUND THEN p_param2 := 'Not Found'; END; ``` **特点**:使用`AS`关键字开始声明部分,参数模式需明确标注`IN/OUT/IN OUT`[^2]。 - **PostgreSQL (PL/pgSQL)** ```sql CREATE OR REPLACE FUNCTION func_name ( p_param1 INTEGER, OUT p_param2 TEXT ) RETURNS TEXT AS $$ DECLARE v_local_var INTEGER := 0; -- 变量声明 BEGIN -- 逻辑代码 SELECT column INTO p_param2 FROM table WHERE id = p_param1; IF NOT FOUND THEN p_param2 := 'Not Found'; END IF; RETURN p_param2; -- 必须显式返回OUT参数 END; $$ LANGUAGE plpgsql; ``` **特点**:使用`DECLARE`块声明变量,`RETURNS`定义返回类型,需显式返回OUT参数[^3]。 #### 2. **流程控制** - **条件语句对比** ```sql -- Oracle IF condition THEN ... ELSIF condition2 THEN ... ELSE ... END IF; -- PostgreSQL IF condition THEN ... ELSIF condition2 THEN ... ELSE ... END IF; -- 语法相同 ``` - **循环语句差异** ```sql -- Oracle显式游标循环 FOR rec IN (SELECT * FROM employees) LOOP DBMS_OUTPUT.PUT_LINE(rec.emp_name); END LOOP; -- PostgreSQL隐式游标循环 FOR rec IN SELECT * FROM employees LOOP RAISE NOTICE '%', rec.emp_name; END LOOP; ``` --- ### 二、功能特性差异 #### 1. **事务控制** - **Oracle** 支持自治事务(`PRAGMA AUTONOMOUS_TRANSACTION`),允许在存储过程中提交独立事务: ```sql CREATE PROCEDURE log_error AS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO error_log VALUES (...); COMMIT; -- 允许显式提交 END; ``` - **PostgreSQL** **不支持存储过程内显式事务控制**(如`COMMIT/ROLLBACK`),所有操作在外部事务中执行[^4]。 #### 2. **返回结果集** - **Oracle** 使用`SYS_REFCURSOR`返回游标: ```sql PROCEDURE get_employees (p_cursor OUT SYS_REFCURSOR) AS BEGIN OPEN p_cursor FOR SELECT * FROM employees; END; ``` - **PostgreSQL** 直接通过`RETURNS SETOF`返回结果集: ```sql CREATE FUNCTION get_employees() RETURNS SETOF employees AS $$ BEGIN RETURN QUERY SELECT * FROM employees; END; $$ LANGUAGE plpgsql; ``` #### 3. **错误处理** - **Oracle** 结构化异常处理: ```sql EXCEPTION WHEN NO_DATA_FOUND THEN ... WHEN OTHERS THEN ROLLBACK; ``` - **PostgreSQL** 使用`EXCEPTION`块需配合`GET STACKED DIAGNOSTICS`: ```sql BEGIN ... EXCEPTION WHEN others THEN GET STACKED DIAGNOSTICS error_message = MESSAGE_TEXT; RAISE NOTICE 'Error: %', error_message; END; ``` --- ### 三、关键移植性问题 | 特性 | Oracle | PostgreSQL | 移植建议 | |--------------------|---------------------------------|--------------------------------|------------------------------| | **包(Package)** | 支持包(逻辑模块分组) | 无原生支持,需用Schema+函数模拟 | 拆分为独立函数 | | **集合类型** | 支持INDEX-BY表、嵌套表等 | 使用数组或JSONB替代 | 重构为数组类型 | | **动态SQL** | EXECUTE IMMEDIATE | EXECUTE ... USING | 调整参数占位符语法 | | **内置函数** | TO_CHAR(), NVL() | TO_CHAR(), COALESCE() | 替换函数名或逻辑 | --- ### 四、性能优化对比 - **Oracle优势** 支持物化视图、函数索引、并行执行(`PARALLEL`提示)。 - **PostgreSQL优势** JIT编译优化(PG11+)、扩展插件(如pg_hint_plan)、JSON处理性能更优。 --- ### 迁移实践示例 **Oracle原始代码**: ```sql CREATE PROCEDURE update_salary (emp_id IN NUMBER) AS BEGIN UPDATE employees SET salary = salary * 1.1 WHERE id = emp_id; COMMIT; -- 显式提交 EXCEPTION WHEN OTHERS THEN ROLLBACK; END; ``` **PostgreSQL移植版**: ```sql CREATE FUNCTION update_salary (emp_id INTEGER) RETURNS VOID AS $$ BEGIN UPDATE employees SET salary = salary * 1.1 WHERE id = emp_id; -- 移除非法的COMMIT语句 EXCEPTION WHEN others THEN RAISE EXCEPTION 'Update failed: %', SQLERRM; END; $$ LANGUAGE plpgsql; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值