Java 处理无法发生的异常的最佳方法

Java 处理无法发生的异常的最佳方法,java,exception-handling,Java,Exception Handling,我使用以下代码构建一个SQL语句,该语句更新特定对象所具有的字段的值。我的问题是,因为我检查对象是否有特定字段,所以异常永远不会发生。使此代码更具可读性的最佳方法是什么?例如,避免使用try{}catch{}块 List<Field> modelFields = Arrays.asList(model.getClass().getFields()); String updateString = ""; for (Field field : fields) { if (m

我使用以下代码构建一个SQL语句,该语句更新特定对象所具有的字段的值。我的问题是,因为我检查对象是否有特定字段,所以异常永远不会发生。使此代码更具可读性的最佳方法是什么?例如,避免使用try{}catch{}块

 List<Field> modelFields = Arrays.asList(model.getClass().getFields());
 String updateString = "";

 for (Field field : fields) {
   if (modelFields.contains(field)) {
            try {
                updateString += " " + field.get((Object) model) + " ";
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            updateString += " NULL ";
        }
    }
List modelFields=Arrays.asList(model.getClass().getFields());
字符串updateString=“”;
用于(字段:字段){
if(modelFields.contains(字段)){
试一试{
updateString+=“”+字段。获取((对象)模型)+“”;
}捕获(非法访问例外e){
e、 printStackTrace();
}
}否则{
updateString+=“NULL”;
}
}

如果您认为该异常永远不会发生,则抛出一个包含原始异常的运行时异常:

try {
    updateString += " " + field.get((Object) model) + " ";
} catch (IllegalAccessException e) {
    throw new IllegalStateException("this should never happen: the field is supposed to be public and thus accessible", e);
}

这样,如果你错了,或者如果代码发生了变化,不可能的事情变成了可能,你会有一个异常,带有明确的错误消息和异常的根本原因,而不是默默地忽略错误,然后得到一个不相关的错误,或者更糟的是,一个有效的,但结果不正确。

例外的全部原因是,我们不希望它们在大多数情况下发生。如果构建一个健壮的大型应用程序,您应该始终以一种有意义的方式编写以处理异常,中止应用程序正在尝试的任何子任务,并以一种不依赖任何代码的方式继续

但是,如果您正在构建一种更轻量级的工具,可以在出现问题时退出,那么捕获并将检查过的异常作为未检查的异常(通常是
RuntimeException
)重新刷新可以让您快速编写代码,而不必担心检查过的异常在代码中到处传播


这不仅仅是一个不期望它现在发生的情况,而是一个良好的实践将持续到未来。底层实现可能会发生变化,假定无法引发异常的代码可能会由于在其他类中所做的更改而突然变得能够引发异常。最糟糕的事情是吞下例外;至少,确保它们打印到日志和/或控制台。

我同意@JBNizet的答案。然而,也许并非所有情况下,您都希望出现无法发生的异常

我承认,这可能与OP的意图略有不同,但我认为在更广泛的背景下,这仍然有助于给出正确的答案

参见下面的示例

public class App {
  enum Which {ONE, TWO};
  String on(Which which) {
    switch (which) {
      case ONE: return "This is one";
      case TWO: return "This is another";
      default: throw new IllegalStateException("Missing case: "+which.name()+" of Which");
    }
  }
}
假设有人添加了第三个枚举值
3
。这段代码总是可以很好地编译,并且编辑器(Netbeans/Eclipse)也不会将其标记为问题。您只会发现在运行时出现问题

在这种情况下,我甚至建议确保没有定义明确抛出异常的
default
case。如果在javac或editor中选择了正确的设置,它至少会更早地被标记。在最坏的情况下,它会编译,但在运行时,您仍然会得到一个RuntimeException:

线程“main”java.lang.RuntimeException中的异常:不可编译的源代码-缺少返回语句

有点可疑……”运行时不可编译

这只适用于编译器或编辑器应该能够理解的绑定开关集,仅表示Enum,而不是String或int。对于这些情况,我可能建议仍然为未覆盖的情况设置显式异常

啊-而且,我必须说,在很多情况下,切换情况是可以避免的。。。通过将案例作为方法直接绑定到枚举值(重写抽象方法),或者通过实现

以下是重新实现枚举的方式:

public class App {
  enum Which {
    ONE { @Override String on() { return "This is One"; } }, 
    TWO { @Override String on() { return "This is Two"; } }, 
    THREE { @Override String on() { return "This is Three"; } }, 
    ;

    abstract String on();
  };

  static String on(Which which) {
    return which.on();
  }

  public static void main(String[] args) {
    String result = on(Which.THREE);
  }
}
现在我们已经完全避免了这种情况。。。它现在总是归结为编译时检测到的未实现方法!此外,由于不必进行开关/案例查找,因此速度也要快得多

这可能是最终目标应该是:

与运行时异常相比,更喜欢编译时错误


我完全同意。撞车和烧毁。但我可能不会选择
IllegalStateException
(方法在非法或不适当的时间被调用)。在这些情况下,我倾向于选择
RuntimeException
AssertionError
对我来说,如果我在执行关键代码之前检查了一些条件,那么捕获异常会给我留下更难阅读的代码和更混乱的代码,你真的没有选择的余地。如果调用一个抛出已检查异常的方法,要么捕获它,要么抛出它。请注意,您的文件示例可能引发异常:没有任何东西可以保证在存在性检查和读取之间未删除该文件。更不用说它可以存在,但不可读;尤其是在异常消息中,而不是在注释行(通常在注释行中看到)包含“这永远不会发生”。