《Core Java Volume I》读书笔记——异常

栏目: Java · 发布时间: 5年前

内容简介:先上图:Java的顶级异常类是

异常分类

先上图:

《Core Java Volume I》读书笔记——异常

Java的顶级异常类是 Throwable 类,下面分为 ErrorException 两大子类。 Error 及其子异常代表的是 Java 运行时系统内部错误,资源耗尽等情况。如果这种异常发生了,我们只能让自己的程序退出。而 Exception 及其分支异常则是我们写代码时需要关注的。

上面是按照类的继承来分的。另外一种更重要的分法是把 ErrorRuntimeException 及其子类异常称为 非受检异常(unchecked exception) ,剩余其它的所有异常称为 受检异常(checked exception) 。所谓非受检异常就是我们代码中无需对这类异常进行捕获处理,但受检异常则必须有地方捕获处理,否则编译器编译的时候就会报错。

为什么非受检异常无需处理呢?一方面,对于 Error 类的异常刚才说了,是系统内部错误,任何时候任何地方都可能出现,我们避免不了,如果出现了,我们也无能为力。另一方面,对于 RuntimeException 异常,基本都是因为我们的代码有bug导致的,这个时候正确的解决方法是修复代码bug,而不是try catch(如果你都已经知道catch了,那你还不赶紧改掉bug?)。

为什么受检异常需要程序处理?因为受检异常也无法避免,且往往不是我们自己代码bug导致的(这点和 RuntimeException 不同),但如果出现了这类异常,我们一般还是可以处理的(这点和 Error 不同)。拿受检异常 FileNotFoundException 举个例子,我们从磁盘读取文件时,如果文件不存在就会抛这个异常,系统上面这个文件存不存在不是我们能决定的,也许你可以先判断存不存在,存在才去读。但这两个操作不是一个原子操作,也许你检查的时候在,真正去读的时候就不在了,所以避免不了。但如果真的出现了,我们的程序不一定就要退出,也许可以采取其它方式让程序继续,这是由业务场景决定的。比如比较常见的一种场景就是配置文件,如果不存在,就全部使用默认值。

以下是 Error 的直接子类:

AnnotationFormatError, AssertionError, AWTError, CoderMalfunctionError, FactoryConfigurationError, FactoryConfigurationError, IOError, LinkageError, SchemaFactoryConfigurationError, ServiceConfigurationError, ThreadDeath, TransformerFactoryConfigurationError, VirtualMachineError

以下是 Exception 的直接子类:

AclNotFoundException, ActivationException, AlreadyBoundException, ApplicationException, AWTException, BackingStoreException, BadAttributeValueExpException, BadBinaryOpValueExpException, BadLocationException, BadStringOperationException, BrokenBarrierException, CertificateException, CloneNotSupportedException, DataFormatException, DatatypeConfigurationException, DestroyFailedException, ExecutionException, ExpandVetoException, FontFormatException, GeneralSecurityException, GSSException, IllegalClassFormatException, InterruptedException, IntrospectionException, InvalidApplicationException, InvalidMidiDataException, InvalidPreferencesFormatException, InvalidTargetObjectTypeException, IOException, JAXBException, JMException, KeySelectorException, LambdaConversionException, LastOwnerException, LineUnavailableException, MarshalException, MidiUnavailableException, MimeTypeParseException, MimeTypeParseException, NamingException, NoninvertibleTransformException, NotBoundException, NotOwnerException, ParseException, ParserConfigurationException, PrinterException, PrintException, PrivilegedActionException, PropertyVetoException, ReflectiveOperationException, RefreshFailedException, RemarshalException, RuntimeException, SAXException, ScriptException, ServerNotActiveException, SOAPException, SQLException, TimeoutException, TooManyListenersException, TransformerException, TransformException, UnmodifiableClassException, UnsupportedAudioFileException, UnsupportedCallbackException, UnsupportedFlavorException, UnsupportedLookAndFeelException, URIReferenceException, URISyntaxException, UserException, XAException, XMLParseException, XMLSignatureException, XMLStreamException, XPathException

以下是 RuntimeException 的直接子类:

AnnotationTypeMismatchException, ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, CompletionException, ConcurrentModificationException, DataBindingException, DateTimeException, DOMException, EmptyStackException, EnumConstantNotPresentException, EventException, FileSystemAlreadyExistsException, FileSystemNotFoundException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException, IllformedLocaleException, ImagingOpException, IncompleteAnnotationException, IndexOutOfBoundsException, JMRuntimeException, LSException, MalformedParameterizedTypeException, MalformedParametersException, MirroredTypesException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NoSuchMechanismException, NullPointerException, ProfileDataException, ProviderException, ProviderNotFoundException, RasterFormatException, RejectedExecutionException, SecurityException, SystemException, TypeConstraintException, TypeNotPresentException, UncheckedIOException, UndeclaredThrowableException, UnknownEntityException, UnmodifiableSetException, UnsupportedOperationException, WebServiceException, WrongMethodTypeException

本节最后再说明一个问题:能否用try...catch来捕获非受检异常,比如空指针异常NullPointerException?

答案是可以的,任何异常都可以用try...catch来捕获,不会有语法错误,且如果发生了对应的异常,的确可以捕获到。但语法上可以不代表实际中就能这么用,实际编码的时候千万别去捕获非受检异常,那样会被别人鄙视的。如果你已经预见可能会产生某种 RuntimeException 的异常,在代码里面做一下判断就好了,而不是用try...catch.

关于异常使用的一些注意点

  1. 捕获多个异常时,后面的异常不能是前面异常的子类,否则会报语法错误。比如下面的就是错误的,因为后面的 FileNotFoundException 是前面 IOException 的子类:

    try {
        // do something;
    } catch (IOException ioe) {
        // do something;
    } catch (FileNotFoundException e) {
        // do something;
    }
  2. 从Java SE7开始,可以在一个catch里面捕获多个异常,但要注意多个异常之间不能有继承关系,比如不能在一个catch里面捕获 FileNotFoundExceptionIOException ,因为他两个有继承关系。使用语法为: catch (ExceptionType1 | ExceptionType2 e) . 还有要特别注意的是,捕获多个异常的时候,我们定义的那个异常变量 e 是final的,所以不能在catch的函数体里面给它赋值。但如果是只捕获一个异常的情况下,不是final,可以赋值。看下面代码:

    try {
        // do something;
    } catch (FileNotFoundException e1) {
        // 没有问题,e1不是final,可以重新赋值
        e1 = new FileNotFoundException("xxx");      
    } catch (IOException | ParseException e2) {
        // 语法错误,e2是final的,不能赋值
        e2 = new IOException("xxx");
    }
  3. 我们覆写(override)父类的方法的时候,如果这个方法有抛出受检异常,那我们覆写后抛出的异常不能比父类抛出的异常更宽泛,也就是说只能抛出父类抛出的异常或者其子类异常。当然,父类抛异常,子类覆写后不抛异常也是完全OK的。
  4. 我们用 throws 声明抛出一个受检异常,实际抛的时候,抛出声明的异常的子类异常也是OK的。捕获到异常的人可以使用 e.getClass().getTypeName() 获取抛出的真正异常类别。

使用异常的一些技巧

最后附一下 Core Java Volume I 一书中关于使用异常的一些技巧,为了保持原汁原味就直接附上英文了。

  1. Exception handling is not supposed to replace a simple test. 这个意思就是不要把try...catch当成分支判断去使用。

    // 假设我们需要遍历一个栈的元素,如何处理栈空的情况呢?
    
    // 正确的方式是每次先判断栈是否空,如下:
    if (!s.empty()) { s.pop(); }
    
    // 错误的方式是捕获栈空时抛出的异常(这是一个非受检异常),如下
    try {
        s.pop();
    } catch (EmptyStackException e) {
        // do something
    }
  2. Do not micromanage exceptions. 就是别写太多小的try...catch。如下是一个 错误 的示例(正确的方式是把for循环里面的两个小try...catch合并为一个大的try...catch):

    PrintStream out;
    Stack s;
    for (i = 0; i < 100; i++) {
        try {
            n = s.pop();
        } catch (EmptyStackException e) {
            // stack was empty
        }
    
        try {
            out.writeInt(n);
        } catch (IOException e) {
            // problem writing to file
        }
    }
  3. Make good use of the exception hierarchy. 意思就是要合理使用异常的层次结构,尽量不要直接抛顶级异常,比如Throwable、Exception、RuntimeException等,尽量找一个比较合适的子类异常。如果没有,可以自定义异常。
  4. Do not squelch exceptions. 不要压制异常。
  5. When you detect an error, “tough love” works better than indulgence. 当你发现错误时,“强硬的爱”比放纵更有效。
  6. Propagating exceptions is not a sign of shame. 把异常抛出去并不可耻。

4、5、6三条要表达的核心意思就是该出手时就出手,该抛异常就抛异常。别觉得这个异常发生的几率很低,就自己默默地捕获然后忽略了,或者没有正确处理。把异常抛给更适合处理异常的上层代码并没有什么不合适的。早点抛出,晚点捕获(throw early, catch late)。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Creative Curve

The Creative Curve

Allen Gannett / Knopf Doubleday Publishing Group / 2018-6-12

Big data entrepreneur Allen Gannett overturns the mythology around creative genius, and reveals the science and secrets behind achieving breakout commercial success in any field. We have been s......一起来看看 《The Creative Curve》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具