作者:手机用户2502932937 | 来源:互联网 | 2017-06-26 14:04
文章标题:Continuation和高级流程控制。Linux是中国IT实验室的一个技术频道。包含桌面应用,Linux系统管理,内核研究,嵌入式系统和开源等一些基本分类
流程控制通常非常简单:包括序列化、选择和迭代等过程。很多一直在使用这些基本控制结构的程序员都曾经经历过一段困难的时间来确定哪种流程控制是必需的。本文将简要介绍有关 continuation 的内容,并向您展示如何用最新的方法来考虑流程控制的问题。
很多程序员在首次接触编程之后,并不会太多考虑有关流程控制的问题,因为大部分编程语言都只有几个简单的流程控制结构。然而,流程控制的内容实际上比大部分主流编程语言中提供的更为丰富。有很多并不被大多数人所知的专用语言都具有高级且有用的流程控制结构。
高级流程控制的例子
我们开始了解流程控制的最好方法是查看几个使用不同语言的高级流程控制结构的例子。然后可以将这些知识归纳为一个适用于高级流程控制情况的框架。
大规模退出
第一种高级流程控制技术您可能已经听说过:大规模退出(non-local exit)。大规模退出有几种类型,每种类型都可以划分成两类:结构化的和非结构化的。非结构化大规模退出(Unstructured non-local exit) 就是计算机科学老师警告您不要这样做的一种情况,例如可怕的 goto
语句。实际上,如果得到广泛而正确地使用,非结构化的大规模退出可能会非常有用。例如,在流程控制非常复杂的程序中,它们可以提高程序的可读性。如果复杂的流程控制不能非常自然地嵌套,那么强行使用嵌套结构会使整个程序的可读性变差,而不是变好。有关使用 goto
语句的优缺点的更多信息,请参考本文后面 参考资料 部分给出的链接。
对于结构化的大规模退出(structured non-local exit),您可能熟悉最流行的一种类型:异常。如果您使用 C、Fortran 和 Cobol 的时间已经超过了 20 年,而且一直没有再使用过其他语言,那么请参阅下面对异常的一段简介。
异常 (exception) 是在代码中触发错误或对错误进行局部化的一种方法。通常当错误发生时,我们希望能够对这个错误进行处理。除非我们明确下达继续操作的指示,否则其余的工作不会继续进行。例如,我们可以看一下下面使用 Java™ 语言编写的这个简单的数据库代码:
清单 1. 简单的数据库代码的例子
//NOTE -- this code will not compile, but that's on purpose.
import java.sql.*;
...
public static int testdbcode(Connection conn) {
//Prepare the statement
PreparedStatement s = conn.prepareStatement(
"select id from test_table where name = ?");
//Set the parameters
s.setString(1, "fred");
//Run the query
ResultSet rs = s.executeQuery()
//Move to the first result row
rs.next();
//Get the answer (first result parameter)
int id = rs.getInt(1);
return id;
}
...
|
这段代码的问题是没有错误处理,在处理数据库或其他外部实体时,每个地方都可能产生错误。例如,如果在准备查询时产生了错误,那么设置参数、运行查询以及检索结果就都没什么用了。这个查询在碰到第一个错误之后就毫无意义了。因此在 Java 语言中,提供了一些异常,这让我们可以封装一段代码,这样在碰到第一个错误时就会跳到这段代码上来。要在 Java 语言中实现这种功能,我们可以按照下面的方式重新编写这段代码:
清单 2. 采用异常处理的简单数据库函数
import java.sql.*;
...
public static int testdbcode(Connection conn) {
try {
//Prepare the statement
PreparedStatement s = conn.prepareStatement(
"select id from test_table where name = ?");
//Set the parameters
s.setString(1, "fred");
//Run the query
ResultSet rs = s.executeQuery()
//Move to the first result row
rs.next();
//Get the answer (first result parameter)
int id = rs.getInt(1);
return id;
} catch (Exception e) {
//Put error handling code here
return -1;
}
}
...
|
try
中的代码块会一直执行完,除非有一条语句出现了错误。如果触发 了某个错误,就会跳过 try
中的代码块,执行 catch
中的代码块,其中变量 e
中保存了异常的信息。在 Java 中,被触发的错误都是完整的类,因此任何信息都可以放入异常中。实际上,我们可以创建多个 catch
代码块,每个代码块分别用来处理一种特定的异常类。
在上面的代码例子中,我们处理的是系统生成的异常。不过我们也可以创建应用程序级的异常,并对其执行同样的处理。应用程序可以在任意时刻使用 throw
关键字触发异常。例如,我们可以说如果上面的代码中 ID 值为 1,那么就可以认为这是一个应用程序级的异常。我们可以使用下面的方式:
清单 3. 触发应用程序级异常的简单数据库的例子
import java.sql.*;
...
public static int testdbcode(Connection conn) {
try {
//Prepare the statement
PreparedStatement s = conn.prepareStatement(
"select id from test_table where name = ?");
//Set the parameters
s.setString(1, "fred");
//Run the query
ResultSet rs = s.executeQuery()
//Move to the first result row
rs.next();
//Get the answer (first result parameter)
int id = rs.getInt(1);
//Check for application exception
if(id == 0) {
//Signal the exception
//Assume that InvalidUserIDException is defined elsewhere
throw new InvalidUserIDException();
}
return id;
} catch (InvalidUserIDException e) {
//Specialized error handling here
return -1;
} catch (Exception e) {
//Handle all other errors here
return -1;
}
}
...
|
另外,处理异常的代码没有理由只能放在函数本身中。try
和 catch
语句也可以放到任何包含函数(containing function)中。异常处理机制会展开堆栈,直到它到达一个合适的异常处理程序,此时程序就会执行异常处理代码。这种执行结构化大规模退出的能力可以极大地简化代码的编写,以及对代码的维护工作,因为在某些情况下,错误处理与实际实现功能的代码是完全分隔开的。当然,这一切都非常简单。异常处理还有几个主要的功能,这已经超出了本文介绍的范围,不过 参考资料 中的部分内容可以为您提供这方面的帮助。
[1] [2] [3] [4] [5] 下一页