避免处理所有异常,直到它们到达全局处理程序

Posted

技术标签:

【中文标题】避免处理所有异常,直到它们到达全局处理程序【英文标题】:Avoid handling all exceptions until they've reached a global handler 【发布时间】:2016-11-02 16:17:53 【问题描述】:

如果我调用hello.f,编译器会强制我处理所有抛出的异常。我可以使用try? 吞下它们,或者通过不指定要捕获然后重新抛出的异常类型来添加catch all。但是,如果我执行后者,我需要将调用函数标记为 throws,并且该过程一直继续向上堆栈。

是否可以忽略f 的异常,使其最终成为可以全局处理的未处理异常?

enum e : Error 
    case hello
    case world


class hello 
    func f() throws  
        throw e.hello
    

【问题讨论】:

rethrows 似乎不在语言指南中。 那超出了我的范围,我没有写语言指南。 :) 你的标题是“避免处理所有异常”。请澄清你的意思。 “全球处理”是什么意思? 我认为你不能。这是设计使然。 Swift 对错误处理更加严格。 @IanWarburton,是的,我修改了我在评论中快速编写的代码,这不是正确的语法,顺便说一句,但你可以去func g() throws try f() 这个,现在是正确的,在这种情况下,您只需转发错误而不在本地处理它。 【参考方案1】:

是否可以忽略 f 的异常,最终成为可以全局处理的未处理异常?

总之,没有。 Swift 错误处理设计的全部要点是您必须明确承认每个阶段都可能出现错误。

在我看来,你在思考 Objective-C 如何处理 NSException,但 Swift 不是这样的(而且 Error 也不像 NSException)。

【讨论】:

来自 C#...我认为 Anders Hejlsberg 在这里提出了一个很好的论据...artima.com/intv/handcuffs.html 为什么不能使用rethrows?然后,您只需将责任传递给链中的前一个调用者。这不是 OP 想要的吗? 其实我应该说的是throws,而不是rethrows @rmaddy 绝对,但这不是“忽略”。正如我所说,它正在承认。当然,我可能不明白 Ian 想要什么,但我认为他想在每个阶段throw / try ,没错,你不能那样做。 @rmaddy 当然。但我认为 Ian 的意思确实是“忽略”。因为这就是例如响应者链的工作原理,以及 NSException 处理在 Objective-C 中的工作方式:运行时只是不断地沿着调用链 寻找 寻​​找 someone 来处理这件事。 (但我的观点是,Swift 错误处理不是这样的:你必须在调用链的每一步都以某种方式处理它。【参考方案2】:

根据您的期望,我创建了这个示例:

enum PetError : Error 
    case pet


class Pet 
    func pet() throws  
        throw PetError.pet
    


class Cat 
    func cat() throws  
        let pet = Pet()
        try pet.pet()
    

class Tiger 
    func tiger() throws  
        let cat = Cat()
        try cat.cat()
    


然后您可以在您需要的***别处理PetError 异常 (=errors),而在链内,错误只是转发到上层。

let tiger = Tiger()
do 
    try tiger.tiger()
 catch PetError.pet 
    print("PetError.pet")


注意:当然,您可能希望在一天结束时处理所有异常(=错误),但这不是这个小示例的一部分。

【讨论】:

【参考方案3】:

这就是我所追求的。输出是“你好\n”。感谢问题的cmets中的holex。

enum e : Error 
    case hello
    case world


class hello 
    func f() throws  
        throw e.world
    


class goodbye 
    func g() throws  
        let h = hello()
        try h.f()
    

class world 
    func w() throws  
        let g = goodbye()
        try g.g()
    


let w = world()
do 
try w.w()

catch e.world 
    print("hello")

【讨论】:

@holex 我想与世界分享更多我的命名约定。如果你回答,我会给你积分。 @IanWarburton 说到命名约定,类型名称应该是UpperCamelCase,例如HelloGoodbyeWorldE 不过,我确实认为你只是在证明我说的是对的。你必须在你知道错误可以通过这种方式传递的链的每个阶段明确地显示编译器。 @IanWarburton,好的,我已经根据您的代码发布了答案;我实际上并不想要额外的功劳,但我绝对反对你在 Swift 中的命名约定。 @holex 可以说这不是惯例。

以上是关于避免处理所有异常,直到它们到达全局处理程序的主要内容,如果未能解决你的问题,请参考以下文章

Springboot的Filter,HandlerInterceptor,Aspect与异常处理

SpringBoot2.0系列教程Springboot框架添加全局异常处理

Spring全局异常处理的三种方式

在 Android 中设置全局未捕获异常处理程序的理想方法

使用中间件的全局异常处理在 ASP.Net Core 应用程序中不起作用

Java中的全局异常处理