异常是什么?
异常就是在程序执行期间发生的打断指令正常执行流程的一个不期望出现的事件。
在Java中,所有的错误和异常都继承自Throwable类。当一个方法内发生错误时,方法会创建一个对象,并把它传递给运行时系统。这个对象就被就做异常对象。
异常对象包含着错误的详细信息,包括错误的类型和该错误发生时系统的状态。创建一个异常对象并把它传递给运行时系统就叫做抛出了一个异常(throwing an exception)。
异常的处理
当我们的应用创建出一个异常对象时,我们有两种方法来处理。
- 要么我们在方法内处理这个异常;
- 要么我们把它传给调用方方法,让调用方方法来处理它。
设置一个方法的职责是一个重要的决定。一个方法应该清晰的表明哪些异常场景它会处理,哪些它不会处理。这是在方法语法中使用throw子句来定义的。
为了处理异常,我们必须在try-catch代码块的catch块中捕获该异常。
如果一个应用的异常没有处理,这个异常会传递给Java虚拟机(JVM),JVM通常会停止这个应用。
异常概述
Java中的所有异常都来自顶级父类Throwable
Throwable下有两个子类Exception和Error。
Error是程序无法处理的错误,一旦出现这个错误,则程序将被迫停止运行,比如OOM,StackOverError,Error一般是JVM的错误。
- StackOverError:栈内存溢出,一般是递归造成的,递归每调用一次都会创建一个栈帧
- OOM:堆内存溢出,创建对象会占用堆内存,空间没管理好就会出错。即
内存泄漏
,就是某些对象没有用了,但是没有被回收
Exception不会导致程序停止,又分为两个部分RunTimeException运行时异常和CheckedException检查异常。
-
RunTimeException常常发生在程序运行过程中,会导致程序当前线程执行失败,又叫做
运行时异常
,是需要程序员处理的,比如空指针是可以try catch的。 -
CheckedException常常发生在程序编译过程中,会导致程序编译不通过,比如把int赋值给了String,javac会告诉你错了,说白了就是语法有问题,一般在写代码时就会被IDE发现。
-
Exception是程序员能够避免的错误,比如空指针,数组越界只是某一个方法,某一个调用出问题了
异常体系保证Java的健壮性
主要通过非运行时异常保证健壮性
运行时异常
我们可以把运行时异常(RUNTIMEEXCEPTION)叫做逻辑异常
,代码写的不严谨,数组越界、空指针异常,程序没有任何提醒,这种异常发生的原因是人为造成的
运行时异常故名思议就是程序在运行的时候出现异常,隐含的一个前提就是程序在编译时是检测不到异常的存在,作者本人也并不知道是否自己的代码中含有运行时异常,所以根本也不可能提前使用try{}catch{}捕获.
运行时异常,编译时没有提示做异常处理,因此通常此类异常的正确理解应该是“逻辑错误”
常见的运行时异常
- 算数异常(除0了)
- 空指针
- 类型转换异常
- 数组越界
- NumberFormateException(数字格式异常,转换失败,比如“a12”就会转换失败)
运行时异常: 都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常(checked Exception)
非运行时异常:FileNotFoundException,比如输入了错误的文件就try catch提醒一下错误,问题产生的根源来自于参与方
一般而言,checked异常指的都是不受程序直接控制的错误。它们通常都是由于与外部资源/网络交互而发生的,例如数据库问题、网络连接错误、文件丢失等问题。
常见的非运行时异常
- lOException
- SQLException
- FileNotFoundException
- NoSuchFileException
- NoSuchMethodException
上面这段代码编译是无法通过的,你会获取到一个编译时异常信息——Unhandled exception type FileNotFoundException(未处理的异常,类型为FileNotFoundException)。
为了使程序能够编译通过,必须用try-catch代码块或者在方法上面throws FileNotFoundException来处理这个异常情况。下面给出的代码就完全可以正常编译。
public static void main(String[] args) throws FileNotFoundException {
FileReader file = new FileReader("somefile.txt");
}
运行之后,没有找到文件,就会抛出FileNotFoundException
checked异常和unchecked异常(运行时异常)的最大区别就是:checked异常会被编译器强制检查,以便指出不受系统控制的意外情况(例如:I/O错误)。unchecked异常是在运行时发生的,用于表示编码错误(例如:一个空指针)。
非运行时异常 (编译异常): 是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
运行异常,可以通过java虚拟机来自行处理,非运行异常,我们应该捕获或者抛出
Java异常都继承自类Throwable,Throwable子类有Error和Exception,其中Exception又分为运行时异常和编译时异常。编译时异常是未雨绸缪性质的异常,是防范,需要显式处理。运行时异常是程序员问题造成,并不强制进行显式处理。
非运行异常=检查异常 需要try catch捕获或者throws抛出
Error
Error是Throwable的一个子类,它表示一个合理的应用程序不应该尝试捕获并处理的严重问题。大多数此类错误都是异常情况。线程死亡(ThreadDeath)错误虽然是正常情况,但它也是Error的子类,因为绝大部分应用都不应该处理这个错误。
方法不需要在其throws子句中声明任何可能在方法执行期间抛出但未捕获的错误的子类,因为这些错误是任何时候都不应该出现的。
也就是说,出于在编译时检查异常的目的,Error和它的子类都被视为unchecked异常。
为什么Error不用处理呢?因为这类问题在程序中是没有办法处理的。举个例子,像内存溢出(OutOfMemoryError)错误,即使我们捕获到了,也不能处理,你可能会说,那我手动进行一次垃圾收集不可以吗?答案是:不可以!因为内存溢出也就是内存不够用了,JVM是在进行垃圾收集后发现内存不够用才报这个错误的,所以这类问题程序是没办法处理的,而这些问题是可以通过编写高质量的代码来避免的。
处理Java异常的最佳实践
- 当一个方法不能执行它所代表的功能时,可以使用checked异常。例如,一个叫做prepareSystem()的方法,它通过加载配置文件并使用这些文件来做一些配置,就可以声明抛出一个FileNotFoundException异常,表示这个方法使用文件系统中的配置文件。
- checked异常理想上不应该用于程序异常,但绝对应该用于资源错误和这中情况下的流程控制。
- 仅仅抛出方法内怎么也处理不了的异常。方法应该首先尝试在遇到异常时就处理它,当在方法内不可能处理时,再抛出这个异常。
- 定义一个异常签名的最好方法时把它声明的和方法名相近。如果你的方法是openFile,那么它抛出的异常就可以是FileNotFoundException,如果你的方法名是findProvider,那么它抛出的异常就可以是NoSuchProviderException。
- 规则就是:如果一个客户端可以合理的从一个异常中恢复为正常,就把这个异常定义为checked异常。如果一个客户端不能从异常中恢复,就把它定义为unchecked异常。
实际上,许多应用程序必须从许多异常中恢复,例如:NullPointerException、IllegalArgumentException等。失败的动作或事务会被中止,但应用必须正常运行并准备为下一个动作或事务服务。
通常,唯一合法的关闭一个应用的时间是在它启动期间。例如,如果一个应用由于配置文件的丢失而不能处理任何业务,那么关闭这个应用就是合法的。
推荐阅读
Java:详解Java中的异常(Error与Exception)
Java:详解Java中的异常(Error与Exception)
【异常】异常的概念,分类和处理机制
异常的练习题
1 能单独和finally语句一起使用的块是(A )
try
catch
throw
throws
解析:处理异常常用的两种方式:
1、try…catch(捕获处理机制);
2、throws(冒泡处理机制).
注意细节:使用try…catch块捕获时可以没有catch块,但当没用catch块的时候必须得有finally块.故选A)
try{
}catch(){
}finally{
}
finally不管是否有异常都会执行,而且,try可以和catch和finally中的一个搭配使用,但是catch和finally不能单独使用
2 以下关于JAVA语言异常处理描述正确的有? CD
throw关键字可以在方法上声明该方法要抛出的异常。
throws用于抛出异常对象。
try是用于检测被包住的语句块是否出现异常,如果有异常,则抛出异常,并执行catch语句。
finally语句块是不管有没有出现异常都要执行的内容。
在try块中不可以抛出异常
解释:
java语言中的异常处理包括声明异常、抛出异常、捕获异常和处理异常四个环节。
throw用于抛出异常。
throws关键字可以在方法上声明该方法要抛出的异常,然后在方法内部通过throw抛出异常对象。
try是用于检测被包住的语句块是否出现异常,如果有异常,则抛出异常,并执行catch语句。
cacth用于捕获从try中抛出的异常并作出处理。
finally语句块是不管有没有出现异常都要执行的内容。
public Test() throws RepletException {
try { System.out.println("Test this Project!")
}catch (Exception e) {
throw new Exception(e.toString());
注意throws是写在方法上,申明要抛出的异常。throw是抛出异常。
3下面程序的输出是什么? B
package algorithms.com.guan.javajicu;
public class TestDemo
{
public static String output = ””;
public static void foo(inti)
{
try
{
if (i == 1)
{
throw new Exception();
}
}
catch (Exception e)
{
output += “2”;
return ;
} finally
{
output += “3”;
}
output += “4”;
}
public static void main(String[] args)
{
foo(0);
foo(1);
System.out.println(output);
}
}
342
3423
34234
323
解释: 首先是foo(0),在try代码块中未抛出异常,finally是无论是否抛出异常必定执行的语句,
所以 output += “3”;然后是 output += “4”;
执行foo(1)的时候,try代码块抛出异常,进入catch代码块,output += “2”;
前面说过finally是必执行的,即使return也会执行output += “3”
由于catch代码块中有return语句,最后一个output += “4”不会执行。
所以结果是3423
4 在try的括号里面有return一个值,那在哪里执行finally里的代码?B
不执行finally代码
return前执行
return后执行
出题的也是不严谨,或者根本不了解,看编译之后的字节码就知道了,确切的说是在return执行的中间。应该增加一个选项,D,return执行到中间的时候发现finally,则先不返回,把值暂存到本地栈,等finally运行之后,如果finally里有返回语句,那么以finally为主,否则才把本地栈里的返回值真的返回。
5 AccessViolationException异常触发后,下列程序的输出结果为( A )
static void Main(string[] args)
{
try
{
throw new AccessViolationException();
Console.WriteLine("error1");
}
catch (Exception e)
{
Console.WriteLine("error2");
}
Console.WriteLine("error3");
}
error2
error3
error3
error2
error1
1.若catch(){}块中,如果有throw 语句,则,try{}catch(){} finally{}块之外的代码不执行;否则,执行。 2.try{}中有异常,则异常下面代码不执行。 3.finally{}中代码必执行。
情况一:出现异常,没有捕捉,那后面的代码就不会执行。情况二:出现异常,catch捕捉成功,那后面的代码按顺序执行。题目中属于情况二,异常被捕捉到了,所有后面代码不受影响
try…catch中,catch捕获到异常后,只要没有抛出异常语句(throw…),并不影响后续程序(try代码块中错误语句及其以后的代码不执行,catch及其以后正常执行)
6 下列哪种异常是检查型异常,需要在编写程序时声明?C
NullPointerException
ClassCastException
FileNotFoundException
IndexOutOfBoundsException
- 粉红色的是受检查的异常(checked exceptions),其必须被 try{}catch语句块所捕获,或者在方法签名里通过throws子句声明.受检查的异常必须在编译时被捕捉处理,命名为 Checked Exception 是因为Java编译器要进行检查,Java虚拟机也要进行检查,以确保这个规则得到遵守.
- 绿色的异常是运行时异常(runtime exceptions),需要程序员自己分析代码决定是否捕获和处理,比如 空指针,被0除…
- 而声明为Error的,则属于严重错误,如系统崩溃、虚拟机错误、动态链接失败等,这些错误无法恢复或者不可能捕捉,将导致应用程序中断,Error不需要捕捉
7 程序读入用户输入的一个值,要求创建一个自定义的异常,如果输入值大于 10 ,使用 throw 语句显式地引发异常,异常输出信息为 ”something’swrong!” ,语句为(A)
if(i>10)throw new Exception("something’swrong!");
if(i>10)throw Exception e("something’swrong!");
if(i>10) throw new Exception e("something’swrong!");
if(i>10)throw Exception( "something’swrong!");
这题目C选项其实是if(i>10) throw new Exception e(“something’swrong!”); 考察的点是是否需要给Exception起名字 而不是楼上那些说题目故意加个e的
throw是语句抛出异常,有两种用法: //***抛出异常e实例或新的Exception实例
1.catch中的throw e;
2.方法体中的throw new Exception();
区别如下: throw e是将已经catch到的e重新抛出,而throw new Exception()是重新生成一个Exception类的对象并抛出。有两点重要区别,第一e中记录了原异常的信息,如除零异常的信息,而new Exception()是一个新对象,当中不包含任何有用的信息;第二e可能存在向上转型,即e的实际类型可能是Exception的子类,而new Exception()就是Exception类的对象。
8 下面有关JAVA异常类的描述,说法错误的是?D
异常的继承结构:基类为Throwable,Error和Exception继承Throwable,RuntimeException和IOException等继承Exception
非RuntimeException一般是外部错误(非Error),其必须被 try{}catch语句块所捕获
Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形,Error不需要捕捉
RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等,必须被 try{}catch语句块所捕获
运行时异常故名思议就是程序在运行的时候出现异常,隐含的一个前提就是程序在编译时是检测不到异常的存在,作者本人也并不知道是否自己的代码中含有运行时异常,所以根本也不可能提前使用try{}catch{}捕获.
异常是指程序运行时(非编译)所发生的非正常情况或错误,当程序违反了语言规则,jvm就会将出现的错误表示一个异常抛出。
异常也是java 的对象,定义了基类 java.lang.throwable作为异常父类。 这些异常类又包括error和exception。两大类
error类异常主要是运行时逻辑错误导致,一个正确程序中是不应该出现error的。当出现error一般jvm会终止。
exception表示可恢复异常,包括检查异常和运行时异常。 检查异常是最常见异常比如 io异常sql异常,都发生在编译阶段。这类通过try、catch捕捉
而运行时异常,编译器没有强制对其进行捕捉和处理。一般都会把异常向上抛出,直到遇到处理代码位置,若没有处理块就会抛到最上层,多线程用thread。run()抛出,单线程用main()抛出。常见的运行异常包括 空指针异常 类型转换异常 数组越界异常 数组存储异常 缓冲区溢出异常 算术异常等
9 下列类在多重catch中同时出现时,哪一个异常类应最后一个列出(C)
ArithmeticException
NumberFormatException
Exception
ArrayIndexOutOfBoundException
解析:这是多重catch块的顺序问题,由于异常处理系统就近寻找匹配异常处理程序,应先子类后父类。
范围越大越放后面
ArithmeticException 是算数异常
NumberFormatException 是数据格式异常
Exception 异常
ArrayIndexOutOfBoundException 数组索引超过界限异常
先处理具体的异常,如果没有则放到一个大的范围之中Exception
10 以下代码执行后输出结果为( B)
public class ExceptionTest
{
public void method()
{
try
{
System.out.println("进入到try块");
}
catch (Exception e)
{
System.out.println("异常发生了!");
}
finally
{
System.out.println("进入到finally块");
}
System.out.println("后续代码");
}
public static void main(String[] args)
{
ExceptionTest test = new ExceptionTest();
test.method();
}
}
try里面只是简单输出语句,无异常,所以catch不执行,直接进入finally,
try {
//执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容 }
catch { //除非try里面执行代码发生了异常,否则这里的代码不会执行 }
finally { //不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally }
11 对于Java中异常的描述正确的是( D)
用throws定义了方法可能抛出的异常,那么调用此方法时一定会抛出此异常。
如果try块中没有抛出异常,finally块中的语句将不会被执行。
抛出异常意味着程序发生运行时错误,需要调试修改
Java中的可不检测(unchecked)异常可能来自RuntimeException类或其子类。
A错 在调用此方法的时候 也可以再次申明以将异常交由更高一级处理。
B错 finally块中的语句一定会被执行。除非catch块中有System.exit(0)。
C错 抛出异常不一定是运行时异常,也有可能是编译时异常。
D对 运行时异常的特点是Java编译器不会检查它。
Exception(异常)
是程序本身可以处理的异常。主要包含RuntimeException等运行时异常和IOException,SQLException等非运行时异常。
运行时异常 包括:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常(编译异常) 包括:RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常
非运行时异常必须处理的意思是必须try,catch