内容简介:先上图:Java的顶级异常类是
异常分类
先上图:
Java的顶级异常类是 Throwable
类,下面分为 Error
和 Exception
两大子类。 Error
及其子异常代表的是 Java 运行时系统内部错误,资源耗尽等情况。如果这种异常发生了,我们只能让自己的程序退出。而 Exception
及其分支异常则是我们写代码时需要关注的。
上面是按照类的继承来分的。另外一种更重要的分法是把 Error
和 RuntimeException
及其子类异常称为 非受检异常(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.
关于异常使用的一些注意点
-
捕获多个异常时,后面的异常不能是前面异常的子类,否则会报语法错误。比如下面的就是错误的,因为后面的
FileNotFoundException
是前面IOException
的子类:try { // do something; } catch (IOException ioe) { // do something; } catch (FileNotFoundException e) { // do something; }
-
从Java SE7开始,可以在一个catch里面捕获多个异常,但要注意多个异常之间不能有继承关系,比如不能在一个catch里面捕获
FileNotFoundException
和IOException
,因为他两个有继承关系。使用语法为: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"); }
- 我们覆写(override)父类的方法的时候,如果这个方法有抛出受检异常,那我们覆写后抛出的异常不能比父类抛出的异常更宽泛,也就是说只能抛出父类抛出的异常或者其子类异常。当然,父类抛异常,子类覆写后不抛异常也是完全OK的。
- 我们用
throws
声明抛出一个受检异常,实际抛的时候,抛出声明的异常的子类异常也是OK的。捕获到异常的人可以使用e.getClass().getTypeName()
获取抛出的真正异常类别。
使用异常的一些技巧
最后附一下 Core Java Volume I 一书中关于使用异常的一些技巧,为了保持原汁原味就直接附上英文了。
-
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 }
-
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 } }
- Make good use of the exception hierarchy. 意思就是要合理使用异常的层次结构,尽量不要直接抛顶级异常,比如Throwable、Exception、RuntimeException等,尽量找一个比较合适的子类异常。如果没有,可以自定义异常。
- Do not squelch exceptions. 不要压制异常。
- When you detect an error, “tough love” works better than indulgence. 当你发现错误时,“强硬的爱”比放纵更有效。
- Propagating exceptions is not a sign of shame. 把异常抛出去并不可耻。
4、5、6三条要表达的核心意思就是该出手时就出手,该抛异常就抛异常。别觉得这个异常发生的几率很低,就自己默默地捕获然后忽略了,或者没有正确处理。把异常抛给更适合处理异常的上层代码并没有什么不合适的。早点抛出,晚点捕获(throw early, catch late)。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
算法竞赛入门经典
刘汝佳 / 清华大学出版社 / 2009-11 / 24.00元
《算法竞赛入门经典》是一本算法竞赛的入门教材,把C/C++语言、算法和解题有机地结合在了一起,淡化理论,注重学习方法和实践技巧。全书内容分为11章,包括程序设计入门、循环结构程序设计、数组和字符串、函数和递归、基础题目选解、数据结构基础、暴力求解法、高效算法设计、动态规划初步、数学概念与方法、图论模型与算法,覆盖了算法竞赛入门所需的主要知识点,并附有大量习题。书中的代码规范、简洁、易懂,不仅能帮助......一起来看看 《算法竞赛入门经典》 这本书的介绍吧!