昨天看了一篇帖子,我意识到我对异常的起源并不了解。它仅是一个与OOP相关的概念吗?我倾向于认为是这样,但是同样有数据库异常。
goto
。特别是,抛出是由上下文决定的,基于块结构的嵌套。因此,异常甚至取决于结构化编程的稍微宽松一些的形式,在这种形式下,将单出口原则作为准则,而不是绝对准则。
昨天看了一篇帖子,我意识到我对异常的起源并不了解。它仅是一个与OOP相关的概念吗?我倾向于认为是这样,但是同样有数据库异常。
goto
。特别是,抛出是由上下文决定的,基于块结构的嵌套。因此,异常甚至取决于结构化编程的稍微宽松一些的形式,在这种形式下,将单出口原则作为准则,而不是绝对准则。
Answers:
异常不是OOP概念。
但是它们在一点点上也不是完全无关的。
正如其他答案所表明的那样:异常的概念已经用几种非OOP语言实现了。该概念中的任何内容都不需要 OOP。
但是认真对待 OOP的所有OOP语言(如果不是全部)都需要例外,因为其他错误处理方法在某个特定点失败:构造函数。
OOP的要点之一是对象应完全一致地封装和管理其内部状态。这也意味着在纯OOP中,您需要一个概念来创建一个具有“原子”一致状态的新对象-从内存分配(如果需要)到初始化到有意义的状态(即简单地将内存清零是不够的)都必须用一个表达式完成。因此,需要一个构造函数:
Foo myFoo = Foo("foo", "bar", 42);
但这意味着构造函数也可能由于某些错误而失败。如何在没有异常的情况下从构造函数中传播错误信息?
返回值?失败,因为在某些语言中new
只能返回null
但不能返回任何有意义的信息。在其他语言中(例如C ++)myFoo
不是指针。您无法对照进行检查null
。您也不能问myFoo
该错误-它没有初始化,因此在OOP思维中“不存在”。
全局错误标志?关于封装状态,然后封装一些全局变量,那么多了吗?去h ... ;-)
混合物?绝对没有更好的选择。
?
因此,例外是比OOP更基本的概念,但是OOP是自然地在它们之上建立的。
它仅与OOP相关吗?
否。异常与OOP无关。
异常处理是一种处理错误的机制。通过将当前执行状态保存在预定义的位置并将执行切换到称为异常处理程序的特定子例程来处理异常。
比较C(不是真正的OOP语言,可以以某种方式模拟C中的异常)和C ++(OOP,支持异常),没有什么可以阻止C的标准委员会向C添加异常处理,它仍然不会使C成为OOP语言。
ON ERROR GOTO xxxx
try catch
构造。
简而言之,例外情况是需要引起注意的例外情况,并且通常会改变程序执行流程。通过该定义,异常和异常处理不限于面向对象,并且简单的程序错误可以视为异常的一种形式。
面向对象的语言通常具有本机异常类,根据上下文,单词“ exception”可能确实是指该本机类而不是一般概念。与大多数面向对象一样,面向对象的异常处理是语法糖,可以很容易地在决定性的非面向对象语言中进行仿真。这是C编程Wikibook中的C示例:
#include <stdio.h>
#include <setjmp.h>
jmp_buf test1;
void tryjump()
{
longjmp(test1, 3);
}
int main (void)
{
if (setjmp(test1)==0) {
printf ("setjmp() returned 0.");
tryjump();
} else {
printf ("setjmp returned from a longjmp function call.");
}
}
答案很简单。
ADA是非OO语言的一个很好的例子。
这里已经有一些非常好的答案。非OOP编程语言的其他示例也有例外:
Oracle PL / SQL
经典的Visual Basic(V6及以下版本,“ On Error Goto”是IMHO异常处理的一种形式)
(更确切地说,您在两种语言中都找到了一些OO元素,但是异常处理机制没有使用它们,我想是因为该概念是在将OO元素添加到这些语言之前的几年才引入的)。
ON ERROR GOTO
语法的错误处理。甚至QuickBASIC也有一些类似于OO的概念(我认为QB 4.5甚至支持某种类),但很难将大多数传统的BASIC称为正确的面向对象语言。[Wikipedia ]
异常背后的基本思想是清理程序流,以便程序员可以更轻松地遵循“正常”执行路径。考虑一个在C中打开文件的简单情况。尝试打开文件后,程序员需要立即检查fopen()调用的响应并确定调用是否成功。如果调用未成功,则程序员必须做出适当的响应。处理错误或失败条件后,将出现“正常”执行路径中的下一个调用,可能是对fread()或fwrite()的调用。可能在下一个屏幕上。
使用提供异常的语言,等效的fopen()调用可以紧随其后的是fread()或fwrite()。没有错误处理隐藏了“正常”执行路径的“下一步”。程序员可以在一个屏幕上看到更多的正常路径,因此可以更轻松地跟随执行。错误处理将移至程序的另一部分。
异常本身不是OOP的概念,但是通常使用OOP的概念来实现,这使它们更加方便和强大。例如,可以使用继承层次结构定义异常。使用我们打开和读取或写入文件的概念性示例,这些调用中的每一个都可能生成各种异常-FileClosedException,DeviceFullException,NoSuchFileException,InsufficientFilePermissionsException等。每个异常都可以继承自FileException,而FileException可以继承自IOException。从GenericException继承。
如果程序员正在执行一种快速而肮脏的实现来测试一个概念,那么他可能会大多忽略异常处理,而只为GenericException实现一个处理程序。该处理程序将处理GenericException以及从GenericException继承的任何异常。如果他想以相同的方式处理任何与文件相关的异常,则可以为FileException编写处理程序。这将被FileExceptions以及从FileException继承的任何异常调用。如果他想编写一个对各种错误情况做出不同响应的程序,则可以为每个特定的异常编写一个特定的处理程序。
其他人正确地回答了语言示例。我认为我可以通过添加一个示例来扩展,该示例涉及如何在不涉及OOP的情况下向语言添加例外。
在OZ的DSKL(声明性顺序内核语言)的情况下,我会这样做,这是一种非常适合此类学术界语言的语言。可以在此处(随机搜索结果),“语句和值”部分看到DSKL(或DKL)。确切的定义并不重要,除了这是一种非常简单的语言,没有可修改的变量(它们被声明并稍后绑定),并且没有内置的OOP。
OOP甚至不能作为该语言的语言抽象添加。通过将唯一的名称添加到内核语言(NewName)并使用本地作用域,可以实现封装。或者通过将可变状态添加到内核语言(NewCell)并使用本地作用域,可以实现带有封装的适当OOP。但是,仅靠指定的内核语言无法实现。
如果随后将异常添加到内核语言中,我们将使用不支持OOP的语言,但会包含异常。让我展示如何:
通过定义具有堆栈和存储空间的抽象机,我们可以定义语言中的每个语句应执行的操作(语句的语义)。例如skip
,堆栈中什么都不做,A = 3
堆栈中应该将A绑定到(/ with)3。
我们首先添加应如何定义异常的语法。为此,我们<statement>
在DKL中添加了另外两个子句。
<statement> ::== ... (old stuff)
| try <statement> catch <id> then <statement> end
| raise <id> end
这是已知的try / catch,以及引发/引发异常的方法。
我们通过它们在抽象机器上的工作方式来定义它们的语义:
尝试
语义语句是(try <statement1> catch <id> then <statement2> end)
:
(catch <id> then <statement2> end)
(<statement1>)
请注意,语句1将位于堆栈的顶部,并首先尝试执行。
提高
语义声明是(raise <id> end)
:
(catch <id> then <statement> end)
(<statement>)
入堆栈”表单。捕获
如果在正常执行过程中看到捕获状态,则表示内部执行的任何内容都不会引发异常直至此级别。因此,我们只是弹出catch
堆栈,什么也不做。
QED,我们有一种例外的语言,没有OOP的可能性。
我已经从抽象机中删除了环境部分,以使其更简单。