关于例外
Java几十年前问世时,它当时是相当创新的。 特别是,它的异常处理机制比以前的C / C ++有了很大的改进。 例如,为了读取文件,可能会发生很多异常:文件可能不存在,文件可能是只读的,等等。<!-more-→
关联的类似Java的伪代码类似于:
Filefile=newFile("/path");if(!file.exists){System.out.println("File doesn't exist");
}elseif(!file.canRead()){System.out.println("File cannot be read");
}else{// Finally read the file// Depending on the language// This could span seveal lines
} 分离的try catch块背后的想法是将业务代码和异常处理代码分开。
try{Filefile=newFile("/path");// Finally read the file// Depending on the language// This could span seveal lines
}catch(FileNotFoundExceptione){System.out.println("File doesn't exist");
}catch(FileNotReadableExceptione){System.out.println("File cannot be read");
} 当然,上面的代码是无用的独立代码。 它可能构成了读取文件的专用方法的主体。
publicStringreadFile(Stringpath){if(!file.exists){returnnull;}elseif(!file.canRead()){returnnull;}else{// Finally read the file// Depending on the language// This could span seveal linesreturncontent;}
} 上述catch块的问题之一是它们返回null 。 因此:
- 调用代码需要每次检查是否为
null值 - 无法知道是否未找到文件,或者文件是否可读。
使用更实用的方法可以解决第一个问题,因此可以组合方法。
publicOptional<String>readFile(Stringpath){if(!file.exists){returnOptional.empty();}elseif(!file.canRead()){returnOptional.empty();}else{// Finally read the file// Depending on the language// This could span seveal linesreturnOptional.of(content);}
} 可悲的是,它对第二个问题没有任何改变。 纯粹的功能性方法的追随者可能会舍弃先前的代码段,而采用类似这样的方法:
publicEither<String,Failure>readFile(Stringpath){if(!file.exists){returnEither.right(newFileNotFoundFailure(path));}elseif(!file.canRead()){returnEither.right(newFileNotReadableFailure(path));}else{// Finally read the file// Depending on the language// This could span seveal linesreturnEither.left(content);}
} 而且,与之前的代码相比,它有了很大的改进。 由于返回值的正确部分,它可以准确说明失败的原因(如果失败了),因此它现在更具意义。
不幸的是,仍然存在一个问题,而不是一个很小的问题。 那调用代码呢? 它需要处理失败。 或更可能的是,让调用代码来处理它,依此类推,直到最顶层的代码。 对我来说,这使得不可能将无异常功能方法视为一种改进。
例如,这就是Go中发生的情况:
items,err:=todo.ReadItems(file)iferr!=nil{fmt.Errorf("%v",err)} 如果代码在这里结束,这很好。 但是,否则,必须如上所述将err一直传递到调用代码。 当然,这里有panic关键字,但是看来这不是处理异常的首选方法。
最奇怪的是,这正是人们抱怨Java的检查异常的原因:必须在它们出现的确切位置处处理它们,并且方法签名必须相应地更改。
这就是Java开发人员在受检查的异常捕获块中所做的事情……以及为什么我认为它们只是无用的冗长pic.twitter.com/52bYuaZRWL
— Mario Fusco🇪🇺(@mariofusco) 2016年6月6日
因此,我都赞成未检查的异常。 这些方法的唯一缺点是它们破坏了纯函数式编程-抛出异常被认为是副作用。 除非您使用的是纯粹的功能方法,否则没有动机避免未检查的异常。
而且,语言和框架可以提供挂钩来处理最顶层的异常。 例如,在JVM上,它们包括:
- 在JDK中,
Thread.setDefaultUncaughtExceptionHandler() - 在Vaadin中,
VaadinSession.setErrorHandler() - 在Spring MVC中,
@ExceptionHandler - 等等
这样,您可以让您的异常冒泡到应有的处理方式。 拥抱(未经检查的)异常!
翻译自: https://blog.frankel.ch/exceptions/
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
