大数跨境
0
0

如何做异常处理?

如何做异常处理? 摩尔线程
2024-02-14
0

你好, 我是Alan, 作为一个程序员, 我们都非常希望代码不出现太大的bug, 那么异常处理就是必不可少的, 那么今天我们就来聊聊异常处理。

首先我们来看看两种不同编程语言的异常处理方式, 一种是Java的异常处理方式, 另外一种是Go语言的异常处理方式,

Go语言使用多返回值来返回错误信息

func echo(request string) (response string, err error) { 
    if request == "" { 
      err = errors.New("empty request"
      return 
    } 
    response = fmt.Sprintf("echo: %s", request) 
    return
}

然后使用if err!=nil去处理异常 

resp, err := echo(req)
if err != nil {
 fmt.Printf("error: %s\n", err)      
}

观察上面这段代码, 不知道你有没有想为什么只判断err为不为空呢, 而不去判断response为不为空呢? Go语言老鸟会跟你说这是约定俗成,  但是实际情况可能是echo函数的第一个返回值response为空, 而第二个返回值err不为空,  或者两个都为空。

这样的多返回值+if判断就会给程序员造成非常大的困惑, 因为你每次看到一个函数返回异常, 都在想到底哪个为空? 而且这种逻辑上的混乱编译器是无法解决的。

Java采用了另外一种方式, 那就是check exception, 类似下面这种

String echo(String request) EmptyReqException {
    if (request == null) {
       throw new EmptyReqExpection();
    }
    return requset;
}

上面的echo函数表示了这样一种含义, 那就是这个函数只会返回一个值,值的类型要么是String, 要么是EmptyReqException。这样就有效避免了Go语言的多返回值+if判断所带来的逻辑混淆了。

同时在Java中, 如果一个函数返回了错误, 编译器就会强迫程序员去检查所有可能出现的错误之后, 才能去使用数据, 

对比这两者显然Java的异常处理是更加严谨的。

下面就简单介绍一下Java异常处理的一些细节

Java中的异常处理有两个东西

  • exception, 其中又分为两种, 可检查(checked)和不可检查(unchecked)异常, 其中可检查异常必须在源代码中显式的进行捕获, 这是编译期的一部分。在下文中我就将checked exception简称为CE了。

  • error, 它是指在正常情况下, 不太可能出现的情况。

  • exception和err这两者又都继承了Throwable类。


介绍完这些细节之处, 就来看一些关于异常处理的最佳实践

(1) 不要"省略"else分支

在很多地方, 我看到很多人的"代码质量建议"的其中一条往往是, "省略else分支", 或者 "嵌套的else分支是有害的", 我想说这种思想是完全片面的, 因为无脑的省略else分支往往会出现逻辑遗漏。

if...else...的含义是, 如果if条件成立, 做某件事情, if的条件不成立, 那就要做另外一件事情, 也就是说当你考虑完正确路径(happy path)之后, 你是需要考虑错误路径sad path的, 而如果你想都不想, 直接的就把else分支给省略了, 那么就可能出现一些逻辑遗漏了。

其实我觉得写上else语句也没有什么大不了的, 等考虑好else中逻辑的处理, 再将它省略也是可以的

if (response != null) {
  return ...
else {
  return ...
}

同时我们也应该谨慎的去对待else出现的场景。

(2) 不要在try...catch...中包含太多代码

try {
  A();
catch(A e) {

}

try {
  B();
catch(A e) {...}

如果函数A出现异常A, 函数B也出现异常A, 那么应该尽可能的将这两者分开, 因为如果你使用了logger的话, 我们其实可以很快的判断是哪一个函数出现了问题, 这样很快就能定位到问题, 并将它解决。

尽量在catch中使用log或者把异常抛出来, 少写e.printStackTrace(), 因为在分布式项目中去打印堆栈信息, 并处理是一件很麻烦的事情。

(3) 不要使用Exception这样的通用异常, 而应该捕获特定异常。

很多人去批判Java的异常处理的一点就是程序员喜欢使用Exception去捕获异常, 我觉得这是典型的"厨师做不好菜说刀不行"。

使用Exception的坏处就是, 它会去捕获所有的异常, 这样有的异常就会被隐藏起来, 难以调试。一种正确的做法就是好好的去思考异常的范围, 将其不断的缩小。

(4) Java CE的本质

Java的CE其实本质上是一种union type

String echo(String request) EmptyReqException {

}

可以认为函数echo返回一个union类型: {String, EmptyReqException}。这种类型是比较严谨的, 因为它只有两种情况, 要么是正常, 要么是异常。

最后, 代码的质量需要我们程序员去保证的, 而不能只是的通过语言层面去提供, 虽然Java的异常处理很严谨, 但是依然可能会出现抛出80多个异常的情况, 所以我们就要具体问题具体分析了。

【声明】内容源于网络
0
0
摩尔线程
摩尔线程以全功能 GPU 为核心,致力于向全球提供计算加速的基础设施和一站式解决方案,为各行各业的数智化转型提供强大的AI计算支持。
内容 301
粉丝 0
摩尔线程 摩尔线程以全功能 GPU 为核心,致力于向全球提供计算加速的基础设施和一站式解决方案,为各行各业的数智化转型提供强大的AI计算支持。
总阅读113
粉丝0
内容301