热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【GoLang那点事】深入Go的异常错误处理机制(二)理解

开篇词上一篇文章分享了Go的异常,错误处理使用,未读过的可以点击回顾一下,我们知道程序运行中,有异常,有错误,那么什么是异常,什么是错误,和其他语言相比,Go的异常错误机制有什么优


开篇词



  • 上一篇文章分享了Go的异常,错误处理使用,未读过的可以点击回顾一下,我们知道程序运行中,有异常,有错误,那么什么是异常,什么是错误,和其他语言相比,Go的异常错误机制有什么优点,缺点?我们如何更好的理解,如何用Go写出更健壮的程序,今天来聊一聊这些问题。


异常和错误



  • 关于异常和错误每个人都有自己的理解,很多人往往把这个混为一谈,认为他们是等价的,这里我们从Java 和Go两种语言异常错误体系的设计分析来试图回答这个问题。

  • Java中,Throwable是所有错误(Error)和异常 (Exception) 的基类,整的来说,它们都是程序运行过程中可能出现的问题,区别在哪里呢? Exception是可预料的,而Error是不可预料的,举个例子,工程队要盖一栋楼,我们把盖这栋楼的过程比作程序一段运行的过程,在盖楼的过程中,建筑人员对于对于瓷砖损坏,下雨,断电,设计错误等都是在意料之内的,并且在发生这些问题时是由恢复,补救措施的,而对于地震,地面塌陷,狂风这些问题是不可预知,意料之外的,并且这些问题真的发生了,也是无法补救,恢复的,只能重新来过。Exception我理解为在程序运行中正常情况下意料之中发生的事,是可以被程序员处理,补救,有机会回到正常处理流程的,而Error在程序运行中非正常成矿下发生后是无法被处理,恢复,比如内存溢出,栈溢出等。

  • Go的异常错误设计体系只有Error,任何一切都在方法返回值中返回可能发生的错误,那么go有没有运行过程中意料之外的错误呢,答案是有呢,panic和defer以及recover共同组成了这个体系,但这个体系最终还是被返回Error所处理,什么含义呢,就是在意料之外的panic发生时,在defer中通过recover捕获这个恐慌,转化为错误通过方法返回值告诉方法调用者,看到这里,其实从字面意思,Go中弱化了异常,一切皆错误,都被包装成类似Code,Message的形式返回方法调用者,直到有调用者去处理, 这也是Go的设计精髓,简化没必要存在的。


从编码上看看Go和Java的异常设计思想



  • 如果你看过Go的许多代码,那么 if err != ni , 应该随处可见,尤其是业务代码开发中,是的,Go没有类似 try catch 这样的语句,Go对错误的价值观是可编程,我们看下面的代码:


result1,err := func1()
if err != nil{
return nil,,err
}
result2,err := func2()
if err != nil{
return nil,err
}
result3,err := func3()
if err != nil{
return nil,err
}
return result1+result2+result3,nil

try{
result1 = method1();
reuslt2 = method2();
result3 = method3();
return result1+result2+result3;
}cache(Exception e){
log.error(e);
return null;
}


  • 上面的代码我想了解Java和Go的人都知道,我们从多个方面来看看上面的代码,第一:从顺序角度来看,是否Go更能被理解,每一个方法都有一个结果值和一个可能发生的错误值,而Java需要更多的语法,意味着需要更多理解,思考;第二:从对异常错误处理角度来看,Go中程序员对err有更多的操作空间,有更多的可编程性,而Java中相对可编程性弱化了许多;第三:也是最直观的,代码量我们发现Go的代码量比Java多了将近一半,而这种代码并没有什么技术量,重复的代码到处都是,是的,这也是许多开发者对Go不满意的地方,但这种是可以通过开发者代码设计去规避的,这里暂且不讨论



  • Java中通过 throw new 抛出一个异常,通过 try cache 捕获,而Go中通过 panic 抛出一个恐慌,通过 defer和recover 来处理,我们来看看代码,在分析


func test() (err error){
defer func(){
if e:=recover(); e != nil{
err = e.(error)
}
}()
panic("发生恐慌了")
return err
}

publis Result test(){
try{
throw new RuntimeException("发生异常了")
}cache(Exception e){
//处理错误
1 打印错误,忽略
2 throw e,继续抛出
//转化为code,message
3 new Result(code,e.message)
}
}


  • 我们分析上面两段代码,当异常或者恐慌发生时,我们可以看到Go中在defer里对通过recover捕获panic,将其转化为一个错误,通过返回值的形式返回,而在Java中异常发生时,捕获以后处理方式为要么打印,要么throw出去抛给上层的方法调用者,站在方法全局来看,当你是一个调用者时,你期望的是什么?如果你有接口交互的开发经验,我想你不会给调用接口的人抛出一个exception 或者 panic,他会不高兴的,同样你也不希望接口返回的是一堆堆栈信息,那么 在上面Java的cache中最终是返回一个Result,包含code,message,这样去看,我们对Java异常包装后是否和Go的错误设计有异曲同工之妙,同样的Go通过panic和defer,recover也可以为try,cache, throw这样的处理,但语言层面的设计的本质是不一样的(记住哦),相互的转化只是人为的在包装而已,请不要偏离正轨哦。


聊聊exception和panic给Java和Go带来了什么



  • 不管是Go还是Java,我们知道当程序启动后,对操作系统而言都是一个进程,Java中,在一个进程中可以启动多个线程,线程是Java的最小单位,Go中,一个进程中依然会有多个线程,但这不是最小单位,协程是Go的最小单位;

  • Exception在Java中的作用域是当前线程,也就是说当Exception中发生时,只会影响到当前线程的执行,终止的是当前线程。

  • Panic在Go中的作用域是整个进程,当Panic发生时,如果当前协程没捕获,则整个Go的进程就会终止,这是非常可怕的。

  • 所以需要开发人员在go的错误处理时需要谨慎,需要手工处理所有的err,尤其在对panic可能发生的地方需要捕获,这稍微增加了开发人员的心智负担

  • 同样的,我们能看到Go的程序需要更多的严谨性,健壮性,所以在开发阶段,快速试错,让尽可能多的错误立刻出现,然后修复。

  • 提醒的是,尤其是在设计一些底层框架,方法时,一定需要对panic处理,转化为err返回,否则框架抛出的panic会导致整个Go的程序结束


总结



  • 在我看来,并没有绝对,Java中对异常和错误有一个比较清晰的边界,通过类继承体系进行隔离,错误并不在程序员的考虑范围之内,通过异常体系和控制流程来实现业务逻辑,往往也容易被滥用;而Go中并没有,且弱化了异常的概念,并提供了将异常转化为错误的方法。一切皆错误,拥有更好的可编程性,但同时也带来诸如 if err != nil 的这样的代码到处都是,不同的编程语言对异常错误体系设计不一样,也代表不同开发者的思想,没有对与错,个人认为都能解决特定的问题,同时也会带来一定的困扰,一定要理解这种异常错误体系设计在当前编程语言中的设计思想,才能更好的使用,写出更优雅的代码。


Go认为:



  • 让程序员更直接的接触错误,从而处理

  • 错误是一种可编程的值

  • 强调的是,无论何时,检查错误都是至关重要的,而不是如何避免检查错误


事实上关于Go的错误处理也有一些最佳实践,有自己的思想,后续我也会整理,就不再这边文章中发布了,大家可以看看下面链接的文章



  1. https://blog.golang.org/errors-are-values

  2. https://blog.golang.org/error-handling-and-go

  3. https://blog.golang.org/defer-panic-and-recover


欢迎大家关注微信公众号:“golang那点事”,更多精彩期待你的到来





推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 2022年的风口:你看不起的行业,真的很挣钱!
    本文介绍了2022年的风口,探讨了一份稳定的副业收入对于普通人增加收入的重要性,以及如何抓住风口来实现赚钱的目标。文章指出,拼命工作并不一定能让人有钱,而是需要顺应时代的方向。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
author-avatar
木子小平方_530
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有