Cleaner,more elegant,and wrong

整洁,更优雅,但是错的

并不是因为你看不到错误的产生路径就意味着它不存在。

下面是C#编程书中的一个片段,摘自关于异常处理的章节。

try {

AccessDatabase accessDb = new AccessDatabase();

accessDb.GenerateDatabase();

} catch (Exception e) {

// Inspect caught exception

}

public void GenerateDatabase()

{

CreatePhysicalDatabase();

CreateTables();

CreateIndexes();

}

Notice how much cleaner and more elegant [this] solution is.

请看这个解决方案是多么地整洁和优雅。

整洁,更优雅,但是错的。

假设在CreateIndexes()中抛出异常。GenerateDatabase()函数没有捕获它,所以错误被抛给执行catch的调用者,

当异常离开GenerateDatabase()时,重要信息已经丢失:数据库创建的状态捕获异常的代码不知道数据库创建的哪个步骤失败了。是否要删除索引?是否需要删除表吗?是否需要删除物理数据库?它不知道。

因此,如果创建CreateIndexes()时出现问题,则永远会泄露物理数据库文件和表。(由于这些可能是磁盘上的文件,所以它们无限期地挂起)。

在异常抛出模型中编写正确的代码比错误代码模型中更难,因为任何事情都可能是吧,您必须做好准备。在错误代码模型中,什么时候必须要检查错误是很明显的:当收到错误代码时。在异常处理模型中,你只需要错误可能会发生在任何地方。

换句话说,在错误代码模型中,很明显的是如当有人处理错误失败:他们没有检查错误代码。但是在一个异常抛出模型中,从代码中看不出是否有人处理错误,因为错误并不是明确的。

考虑如下:

Guy AddNewGuy(string name)

{

Guy guy = new Guy(name);

AddToLeague(guy);

guy.Team = ChooseRandomTeam();

return guy;

}

这个函数创建一个新的Guy,将他加入了联盟,并随机分配给一个团队。没有比这更简单的了。

记住:每一行都可能发生错误。

如果 “new Guy(name)“抛出异常怎么办?

好吧,幸运的是,我们还没有开始做任何事情,所以没有任何伤害 。

如果“AddToLeague(guy)“抛出异常怎么办?

我们创建的“Guy“将被放弃,GC将会清理它。

如果“guy.Team = ChooseRandomTeam()“抛出异常怎么办?

呃哦,现在我们很麻烦我们已经把这个人加入了联盟。如果有人捕获这个异常,他们将在联盟中找到一个不属于任何球队的人。如果有一些代码遍历联盟的所有成员,并使用gue.Team成员,他们将会获得NullReferenceException,因为guy.Team尚未初始化。

在编写代码时,您是否考虑到每行代码引发异常的后果呢?如果你打算写正确的代码,你必须这样做。

好吧,怎么解决这个问题?对操作重新排序。

Guy AddNewGuy(string name)

{

Guy guy = new Guy(name);

guy.Team = ChooseRandomTeam();

AddToLeague(guy);

return guy;

}

这种看似微不足道的变化对错误恢复有很大的影响。通过延迟提交数据(将guy加入到联盟),任何人员在创建过程中所遇到的异常都没有持久的影响。发生异常时,部分构造的guy被遗弃,最终被GC回收。

当然,这个例子很简单,因为设置guy的步骤没有副作用。如果设置过程中出现错误,我们可以抛弃guy,让GC清理回收。

在现实世界中,事情是比较麻烦的。考虑以下几点:

Guy AddNewGuy(string name)

{

Guy guy = new Guy(name);

guy.Team = ChooseRandomTeam();

guy.Team.Add(guy);

AddToLeague(guy);

return guy;

}

这与我们修正的函数一样,只是有人认为:如果每个球队保留一个成员列表,将会更有效率。所以您必须将自己添加到打算加入的球队中。这样做对函数的正确性有什么样后果?

Cleaner, more elegant, and wrong(翻译)的更多相关文章

  1. Cleaner, more elegant, and harder to recognize(翻译)

    Cleaner, more elegant, and harder to recognize 更整洁,更优雅,但更难识别 看来,有些人把我几个月前一篇文章的标题"Cleaner,more e ...

  2. Cleaner, more elegant, and wrong(msdn blog)

    Cleaner, more elegant, and wrong Just because you can't see the error path doesn't mean it doesn't e ...

  3. Cleaner, more elegant, and harder to recognize (msdn blog)

    It appears that some people interpreted the title of one of my rants from many months ago, "Cle ...

  4. Go 开发关键技术指南 | 敢问路在何方?(内含超全知识大图)

    作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 Go 开发关键技术指南文章目录: 为什么你要选择 Go? Go 面向失败编程 带着服务器编程金刚经走进 2020 年 敢问路在何方? Go 开发指南大图 ...

  5. Go 开发关键技术指南 | Go 面向失败编程 (内含超全知识大图)

    作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 关注"阿里巴巴云原生"公众号,回复 Go 即可查看清晰知识大图! 导读:从问题本身出发,不局限于 Go 语言,探讨服务器中常常遇到的 ...

  6. Java 7 Concurrency Cookbook 翻译 第一章 线程管理之四

    七.创建和运行一个后台线程 Java中有一种特别的线程叫做 deamon(后台) 线程.这类线程具有非常低的权限,并且只有在同一个程序中没有其他的正常线程在运行时才会运行.注意:当一个程序中只剩下后台 ...

  7. [翻译]Java垃圾收集精粹(Java Garbage Collection Distilled)

    source URL: http://www.infoq.com/articles/Java_Garbage_Collection_Distilled Name: Java Garbage Colle ...

  8. Effective Java 第三版——8. 避免使用Finalizer和Cleaner机制

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  9. PEP8中文翻译(转)

    原文:https://github.com/zgia/manual PEP 8 -- Style Guide for Python Code PEP Index > PEP 8 -- Style ...

随机推荐

  1. webpack构建项目

    webpack构建项目 案例代码戳这里 ps:每个案例对应相应的demo,例如"案例1"对应"demo1" 一.webpack基本功能及简单案例 安装webpa ...

  2. tomcat警告setting property 'debug' to '0' did not find a matching property

    在使用tomcat6.0版本结合myeclipse进行java web项目,运行程序显示setting property 'debug' to '0' did not find a matching ...

  3. Wannafly挑战赛5 补题

    A 珂朵莉与宇宙 题目链接: https://www.nowcoder.com/acm/contest/36/A 思路: 科学暴力:枚举前缀和,同时计算前缀和里面可能出现的完全平方数,匹配前缀和 与完 ...

  4. 矩阵的奇异值分解(SVD)(理论)

    矩阵的奇异值分解(Singular Value Decomposition,SVD)是数值计算中的精彩之处,在其它数学领域和机器学习领域得到了广泛的应用,如矩阵的广义逆,主分成分析(PCA),自然语言 ...

  5. Hibernate学习(二)关系映射----基于外键的单向一对一

    事实上,单向1-1与N-1的实质是相同的,1-1是N-1的特例,单向1-1与N-1的映射配置也非常相似.只需要将原来的many-to-one元素增加unique="true"属性, ...

  6. 41.Linux应用调试-修改内核来打印用户态的oops

    1.在之前第36章里,我们学习了通过驱动的oops定位错误代码行 第36章的oops代码如下所示: Unable to handle kernel paging request at //无法处理内核 ...

  7. Netty之二进制文件传输

    传输会话简要 客户端发起一个文本请求给服务器端, 服务器端解析里面文本, 返回文件给客户端, 客户端解析文件 服务器端 因为示例文件比较小, 所以没有做分段传输, 而是直接一次性把整个文件byte[] ...

  8. js比较日期大小

    第一种方法: var starttime = "2007-1-2 7:30"; var endtime = "2007-2-31 8:30"; alert(Co ...

  9. Web Api 基于Zookeeper的服务注册与发现

    安装与差异 Zookeeper安装请参考我上篇文章 http://www.cnblogs.com/woxpp/p/7700368.html 基于Nginx的服务提供和消费 基于zookeeper的服务 ...

  10. javascript变量:全局?还是局部?这个得注意

    在JS中.是没有块级作用域的 举两个个样例: if语句块:     if (true){ var name='Ling'; } alert(name); 输出:Ling for语句块; for(var ...