我已经在StackOverFlow上阅读了有关已检查和未经检查的异常的多个帖子.老实说,我还是不太确定如何正确使用它们.
Joshua Bloch在" Effective Java "中说过
对可恢复条件使用已检查的异常,对编程错误使用运行时异常(第2版中的第58项)
让我们看看我是否正确理解这一点.
以下是我对已检查异常的理解:
try{
String userInput = //read in user input
Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
id = 0; //recover the situation by setting the id to 0
}
Run Code Online (Sandbox Code Playgroud)
1.以上是否考虑了检查异常?
2. RuntimeException是未经检查的异常吗?
以下是我对未经检查的异常的理解:
try{
File file = new File("my/file/path");
FileInputStream fis = new FileInputStream(file);
}catch(FileNotFoundException e){
//3. What should I do here?
//Should I "throw new FileNotFoundException("File not found");"?
//Should I log?
//Or should I System.exit(0);?
}
Run Code Online (Sandbox Code Playgroud)
4.现在,上述代码也不能成为检查异常吗?我可以尝试恢复这样的情况吗?我可以吗?(注意:我的第3个问题在catch上面)
try{
String …Run Code Online (Sandbox Code Playgroud) java exception runtimeexception checked-exceptions unchecked-exception
多年来,我一直无法得到以下问题的正确答案:为什么一些开发人员如此反对已检查的异常?我有很多对话,在博客上阅读,阅读Bruce Eckel所说的内容(我看到的第一个人反对他们).
我目前正在编写一些新代码,并非常注意我如何处理异常.我试图看到"我们不喜欢被检查的例外"人群的观点,我仍然看不到它.
每次谈话结束时,同样的问题都没有得到答复......让我把它设置起来:
一般来说(从Java的设计方式来看),
我听到的一个常见论点是,如果发生异常,那么开发人员将要做的就是退出该程序.
我听到的另一个常见论点是,经过检查的异常会使重构代码变得更加困难.
对于"我将要做的就是退出"这个论点,我说即使你要退出,你也需要显示一个合理的错误信息.如果您只是在处理错误,那么当程序退出而没有明确说明原因时,您的用户将不会过于高兴.
对于"它很难重构"的人群,这表明没有选择适当的抽象级别.而不是声明方法抛出IOException,IOException应该转换为更适合正在发生的事件的异常.
我没有使用catch(Exception)包装Main的问题(或者在某些情况下catch(Throwable)以确保程序可以正常退出 - 但我总是捕获我需要的特定异常.这样做允许我,至少,显示适当的错误消息.
人们从不回复的问题是:
如果你抛出RuntimeException子类而不是Exception子类,那么你怎么知道你应该捕获什么?
如果答案是捕获异常,那么您也会以与系统异常相同的方式处理程序员错误.这对我来说似乎不对.
如果您捕获Throwable,那么您将以相同的方式处理系统异常和VM错误(等).这对我来说似乎不对.
如果答案是你只捕获你知道的异常,那么你怎么知道抛出的是什么?当程序员X抛出一个新的异常并忘记捕获它时会发生什么?这对我来说似乎非常危险.
我会说显示堆栈跟踪的程序是错误的.那些不喜欢检查异常的人是不是觉得那样?
那么,如果您不喜欢已检查的异常,您可以解释为什么不能并且回答那些无法解答的问题吗?
编辑:我不是在寻找何时使用任何一个模型的建议,我正在寻找的是为什么人们从RuntimeException扩展,因为他们不喜欢从Exception扩展和/或为什么他们捕获异常然后重新抛出RuntimeException而不是将抛出添加到他们的方法中.我想了解不喜欢检查异常的动机.
如何从Java 8流/ lambdas中抛出CHECKED异常?
换句话说,我想像这样编译代码:
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(className -> Class.forName(className))
.collect(Collectors.toList());
return classes;
}
Run Code Online (Sandbox Code Playgroud)
此代码无法编译,因为Class.forName()上面的方法抛出ClassNotFoundException,检查.
请注意我不希望将已检查的异常包装在运行时异常中,而是抛出包装的未经检查的异常.我想抛出已检查的异常本身,而不是向流添加丑陋的try/ catches.
在Java(或任何其他具有已检查异常的语言)中,在创建自己的异常类时,如何确定是应该选中还是取消选中它?
我的直觉是,如果调用者能够以某种富有成效的方式恢复,那么将调用一个已检查的异常,其中未经检查的异常对于不可恢复的情况更多,但我会对其他人的想法感兴趣.
class throwseg1
{
void show() throws Exception
{
throw new Exception("my.own.Exception");
}
void show2() throws Exception // Why throws is necessary here ?
{
show();
}
void show3() throws Exception // Why throws is necessary here ?
{
show2();
}
public static void main(String s[]) throws Exception // Why throws is necessary here ?
{
throwseg1 o1 = new throwseg1();
o1.show3();
}
}
Run Code Online (Sandbox Code Playgroud)
为什么编译器报告方法show2(),show3()以及main()具有
未报告的异常必须捕获或声明要抛出的异常
当我throws Exception从这些方法中删除?
java exception-handling unhandled-exception throws checked-exceptions
我正在使用Java 8中的新lambda特性,并发现Java 8提供的实践非常有用.但是,我想知道是否有一种很好的方法可以解决以下情况.假设您有一个对象池包装器,需要某种工厂来填充对象池,例如(使用java.lang.functions.Factory):
public class JdbcConnectionPool extends ObjectPool<Connection> {
public ConnectionPool(int maxConnections, String url) {
super(new Factory<Connection>() {
@Override
public Connection make() {
try {
return DriverManager.getConnection(url);
} catch ( SQLException ex ) {
throw new RuntimeException(ex);
}
}
}, maxConnections);
}
}
Run Code Online (Sandbox Code Playgroud)
将函数接口转换为lambda表达式后,上面的代码变为:
public class JdbcConnectionPool extends ObjectPool<Connection> {
public ConnectionPool(int maxConnections, String url) {
super(() -> {
try {
return DriverManager.getConnection(url);
} catch ( SQLException ex ) {
throw new RuntimeException(ex);
}
}, maxConnections); …Run Code Online (Sandbox Code Playgroud) 在Java中,抛出已检查异常的方法(异常或其子类型 - IOException,InterruptedException等)必须声明throws语句:
public abstract int read() throws IOException;
Run Code Online (Sandbox Code Playgroud)
不声明throws语句的方法不能抛出已检查的异常.
public int read() { // does not compile
throw new IOException();
}
// Error: unreported exception java.io.IOException; must be caught or declared to be thrown
Run Code Online (Sandbox Code Playgroud)
但是在安全方法中捕获已检查的异常在java中仍然是合法的:
public void safeMethod() { System.out.println("I'm safe"); }
public void test() { // method guarantees not to throw checked exceptions
try {
safeMethod();
} catch (Exception e) { // catching checked exception java.lang.Exception
throw e; …Run Code Online (Sandbox Code Playgroud) java exception try-catch checked-exceptions unchecked-exception
我在java中有这个工厂方法:
public static Properties getConfigFactory() throws ClassNotFoundException, IOException {
if (config == null) {
InputStream in = Class.forName(PACKAGE_NAME).getResourceAsStream(CONFIG_PROP);
config = new Properties();
config.load(in);
}
return config;
}
Run Code Online (Sandbox Code Playgroud)
我想将两个已检查的异常转换为未经检查的异常.最好的方法是什么?
我应该捕获异常并使用捕获的异常作为内部异常抛出一个新的RuntimeException吗?
有没有更好的方法来做到这一点,或者我是否应该首先尝试这样做?
编辑:
只是为了澄清.这些异常将是致命的,因为配置文件基本上是程序的操作,所有异常都将被捕获并记录在我的程序的顶层.
我的目的是避免不必要的抛出异常,将异常添加到调用我的工厂的每个方法的签名中.
我最近发现并写了一篇关于这样一个事实的博客:有可能通过javac编译器偷看一个已检查的异常,并将它扔到不能抛出它的地方.这在Java 6和7中编译并运行,抛出一个SQLExceptionwithout throws或catch子句:
public class Test {
// No throws clause here
public static void main(String[] args) {
doThrow(new SQLException());
}
static void doThrow(Exception e) {
Test.<RuntimeException> doThrow0(e);
}
static <E extends Exception> void doThrow0(Exception e) throws E {
throw (E) e;
}
}
Run Code Online (Sandbox Code Playgroud)
生成的字节码表示JVM并不真正关心已检查/未检查的异常:
// Method descriptor #22 (Ljava/lang/Exception;)V
// Stack: 1, Locals: 1
static void doThrow(java.lang.Exception e);
0 aload_0 [e]
1 invokestatic Test.doThrow0(java.lang.Exception) : void [25]
4 return
Line numbers:
[pc: …Run Code Online (Sandbox Code Playgroud) 我有一些代码可能会抛出已检查和运行时异常.
我想捕获已检查的异常并将其包装为运行时异常.但是如果抛出RuntimeException,我不必将它包装起来,因为它已经是运行时异常.
我的解决方案有点开销,并不"整洁":
try {
// some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
Run Code Online (Sandbox Code Playgroud)
想要更优雅的方式吗?