当前位置:网站首页 > Java中级 > 正文

java面试题大全及答案(归类)(java面试题带答案)



Java异常是Java提供的一种识别及响应错误的一致性机制。 Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序 健壮性。在有效使用异常的情况下,异常能清晰的回答what, where, why这3个问题:

异常类型回答 了“什么”被抛出,异常堆栈跟踪回答了“在哪”抛出,异常信息回答了“为什么”会抛出。 

1. Throwable Throwable 是 Java 语言中所有错误与异常的超类。 Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示发生了异常情 况。 

Throwable 包含了其线程创建时线程执行堆栈的快照,它提供了 printStackTrace() 等接口用于获取 堆栈跟踪数据等信息。

2. Error(错误) 定义:Error 类及其子类。程序中无法处理的错误,表示运行应用程序中出现了严重的错误。 特点:此类错误一般表示代码运行时 JVM 出现问题。通常有 VirtualMachineError(虚拟机运行错 误)、NoClassDefFoundError(类定义错误)等。

比如 OutOfMemoryError:内存不足错误; StackOverflowError:栈溢出错误。此类错误发生时,JVM 将终止线程。 这些错误是不受检异常,非代码性错误。因此,当此类错误发生时,应用程序不应该去处理此类错 误。按照Java惯例,我们是不应该实现任何新的Error子类的! 

3. Exception(异常)程序本身可以捕获并且可以处理的异常。Exception 这种异常又分为两类:运行时异常和编译时异 常。 定义:RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。 特点:Java 编译器不会检查它。

也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws 声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。比如NullPointerException空指针 异常、ArrayIndexOutBoundException数组下标越界异常、ClassCastException类型转换异常、 ArithmeticExecption算术异常。

此类异常属于不受检异常,一般是由程序逻辑错误引起的,在程序中 可以选择捕获处理,也可以不处理。虽然 Java 编译器不会检查运行时异常,但是我们也可以通过 throws 进行声明抛出,也可以通过 try-catch 对它进行捕获处理。如果产生运行时异常,则需要通过 修改代码来进行避免。例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!

RuntimeException 异常会由 Java 虚拟机自动抛出并自动捕获(就算我们没写异常捕获语句运行时也 会抛出错误!!),此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。 定义: Exception 中除 RuntimeException 及其子类之外的异常。

特点: Java 编译器会检查它。如果程序中出现此类异常,比如 ClassNotFoundException(没有找到 指定的类异常),IOException(IO流异常),要么通过throws进行声明抛出,要么通过try-catch进 行捕获处理,否则不能通过编译。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异 常类。该异常我们必须手动在代码里添加捕获语句来处理该异常。

4. 受检异常与非受检异常 Java 的所有异常可以分为受检异常(checked exception)和非受检异常(unchecked exception)。 编译器要求必须处理的异常。正确的程序在运行过程中,经常容易出现的、符合预期的异常情况。一 旦发生此类异常,就必须采用某种方式进行处理。除 RuntimeException 及其子类外,其他的 Exception 异常都属于受检异常。

编译器会检查此类异常,也就是说当编译器检查到应用中的某处可 能会此类异常时,将会提示你处理本异常——要么使用try-catch捕获,要么使用方法签名中用 throws 关键字抛出,否则编译不通过。 编译器不会进行检查并且不要求必须处理的异常,也就说当程序中出现此类异常时,即使我们没有trycatch捕获它,也没有使用throws抛出该异常,编译也会正常通过。该类异常包括运行时异常 (RuntimeException极其子类)和错误(Error)。

• try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异 常时,异常就被抛出。

• catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。 

• finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网 络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停 止。 

• throw – 用于抛出异常。 

• throws – 用在方法签名中,用于声明该方法可能抛出的异常。

Java异常处理

Java 通过面向对象的方法进行异常处理,一旦方法抛出异常,系统自动根据该异常对象寻找合适异常 处理器(Exception Handler)来处理该异常,把各种不同的异常进行分类,并提供了良好的接口。

在Java 中,每个异常都是一个对象,它是 Throwable 类或其子类的实例。当一个方法出现异常后便抛出 一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行 处理。

Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws 和 finally。 在Java应用中,异常的处理机制分为声明异常,抛出异常和捕获异常。 

通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以在 方法签名处使用 throws 关键字声明可能会抛出的异常。 注意 非检查异常(Error、RuntimeException 或它们的子类)不可使用 throws 关键字来声明要抛出的异常。 一个方法出现编译时异常,就需要 try-catch/ throws 处理,否则会导致编译错误。 

如果你觉得解决不了某些异常问题,且不需要调用者处理,那么你可以抛出异常。 throw关键字作用是在方法内部抛出一个Throwable类型的异常。任何Java代码都可以通过throw语句 抛出异常。 

程序通常在运行之前不报错,但是运行后可能会出现某些未知的错误,但是还不想直接抛出到上一 级,那么就需要通过try…catch…的形式进行异常捕获,之后根据不同的异常情况来进行相应的处理。 

直接抛出异常 通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以在 方法签名处使用 throws 关键字声明可能会抛出的异常。 

1 private static void readFile(String filePath) throws IOException { 

2 File file = newFile(filePath); 

3 String result; 

4 BufferedReader reader = newBufferedReader(newFileReader(file)); 

5 while ((result = reader.readLine()) != null) { 

6 System.out.println(result); 

7 } 

8 reader.close(); 

9 } 

封装异常再抛出 有时我们会从 catch 中抛出一个异常,目的是为了改变异常的类型。多用于在多系统集成时,当某个 子系统故障,异常类型可能有多种,可以用统一的异常类型向外暴露,不需暴露太多内部异常细节。 

1 private static void readFile(String filePath)throws MyException { 

2 try{ 

3 // code 

4 }catch(IOException e){ 

5 MyException ex =newMyException("read file failed."); 

6 ex.initCause(e); 

7 throw ex; 

8 } 

9 } 

捕获异常 在一个 try-catch 语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理 

private static void readFile(String filePath){try{// code}catch(FileNotFoundException e){// handle FileNotFoundException}catch(IOException e){// handle IOException}} 

同一个 catch 也可以捕获多种类型异常,用 | 隔开 

privatestaticvoidreadFile(String filePath){try{// code}catch(FileNotFoundException| UnknownHostException e){// handle FileNotFoundException or UnknownHostException}catch(IOException e){// handleIOException}} 

自定义异常 习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函 数(Throwable 的 toString 方法会打印这些详细信息,调试时很有用) publicclassMyExceptionextendsException{publicMyException(){}publicMyException(String msg) {super(msg);}// ...} try-catch-finally 当方法中发生异常,异常处之后的代码不会再执行,如果之前获取了一些本地资源需要释放,则需要 在方法正常结束时和 catch 语句中都调用释放本地资源的代码,显得代码比较繁琐,finally 语句可以 解决这个问题。

 privatestaticvoidreadFile(String filePath)throws MyException { File file =newFile(filePath); String result; BufferedReader reader = null;try{ reader=newBufferedReader(newFileReader(file));while((result = reader.readLine())!=null){ System.out.println(result);}}catch(IOException e){ System.out.println("readFile method catch block."); MyException ex =newMyException("read file failed."); ex.initCause(e);throw ex;}finally{ System.out.println("readFile method finally block.");if(null != reader){try{ reader.close();}catch(IOException e){ e.printStackTrace();}}}} 

调用该方法时,读取文件时若发生异常,代码会进入 catch 代码块,之后进入 finally 代码块;若读取 文件时未发生异常,则会跳过 catch 代码块直接进入 finally 代码块。所以无论代码中是否发生异常, fianlly 中的代码都会执行。 

若 catch 代码块中包含 return 语句,finally 中的代码还会执行吗?将以上代码中的 catch 子句修改如 下:

catch(IOException e){ System.out.println("readFile method catch block.");return;} 

调用 readFile 方法,观察当 catch 子句中调用 return 语句时,finally 子句是否执行 readFile method catch block.readFile method finally block. 可见,即使 catch 中包含了 return 语句,finally 子句依然会执行。

若 finally 中也包含 return 语句, finally 中的 return 会覆盖前面的 return. try-with-resource 上面例子中,finally 中的 close 方法也可能抛出 IOException, 从而覆盖了原始异常。JAVA 7 提供了 更优雅的方式来实现资源的自动释放,自动释放的资源需要是实现了 AutoCloseable 接口的类。 

privatestaticvoidtryWithResourceTest(){try(Scanner scanner =newScanner(newFileInputStream("c:/abc"),"UTF-8")){// code}catch(IOException e){// handle exception}} 

try 代码块退出时,会自动调用 scanner.close 方法,和把 scanner.close 方法放在 finally 代码块中不 同的是,若 scanner.close 抛出异常,则会被抑制,抛出的仍然为原始异常。被抑制的异常会由 addSusppressed 方法添加到原来的异常,如果想要获取被抑制的异常列表,可以调用 getSuppressed 方法来获取。

Error 类型的错误通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错 误进行检测,JAVA 应用程序也不应对这类错误进行捕获,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复; Exception 类的错误是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理, 使应用程序可以继续正常运行。 

运行时异常包括 RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。 Java 编译 器不会检查运行时异常。 受检异常是Exception 中除 RuntimeException 及其子类之外的异常。 Java 编译器会检查受检异常。 RuntimeException异常和受检异常之间的区别:是否强制要求调用者必须处理此异常,如果强制要 求调用者必须进行处理,那么就使用受检异常,否则就选择非受检异常(RuntimeException)。一般来 讲,如果没有特殊的要求,我们建议使用RuntimeException异常。

在一个方法中如果发生异常,这个方法会创建一个异常对象,并转交给 JVM,该异常对象包含异常名 称,异常描述以及异常发生时应用程序的状态。创建异常对象并转交给 JVM 的过程称为抛出异常。可 能有一系列的方法调用,最终才进入抛出异常的方法,这一系列方法调用的有序列表叫做调用栈。 JVM 会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。当 JVM 发 现可以处理异常的代码时,会把发生的异常传递给它。如果 JVM 没有找到可以处理该异常的代码块, JVM 就会将该异常转交给默认的异常处理器(默认处理器为 JVM 的一部分),默认异常处理器打印 出异常信息并终止应用程序。 

Java 中的异常处理除了包括捕获异常和处理异常之外,还包括声明异常和拋出异常,可以通过 throws 关键字在方法上声明该方法要拋出的异常,或者在方法内部通过 throw 拋出异常对象。 throws 关键字和 throw 关键字在使用上的几点区别如下: throw 关键字用在方法内部,只能用于抛出一种异常,用来抛出方法或代码块中的异常,受查异常和非受 查异常都可以被抛出。 throws 关键字用在方法声明上,可以抛出多个异常,用来标识该方法可能抛出的异常列表。一个方法用 throws 标识了可能抛出的异常列表,调用该方法的方法中必须包含可处理异常的代码,否则也要在方法签名 中用 throws 关键字声明相应的异常。

final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量 表示该变量是一个常量不能被重新赋值。 finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码 块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。 finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,Java 中允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

NoClassDefFoundError 是一个 Error 类型的异常,是由 JVM 引起的,不应该尝试捕获这个异常。 引起该异常的原因是 JVM 或 ClassLoader 尝试加载某类时在内存中找不到该类的定义,该动作发生在 运行期间,即编译时该类存在,但是在运行时却找不到了,可能是变异后被删除了等原因导致;ClassNotFoundException 是一个受查异常,需要显式地使用 try-catch 对其进行捕获和处理,或在 方法签名中用 throws 关键字进行声明。当使用 Class.forName, ClassLoader.loadClass 或 ClassLoader.findSystemClass 动态加载类到内存的时候,通过传入的类路径参数没有找到该类,就 会抛出该异常;另一种抛出该异常的可能原因是某个类已经由一个类加载器加载至内存中,另一个加 载器又尝试去加载它。 

答:catch 可以省略 原因 更为严格的说法其实是:try只适合处理运行时异常,try+catch适合处理运行时异常+普通异常。也就 是说,如果你只用try去处理普通异常却不加以catch处理,编译是通不过的,因为编译器硬性规定,普 通异常如果选择捕获,则必须用catch显示声明以便进一步处理。而运行时异常在编译时没有如此规 定,所以catch可以省略,你加上catch编译器也觉得无可厚非。 理论上,编译器看任何代码都不顺眼,都觉得可能有潜在的问题,所以你即使对所有代码加上try,代 码在运行期时也只不过是在正常运行的基础上加一层皮。但是你一旦对一段代码加上try,就等于显示 地承诺编译器,对这段代码可能抛出的异常进行捕获而非向上抛出处理。如果是普通异常,编译器要 求必须用catch捕获以便进一步处理;如果运行时异常,捕获然后丢弃并且+finally扫尾处理,或者加 上catch捕获以便进一步处理。 至于加上finally,则是在不管有没捕获异常,都要进行的“扫尾”处理。 

答:会执行,在 return 前执行。 注意:在 finally 中改变返回值的做法是不好的,因为如果存在 finally 代码块,try中的 return 语句不 会立马返回调用者,而是记录下返回值待 finally 代码块执行完毕之后再向调用者返回其值,然后如果 在 finally 中修改了返回值,就会返回修改后的值。显然,在 finally 中返回或者修改返回值会对程序造 成很大的困扰,C#中直接用编译错误的方式来阻止程序员干这种龌龊的事情,Java 中也可以通过提升 编译器的语法检查级别来产生警告或错误。

代码示例1: publicstaticintgetInt(){int a =10;try{ System.out.println(a /0); a =20;}catch(ArithmeticException e){ a =30;return a;/* * return a 在程序执行到这一步的时候,这里不是return a 而是 return 30;这个返回路径就 形成了 * 但是呢,它发现后面还有finally,所以继续执行finally的内容,a=40 * 再次回到以前的路径,继续 走return 30,形成返回路径之后,这里的a就不是a变量了,而是常量30 */}finally{ a =40;}return a;} 执行结果:30 

代码示例2: publicstaticintgetInt(){int a =10;try{ System.out.println(a /0); a =20;}catch(ArithmeticException e){ a =30;return a;}finally{ a =40;//如果这样,就又重新形成了一条返回路径,由于只能通过1个return返回,所以 这里直接返回40return a;}} 执行结果:40

总是优先捕获最具体的异常类,并将不太具体的 catch 块添加到列表的末尾。 

你可以在下面的代码片断中看到这样一个 try-catch 语句的例子。 第一个 catch 块处理所有 NumberFormatException 异常,第二个处理所有非 NumberFormatException 异常的 IllegalArgumentException 异常。

publicvoidcatchMostSpecificExceptionFirst(){try{doSomething("A message");}catch(NumberFormatException e){ log.error(e);}catch(IllegalArgumentException e){ log.error(e)}} 

Throwable 是所有异常和错误的超类。你可以在 catch 子句中使用它,但是你永远不应该这样做!

到此这篇java面试题大全及答案(归类)(java面试题带答案)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • java技术网站(java技术网站都有哪些)2025-08-30 08:00:05
  • java面试题大全及答案下载 百度网盘(java面试题库及答案)2025-08-30 08:00:05
  • java爬虫入门教程(java爬虫技术从零入门)2025-08-30 08:00:05
  • java面试题大全及答案(java笔试题大全带答案)2025-08-30 08:00:05
  • java技术网站(java新技术网站)2025-08-30 08:00:05
  • java面试题大全及答案下载网盘(java面试题库及答案)2025-08-30 08:00:05
  • java面试题库及答案(java面试题大全带答案pdf版)2025-08-30 08:00:05
  • 华为笔试java编程题(华为java编程规范考试)2025-08-30 08:00:05
  • java面试题大全带答案pdf版(java面试题库及答案)2025-08-30 08:00:05
  • java面试题大全(java面试题大全带答案pdf版)2025-08-30 08:00:05
  • 全屏图片