大佬教程收集整理的这篇文章主要介绍了Java秋招,稳了,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
💂 个人主页: Java程序鱼 🤟 整个Java 体系的面试题我都会分享c;大家可以持续关注 Ὂc; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦。 Ὀ5; 有任何问题欢迎私信,看到会及时回复!
序号@H_674_21@ | 内容@H_674_21@ | 链接地址@H_674_21@ |
---|---|---|
1 | Java基础知识面试题 | https://blog.csdn.net/qq_35620342/article/details/119636436 |
2 | Java集合容器面试题 | 待分享 |
3 | Java并发编程面试题 | 待分享 |
4 | Java异常面试题 | https://blog.csdn.net/qq_35620342/article/details/119977051 |
5 | JVM面试题 | 待分享 |
6 | Java Web面试题 | https://blog.csdn.net/qq_35620342/article/details/119642114 |
7 | Spring面试题 | https://blog.csdn.net/qq_35620342/article/details/119956512 |
8 | Spring MVC面试题 | https://blog.csdn.net/qq_35620342/article/details/119965560 |
9 | Spring Boot面试题 | 待分享 |
10 | @H_174_30@myBatis面试题https://blog.csdn.net/qq_35620342/article/details/119956541 | |
11 | Spring Cloud面试题 | 待分享 |
12 | redis面试题 | https://blog.csdn.net/qq_35620342/article/details/119575020 |
13 | @H_174_30@mySQL数据库面试题https://blog.csdn.net/qq_35620342/article/details/119930887 | |
14 | RabbitMQ面试题 | 待分享 |
15 | Dubbo面试题 | 待分享 |
16 | Linux面试题 | 待分享 |
17 | tomcat面试题 | 待分享 |
18 | ZooKeeper面试题 | 待分享 |
19 | Netty面试题 | 待分享 |
20 | 数据结构与算法面试题 | 待分享 |
Exception 异常主要分为两类
编译器要求必须处理的异常。正确的程序在运行过程中c;经常容易出现的、符合预期的异常情况。一旦发生此类异常c;就必须采用某种方式进行处理。除 RuntimeException 及其子类外c;其他的 Exception 异常都属于受检异常。编译器会检查此类异常c;也就是说当编译器检查到应用中的某处可能会此类异常时c;将会提示你处理本异常——要么使用try-catch捕获c;要么使用方法签名中用 throws 关键字抛出c;否则编译不通过。
编译器不会进行检查并且不要求必须处理的异常c;也就说当程序中出现此类异常时c;即使我们没有try-catch捕获它c;也没有使用throws抛出该异常c;编译也会正常通过。该类异常包括运行时异常(RuntimeException极其子类)和错误(Error)。
(1)try…catch关键字
try/catch代码块中的代码称为保护代码c;使用 try/catch 的语法如下:
try {
// 程序代码
} catch(ExceptionName e1) {
//Catch 块
}
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}
(2) throws/throw 关键字
public class className {
public void deposit(double amount) throws RemoteException {
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
一个方法可以声明抛出多个异常c;多个异常之间用逗号隔开。
(3)finally关键字
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
@H_696_284@8.声明异常
通常c;应该捕获那些知道如何处理的异常c;将不知道如何处理的异常继续传递下去。传递异常可以在方法签名处使用 throws 关键字声明可能会抛出的异常。
注意
如果你觉得解决不了某些异常问题c;且不需要调用者处理c;那么你可以抛出异常。
throw关键字作用是在方法内部抛出一个Throwable
类型的异常。任何Java代码都可以通过throw语句抛出异常。
程序通常在运行之前不报错c;但是运行后可能会出现某些未知的错误c;但是还不想直接抛出到上一级c;那么就需要通过try…catch…的形式进行异常捕获c;之后根据不同的异常情况来进行相应的处理。
@H_696_284@11.常见异常处理方式(1)直接抛出异常
通常c;应该捕获那些知道如何处理的异常c;将不知道如何处理的异常继续传递下去。传递异常可以在方法签名处使用 throws 关键字声明可能会抛出的异常。
private static void readFile(String filePath) throws IOException {
File file = new File(filePath);
String result;
BufferedReader reader = new BufferedReader(new FileReader(file));
while((result = reader.readLine())!=null) {
System.out.println(result);
}
reader.close();
}
(2)封装异常再抛出
有时我们会从 catch 中抛出一个异常c;目的是为了改变异常的类型。多用于在多系统集成时c;当某个子系统故障c;异常类型可能有多种c;可以用统一的异常类型向外暴露c;不需暴露太多内部异常细节。
private static void readFile(String filePath) throws @H_460_366@myException {
try {
} catch (IOException e) {
@H_460_366@myException ex = new @H_460_366@myException("read file failed.");
ex.initCause(e);
throw ex;
}
}
@H_696_284@12.捕获异常
在一个 try-catch 语句块中可以捕获多个异常类型c;并对不同类型的异常做出不同的处理
private static void readFile(String filePath) {
try {
} catch (FileNotFoundException e) {
} catch (IOException e){
}
}
同一个 catch 也可以捕获多种类型异常c;用 | 隔开
private static void readFile(String filePath) {
try {
} catch (FileNotFoundException | UnknownHostException e) {
} catch (IOException e){
}
}
@H_696_284@13.自定义异常
习惯上c;定义一个异常类应包含两个构造函数c;一个无参构造函数和一个带有详细描述信息的构造函数(Throwable 的 toString 方法会打印这些详细信息c;调试时很有用)
public class @H_460_366@myException extends Exception {
public @H_460_366@myException(){ }
public @H_460_366@myException(String msg){
super(@H_637_354@msg);
}
}
@H_696_284@14.try-catch-finally
当方法中发生异常c;异常处之后的代码不会再执行c;如果之前获取了一些本地资源需要释放c;则需要在方法正常结束时和 catch 语句中都调用释放本地资源的代码c;显得代码比较繁琐c;finally 语句可以解决这个问题。
private static void readFile(String filePath) throws @H_460_366@myException {
File file = new File(filePath);
String result;
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
while((result = reader.readLine())!=null) {
System.out.println(result);
}
} catch (IOException e) {
System.out.println("readFile method catch block.");
@H_460_366@myException ex = new @H_460_366@myException("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();
}
}
}
}
调用该方法时c;读取文件时若发生异常c;代码会进入 catch 代码块c;之后进入 finally 代码块;若读取文件时未发生异常c;则会跳过 catch 代码块直接进入 finally 代码块。所以无论代码中是否发生异常c;fianlly 中的代码都会执行。
若 catch 代码块中包含 return 语句c;finally 中的代码还会执行吗?将以上代码中的 catch 子句修改如下:
catch (IOException e) {
System.out.println("readFile method catch block.");
return;
}
调用 readFile 方法c;观察当 catch 子句中调用 return 语句时c;finally 子句是否执行
readFile method catch block.
readFile method finally block.
可见c;即使 catch 中包含了 return 语句c;finally 子句依然会执行。若 finally 中也包含 return 语句c;finally 中的 return 会覆盖前面的 return.
@H_696_284@15.try-with-resource上面例子中c;finally 中的 close 方法也可能抛出 IOException, 从而覆盖了原始异常。JAVA 7 提供了更优雅的方式来实现资源的自动释放c;自动释放的资源需要是实现了 AutoCloseable 接口的类。
private static void tryWithresourceTest(){
try (ScAnner scAnner = new ScAnner(new FileInputStream("c:/abc"),"UTF-8")){
} catch (IOException e){
}
}
try 代码块退出时c;会自动调用 scAnner.close 方法c;和把 scAnner.close 方法放在 finally 代码块中不同的是c;若 scAnner.close 抛出异常c;则会被抑制c;抛出的仍然为原始异常。被抑制的异常会由 addSusppressed 方法添加到原来的异常c;如果想要获取被抑制的异常列表c;可以调用 getSuppressed 方法来获取。
@H_696_284@16.Error 和 Exception 区别是什么?Error类和Exception类的父类都是throwable类c;他们的区别是:
Error类一般是指与虚拟机相关的问题c;如系统崩溃c;虚拟机错误c;内存空间不足c;方法调用栈溢等。对于这类错误的导致的应用程序中断c;仅靠程序本身无法恢复和预防c;遇到这样的错误c;建议让程序终止。
Exception类表示程序可以处理的异常c;可以捕获且可能恢复。遇到这类异常c;应该尽可能处理异常c;使程序恢复运行c;而不应该随意终止异常。
Exception类又分为运行时异常(Runtime Exception)和受检查的异常(checked Exception )c;运行时异常;ArithmaticException,IllegalArgumentexceptionc;编译能通过c;但是一运行就终止了c;程序不会处理运行时异常c;出现这类异常c;程序会终止。而受检查的异常c;要么用try…catch捕获c;要么用throws字句声明抛出c;交给它的父类处理c;否则编译不会通过。
@H_696_284@17.Java 虚拟机是如何捕获异常的?在编译生成的字节码中c;每个方法都附带一个异常表c;异常表中的每一个条目代表一个异常处理器c;并且由 form 指针c;to 指针c;target 指针以及所捕获的异常类型构成。这些指针的值是字节码索引c;用来定位字节码。
from 指针和 to 指针标示了该异常所监控的范围:try 代码块所覆盖的范围。 target 指针标示了异常处理器的起始位置:catch 代码块的起始位置。
当程序处罚异常时c;Java 虚拟机会从上至下遍历异常表中的所有条目。当触发异常的字节码索引值在某个异常表条目的监控范围内c;Java 虚拟机再判断所抛出的异常和该条目想要捕获的异常是否匹配。如果匹配c;Java 虚拟机会将控制流转移至该条目 target 指针指向的字节码。
如果遍历完异常表的条目未曾匹配到异常处理器c;那么它会弹出当前方法对应的 Java 栈帧c;并且在调用者中重复上述操作。
finally 代码块的编译比较复杂。当前版本 Java 编译器的做法:复制 finally 代码块内容c;分别放在 try-catch 代码块所有正常执行路径以及异常执行路径的出口中。
问题:如果 catch 代码块捕获了异常c;并且触发了另一个异常c;那么 finally 捕获并且重抛的异常是 catch 代码块触发的新的异常c;原本的异常就被忽略了。这对代码调试来说c;就不友好了。
Java 7 中引出了 Supressed 异常来解决上面的问题。这个新特性允许开发人员将一个异常附在另一个异常上c;这样抛出的异常就可以附带多个异常的信息。
问答 Q:为什么使用异常捕获的代码比较耗费性能 单从 Java 语法上看不出来c;但是从 JVM 实现的细节上来看就明白了。构造异常实例c;需要生成该异常的栈轨迹。该操作会逐一访问当前线程的栈帧c;记录各种调试信息c;包括类名c;方法名c;触发异常的代码行数等等。
Q:finally 是怎么实现无论异常与否都能执行 编译器在编译代码时会复制 finally 代码块放在 try-catch 代码块所有正常执行路径以及异常执行路径的出口处。
Q:finally 中有 ruturn 语句c;catch 中抛出的异常会被忽略c;为什么 catch 抛出的异常会被 finally 捕获c;执行完 finally 后会重新抛出该异常。由于 finally 中有 return 语句c;在重新抛出异常之前c;代码就已经返回了。
Q:方法的异常表都包含哪些异常 方法的异常表只声明这段代码会被捕获的异常c;而且是非检查异常。如果 catch 中有自定义异常c;那么异常表中也会包含自定义异常的条目。
Q:检查异常和非检查异常也就是其他书籍中说的编译期异常和运行时异常? 检查异常也会在运行过程中抛出。但是它会要求编译器检查代码有没有显式地处理该异常。非检查异常包括Error和RuntimeExceptionc;这两个则不要求编译器显式处理。
@H_696_284@18. throw 和 throws 的区别是什么?Java 中的异常处理除了包括捕获异常和处理异常之外c;还包括声明异常和拋出异常c;可以通过 throws 关键字在方法上声明该方法要拋出的异常c;或者在方法内部通过 throw 拋出异常对象。
throws 关键字和 throw 关键字在使用上的几点区别如下:
final是一种声明属性c;作用与类、方法和变量;final修饰的变量的值不能够再改变c;final修饰的方面不能被覆盖c;final修饰的类不能被继承。
finally是异常处理语句的一部分c;表示总是执行。
finalize是object类的一个子方法c;在垃圾回收器执行是调用回收对象的此方法c;此方法可以被覆盖提供资源回收时的其他资源回收。如文件关闭等。
@H_696_284@20.NoClassDefFoundError 和 ClassnotFoundException 区别?在写Java程序的时候c;当一个类找不到的时候c;JVM有时候会抛出 ClassnotFoundException 异常c;而有时候又会抛出 NoClassDefFoundError。看两个异常的字面意思c;好像都是类找不到c;但是JVM为什么要用两个异常去区分类找不到的情况呢?这个两个异常有什么不同的地方呢?
(1)ClassnotFoundException
ClassnotFoundException 是一个运行时异常。从类继承层次上来看c;ClassnotFoundException 是从 Exception 继承的c;所以 ClassnotFoundException 是一个检查异常。
当应用程序运行的过程中尝试使用类加载器去加载Class文件的时候c;如果没有在 classpath 中查找到指定的类c;就会抛出 ClassnotFoundException 。一般情况下c;当我们使用Class.forName()或ClassLoader.loadClass()或ClassLoader.findSystemClass()在运行时加载类的时候c;如果类没有被找到c;那么就会导致JVM抛出 ClassnotFoundException。
最简单的c;当我们使用JDBC去连接数据库的时候c;我们一般会使用Class.forName()的方式去加载JDBC的驱动c;如果我们没有将驱动放到应用的 classpath 下c;那么会导致运行时找不到类c;所以运行Class.forName()会抛出 ClassnotFoundException。
public class @H_460_366@mainClass {
public static void @H_711_472@main(String[] args) {
try {
Class.forName("Oracle.jdbc.driver.OracleDriver");
} catch (ClassnotFoundException e) {
e.printStackTrace();
}
}
}
输出结果:
$ java MainClass
java.lang.ClassnotFoundException: Oracle.jdbc.driver.OracleDriver
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at MainClass.main(MainClass.java:7)
(2)NoClassDefFoundError
NoClassDefFoundError 异常c;看命名后缀是一个 Error 。从类继承层次上看c;NoClassDefFoundError 是从 Error 继承的。和 ClassnotFoundException 相比c;明显的一个区别是c;NoClassDefFoundError 并不需要应用程序去关心捕获的问题。
当JVM在加载一个类的时候c;如果这个类在编译时是可用的c;但是在运行时找不到这个类的定义的时候c;JVM就会抛出一个 NoClassDefFoundError 错误。比如当我们在 new 一个类的实例的时候c;如果在运行是类找不到c;则会抛出一个 NoClassDefFoundError 的错误。
public class TempClass {
}
public class @H_460_366@mainClass {
public static void @H_711_472@main(String[] args) {
TempClass t = new TempClass();
}
}
输出结果:
$ java MainClass
Exception in thread "main" java.lang.NoClassDefFoundError: TempClass
at MainClass.main(MainClass.java:6)
Caused by: java.lang.ClassnotFoundException: TempClass
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more
(3)总结
ClassnotFoundException@H_674_21@ | NoClassDefFoundError@H_674_21@ |
---|---|
从java.lang.Exception继承c;是Exception类型 | 从java.lang.Error继承c;是Error类型 |
当动态加载Class的时候找不到类会抛出ClassnotFoundException异常 | 当编译成功以后执行过程中Class找不到导致抛出NoClassDefFoundError错误 |
一般在执行Class.forName()、ClassLoader.loadClass()或ClassLoader.findSystemClass()的时候抛出 | 由JVM的运行时抛出 |
答:catch 可以省略
原因
更为严格的说法其实是:try只适合处理运行时异常c;try+catch适合处理运行时异常+普通异常。也就是说c;如果你只用try去处理普通异常却不加以catch处理c;编译是通不过的c;因为编译器硬性规定c;普通异常如果选择捕获c;则必须用catch显示声明以便进一步处理。而运行时异常在编译时没有如此规定c;所以catch可以省略c;你加上catch编译器也觉得无可厚非。
理论上c;编译器看任何代码都不顺眼c;都觉得可能有潜在的问题c;所以你即使对所有代码加上tryc;代码在运行期时也只不过是在正常运行的基础上加一层皮。但是你一旦对一段代码加上tryc;就等于显示地承诺编译器c;对这段代码可能抛出的异常进行捕获而非向上抛出处理。如果是普通异常c;编译器要求必须用catch捕获以便进一步处理;如果运行时异常c;捕获然后丢弃并且+finally扫尾处理c;或者加上catch捕获以便进一步处理。
至于加上finallyc;则是在不管有没捕获异常c;都要进行的“扫尾”处理。
@H_696_284@22.try-catch-finally 中c;如果 catch 中 return 了c;finally 还会执行吗?答:会执行c;在 return 前执行。
注意:在 finally 中改变返回值的做法是不好的c;因为如果存在 finally 代码块c;try中的 return 语句不会立马返回调用者c;而是记录下返回值待 finally 代码块执行完毕之后再向调用者返回其值c;然后如果在 finally 中修改了返回值c;就会返回修改后的值。显然c;在 finally 中返回或者修改返回值会对程序造成很大的困扰c;C#中直接用编译错误的方式来阻止程序员干这种龌龊的事情c;Java 中也可以通过提升编译器的语法检查级别来产生警告或错误。
代码示例1:
public static int geTint() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
}
return a;
}
执行结果:30
代码示例2:
public static int geTint() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
} finally {
a = 40;
return a;
}
}
执行结果:40
@H_696_284@23.类 ExampleA 继承 Exceptionc;类 ExampleB 继承ExampleA有如下代码片断:
try {
throw new ExampleB("b")
} catch(ExampleA e){
System.out.println("ExampleA");
} catch(Exception e){
System.out.println("Exception");
}
请问执行此段代码的输出是什么?
答:
输出:ExampleA。(根据里氏代换原则[能使用父类型的地方一定能使用子类型]c;抓取 ExampleA 类型异常的 catch 块能够抓住 try 块中抛出的 ExampleB 类型的异常)
面试题 - 说出下面代码的运行结果。
class Annoyance extends Exception {
}
class Sneeze extends Annoyance {
}
class Human {
public static void @H_711_472@main(String[] args)
throws Exception {
try {
try {
throw new Sneeze();
} catch ( Annoyance a ) {
System.out.println("Caught Annoyance");
throw a;
}
} catch ( Sneeze s ) {
System.out.println("Caught Sneeze");
return ;
} finally {
System.out.println("hello World!");
}
}
}
结果
Caught Annoyance
Caught Sneeze
Hello World!
@H_696_284@24.常见的 RuntimeException 有哪些?
NullPointerExceptionc;空指针引用异常 ClassCastExceptionc;类型强制转换异常。 IllegalArgumentexceptionc;传递非法参数异常。 ArithmeticExceptionc;算术运算异常 ArrayStoreExceptionc;向数组中存放与声明类型不兼容对象异常 IndexOutOfBoundsExceptionc;下标越界异常 NegativeArraySizeExceptionc;创建一个大小为负数的数组错误异常 numberFormatExceptionc;数字格式异常 SecurityExceptionc;安全异常 UnsupportedoperationExceptionc;不支持的操作异常
@H_696_284@25.Java常见异常有哪些?ArithmeticExecption 算术异常类
NullPointerException 空指针异常类
ClassCastException 类型强制转换异常
NegativeArrayException 数组负下标异常
ArrayIndexOutOfBoundsException 数组下标越界异常
SecturityException 违背安全原则异常
EOFException 文件已结束异常
FileNotFoundException 文件未找到异常
numberFormatException 字符串转换为数字异常
SQLException 操作数据库异常
IOException 输入输出异常
NoSuchMethodException 方法未找到异常
java.lang.AbstractMethodError 抽象方法错误。当应用试图调用抽象方法时抛出。
java.lang.AssertionError 断言错。用来指示一个断言失败的情况。
java.lang.ClassCircularityError 类循环依赖错误。在初始化一个类时c;若检测到类之间循环依赖则抛出该异常。
java.lang.ClassFormatError 类格式错误。当Java虚拟机试图从一个文件中读取Java类c;而检测到该文件的内容不符合类的有效格式时抛出。
java.lang.Error 错误。是所有错误的基类c;用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。
java.lang.ExceptionInInitializerError 初始化程序错误。当执行一个类的静态初始化程序的过程中c;发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。
java.lang.IllegalAccessError 违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法c;但是又违反域或方法的可见性声明c;则抛出该异常。
java.lang.IncompatibleClassChangeError 不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时c;抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下c;容易引发该错误。
java.lang.InstantiationError 实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.
java.lang.InternalError 内部错误。用于指示Java虚拟机发生了内部错误。
java.lang.LinkageError 链接错误。该错误及其所有子类指示某个类依赖于另外一些类c;在该类编译之后c;被依赖的类改变了其类定义而没有重新编译所有的类c;进而引发错误的情况。
java.lang.NoClassDefFoundError 未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类c;而找不到该类的定义时抛出该错误。
java.lang.NoSuchFieldError 域不存在错误。当应用试图访问或者修改某类的某个域c;而该类的定义中没有该域的定义时抛出该错误。
java.lang.NoSuchMethodError 方法不存在错误。当应用试图调用某类的某个方法c;而该类的定义中没有该方法的定义时抛出该错误。
java.lang.outOfMemoryError 内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
java.lang.StackOverflowError 堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。
java.lang.ThreadDeath 线程结束。当调用Thread类的stop方法时抛出该错误c;用于指示线程结束。
java.lang.Unknownerror 未知错误。用于指示Java虚拟机发生了未知严重错误的情况。
java.lang.UnsatisfiedLinkError 未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出。
java.lang.UnsupportedClassversionError 不支持的类版本错误。当Java虚拟机试图从读取某个类文件c;但是发现该文件的主、次版本号不被当前Java虚拟机支持的时候c;抛出该错误。
java.lang.VerifyError 验证错误。当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误。
java.lang.VirtualMachineError 虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况。
java.lang.ArithmeticException 算术条件异常。譬如:整数除零等。
java.lang.ArrayIndexOutOfBoundsException 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
java.lang.ArrayStoreException 数组存储异常。当向数组中存放非数组声明类型对象时抛出。
java.lang.ClassCastException 类造型异常。假设有类A和B(A不是B的父类或子类)c;O是A的实例c;那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。
java.lang.ClassnotFoundException 找不到类异常。当应用试图根据字符串形式的类名构造类c;而在遍历CLASSPAH之后找不到对应名称的class文件时c;抛出该异常。
java.lang.CloneNotSupportedException 不支持克隆异常。当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。
java.lang.EnumConstantNotPresentexception 枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象c;但该枚举对象并不包含常量时c;抛出该异常。
java.lang.Exception 根异常。用以描述应用程序希望捕获的情况。
java.lang.IllegalAccessException 违法的访问异常。当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法c;而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常。
java.lang.IllegalMonitorStateException 违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时c;抛出该异常。
java.lang.IllegalStateException 违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态c;而调用了该方法时c;抛出该异常。
java.lang.IllegalThreadStateException 违法的线程状态异常。当县城尚未处于某个方法的合法调用状态c;而调用了该方法时c;抛出异常。
java.lang.IndexOutOfBoundsException 索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时c;抛出该异常。
java.lang.InstantiationException 实例化异常。当试图通过newInstance()方法创建某个类的实例c;而该类是一个抽象类或接口时c;抛出该异常。
java.lang.InterruptedException 被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态c;而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。
java.lang.NegativeArraySizeException 数组大小为负值异常。当使用负数大小值创建数组时抛出该异常。
java.lang.NoSuchFieldException 属性不存在异常。当访问某个类的不存在的属性时抛出该异常。
java.lang.NoSuchMethodException 方法不存在异常。当访问某个类的不存在的方法时抛出该异常。
java.lang.NullPointerException 空指针异常。当应用试图在要求使用对象的地方使用了null时c;抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。
java.lang.numberFormatException 数字格式异常。当试图将一个String转换为指定的数字类型c;而该字符串确不满足数字类型要求的格式时c;抛出该异常。
java.lang.RuntimeException 运行时异常。是所有Java虚拟机正常操作期间可以被抛出的异常的父类。
java.lang.SecurityException 安全异常。由安全管理器抛出c;用于指示违反安全情况的异常。
java.lang.StringIndexOutOfBoundsException 字符串索引越界异常。当使用索引值访问某个字符串中的字符c;而该索引值小于0或大于等于序列大小时c;抛出该异常。
java.lang.TypeNotPresentexception 类型不存在异常。当应用试图以某个类型名称的字符串表达方式访问该类型c;但是根据给定的名称又找不到该类型是抛出该异常。该异常与ClassnotFoundException的区别在于该异常是unchecked(不被检查)异常c;而ClassnotFoundException是checked(被检查)异常。
java.lang.UnsupportedoperationException 不支持的方法异常。指明请求的方法不被支持情况的异常。
@H_696_284@26.在 finally 块中清理资源或者使用 try-with-resource 语句当使用类似InputStream这种需要使用后关闭的资源时c;一个常见的错误就是在try块的最后关闭资源。
public void doNotCloseresourceInTry() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
inputStream.close();
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
问题就是c;只有没有异常抛出的时候c;这段代码才可以正常工作。try 代码块内代码会正常执行c;并且资源可以正常关闭。但是c;使用 try 代码块是有原因的c;一般调用一个或多个可能抛出异常的方法c;而且c;你自己也可能会抛出一个异常c;这意味着代码可能不会执行到 try 代码块的最后部分。结果就是c;你并没有关闭资源。
所以c;你应该把清理工作的代码放到 finally 里去c;或者使用 try-with-resource 特性。
@H_696_284@27.使用 finally 代码块与前面几行 try 代码块不同c;finally 代码块总是会被执行。不管 try 代码块成功执行之后还是你在 catch 代码块中处理完异常后都会执行。因此c;你可以确保你清理了所有打开的资源。
public void closeresourceInFinally() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
log.error(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e);
}
}
}
}
@H_696_284@28.Java 7 的 try-with-resource 语法
如果你的资源实现了 AutoCloseable 接口c;你可以使用这个语法。大多数的 Java 标准资源都继承了这个接口。当你在 try 子句中打开资源c;资源会在 try 代码块执行后或异常处理后自动关闭。
public void automaticallyCloseresource() {
File file = new File("./tmp.txt");
try (FileInputStream inputStream = new FileInputStream(file);) {
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
@H_696_284@29.优先明确的异常
你抛出的异常越明确越好c;永远记住c;你的同事或者几个月之后的你c;将会调用你的方法并且处理异常。
因此需要保证提供给他们尽可能多的信息。这样你的 API 更容易被理解。你的方法的调用者能够更好的处理异常并且避免额外的检查。
因此c;总是尝试寻找最适合你的异常事件的类c;例如c;抛出一个 numberFormatException 来替换一个 IllegalArgumentexception 。避免抛出一个不明确的异常。
public void doNotDoThis() throws Exception {
...
}
public void doThis() throws numberFormatException {
...
}
@H_696_284@30.对异常进行文档说明
当在方法上声明抛出异常时c;也需要进行文档说明。目的是为了给调用者提供尽可能多的信息c;从而可以更好地避免或处理异常。 在 Javadoc 添加 @throws 声明c;并且描述抛出异常的场景。
public void doSomething(String input) throws @H_460_366@myBusinessException {
...
}
@H_696_284@31.使用描述性消息抛出异常
在抛出异常时c;需要尽可能精确地描述问题和相关信息c;这样无论是打印到日志中还是在监控工具中c;都能够更容易被人阅读c;从而可以更好地定位具体错误信息、错误的严重程度等。
但这里并不是说要对错误信息长篇大论c;因为本来 Exception 的类名就能够反映错误的原因c;因此只需要用一到两句话描述即可。
如果抛出一个特定的异常c;它的类名很可能已经描述了这种错误。所以c;你不需要提供很多额外的信息。一个很好的例子是 numberFormatException 。当你以错误的格式提供 String 时c;它将被 java.lang.Long 类的构造函数抛出。
try {
new Long("xyz");
} catch (numberFormatException e) {
log.error(e);
}
@H_696_284@32.优先捕获最具体的异常
大多数 IDE 都可以帮助你实现这个最佳实践。当你尝试首先捕获较不具体的异常时c;它们会报告无法访问的代码块。
但问题在于c;只有匹配异常的第一个 catch 块会被执行。 因此c;如果首先捕获 IllegalArgumentexception c;则永远不会到达应该处理更具体的 numberFormatException 的 catch 块c;因为它是 IllegalArgumentexception 的子类。
总是优先捕获最具体的异常类c;并将不太具体的 catch 块添加到列表的末尾。
你可以在下面的代码片断中看到这样一个 try-catch 语句的例子。 第一个 catch 块处理所有 numberFormatException 异常c;第二个处理所有非 numberFormatException 异常的IllegalArgumentexception 异常。
public void catchMostSpecificExceptionFirst() {
try {
doSomething("A message");
} catch (numberFormatException e) {
log.error(e);
} catch (IllegalArgumentexception e) {
log.error(e)
}
}
@H_696_284@33.不要捕获 Throwable 类
Throwable 是所有异常和错误的超类。你可以在 catch 子句中使用它c;但是你永远不应该这样做!
如果在 catch 子句中使用 Throwable c;它不仅会捕获所有异常c;也将捕获所有的错误。JVM 抛出错误c;指出不应该由应用程序处理的严重问题。 典型的例子是 OutOfMemoryError 或者 StackOverflowError 。两者都是由应用程序控制之外的情况引起的c;无法处理。
所以c;最好不要捕获 Throwable c;除非你确定自己处于一种特殊的情况下能够处理错误。
public void doNotCatchThrowable() {
try {
} catch (Throwable t) {
}
}
@H_696_284@34.不要忽略异常
很多时候c;开发者很有自信不会抛出异常c;因此写了一个catch块c;但是没有做任何处理或者记录日志。
public void doNotIgnoreExceptions() {
try {
} catch (numberFormatException e) {
}
}
但现实是经常会出现无法预料的异常c;或者无法确定这里的代码未来是不是会改动(删除了阻止异常抛出的代码)c;而此时由于异常被捕获c;使得无法拿到足够的错误信息来定位问题。
合理的做法是至少要记录异常的信息。
public void logAnException() {
try {
} catch (numberFormatException e) {
log.error("This should never happen: " + e);
}
}
@H_696_284@35.不要记录并抛出异常
这可能是本文中最常被忽略的最佳实践。可以发现很多代码甚至类库中都会有捕获异常、记录日志并再次抛出的逻辑。如下:
try {
new Long("xyz");
} catch (numberFormatException e) {
log.error(e);
throw e;
}
这个处理逻辑看着是合理的。但这经常会给同一个异常输出多条日志。如下:
17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.numberFormatException: For input String: "xyz"
Exception in thread "main" java.lang.numberFormatException: For input String: "xyz"
at java.lang.numberFormatException.forInputString(numberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.(Long.java:965)
at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)
如上所示c;后面的日志也没有附加更有用的信息。如果想要提供更加有用的信息c;那么可以将异常包装为自定义异常。
public void wrapException(String input) throws @H_460_366@myBusinessException {
try {
} catch (numberFormatException e) {
throw new @H_460_366@myBusinessException("A message that describes the error.", e);
}
}
因此c;仅仅当想要处理异常时才去捕获c;否则只需要在方法签名中声明让调用者去处理。
@H_696_284@36.包装异常时不要抛弃原始的异常捕获标准异常并包装为自定义异常是一个很常见的做法。这样可以添加更为具体的异常信息并能够做针对的异常处理。 在你这样做时c;请确保将原始异常设置为原因(注:参考下方代码 numberFormatException e 中的原始异常 e )。Exception 类提供了特殊的构造函数方法c;它接受一个 Throwable 作为参数。否则c;你将会丢失堆栈跟踪和原始异常的消息c;这将会使分析导致异常的异常事件变得困难。
public void wrapException(String input) throws @H_460_366@myBusinessException {
try {
} catch (numberFormatException e) {
throw new @H_460_366@myBusinessException("A message that describes the error.", e);
}
}
@H_696_284@37.不要使用异常控制程序的流程
不应该使用异常控制应用的执行流程c;例如c;本应该使用if语句进行条件判断的情况下c;你却使用异常处理c;这是非常不好的习惯c;会严重影响应用的性能。
@H_696_284@38.使用标准异常如果使用内建的异常可以解决问题c;就不要定义自己的异常。Java API 提供了上百种针对不同情况的异常类型c;在开发中首先尽可能使用 Java API 提供的异常c;如果标准的异常不能满足你的要求c;这时候创建自己的定制异常。尽可能得使用标准异常有利于新加入的开发者看懂项目代码。
@H_696_284@39.异常会影响性能异常处理的性能成本非常高c;每个 Java 程序员在开发时都应牢记这句话。创建一个异常非常慢c;抛出一个异常又会消耗1~5msc;当一个异常在应用的多个层级之间传递时c;会拖累整个应用的性能。
尽管使用异常有利于 Java 开发c;但是在应用中最好不要捕获太多的调用栈c;因为在很多情况下都不需要打印调用栈就知道哪里出错了。因此c;异常消息应该提供恰到好处的信息。
@H_696_284@40.总结综上所述c;当你抛出或捕获异常的时候c;有很多不同的情况需要考虑c;而且大部分事情都是为了改善代码的可读性或者 API 的可用性。
异常不仅仅是一个错误控制机制c;也是一个通信媒介。因此c;为了和同事更好的合作c;一个团队必须要制定出一个最佳实践和规则c;只有这样c;团队成员才能理解这些通用概念c;同时在工作中使用它。
@H_696_284@41.异常处理-阿里巴巴Java开发手册1.【强制】Java 类库中定义的可以通过预检查方式规避的RuntimeException异常不应该通过catch 的方式来处理c;比如:NullPointerExceptionc;IndexOutOfBoundsException等等。 说明:无法通过预检查的异常除外c;比如c;在解析字符串形式的数字时c;可能存在数字格式错误c;不得不通过catch numberFormatException来实现。 正例:if (obj != null) {…} 反例:try { obj.method(); } catch (NullPointerException E) {…}
2.【强制】异常不要用来做流程控制c;条件控制。 说明:异常设计的初衷是解决程序运行中的各种意外情况c;且异常的处理效率比条件判断方式要低很多。
3.【强制】catch时请分清稳定代码和非稳定代码c;稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型c;再做对应的异常处理。 说明:对大段代码进行try-catchc;使程序无法根据不同的异常做出正确的应激反应c;也不利于定位问题c;这是一种不负责任的表现。 正例:用户注册的场景中c;如果用户输入非法字符c;或用户名称已存在c;或用户输入密码过于简单c;在程序上作出分门别类的判断c;并提示给用户。
4.【强制】捕获异常是为了处理它c;不要捕获了却什么都不处理而抛弃之c;如果不想处理它c;请将该异常抛给它的调用者。最外层的业务使用者c;必须处理异常c;将其转化为用户可以理解的内容。
5.【强制】有try块放到了事务代码中c;catch异常后c;如果需要回滚事务c;一定要注意手动回滚事务。
6.【强制】finally块必须对资源对象、流对象进行关闭c;有异常也要做try-catch。 说明:如果JDK7及以上c;可以使用try-with-resources方式。
7.【强制】不要在finally块中使用return。 说明:try块中的return语句执行成功后c;并不马上返回c;而是继续执行finally块中的语句c;如果此处存在return语句c;则在此直接返回c;无情丢弃掉try块中的返回点。 反例:
private int x = 0;
public int checkReturn() {
try {
return ++x;
} finally {
return ++x;
}
}
8.【强制】捕获异常与抛异常c;必须是完全匹配c;或者捕获异常是抛异常的父类。 说明:如果预期对方抛的是绣球c;实际接到的是铅球c;就会产生意外情况。
9.【强制】在调用RPC、二方包、或动态生成类的相关方法时c;捕捉异常必须使用Throwable类来进行拦截。 说明:通过反射机制来调用方法c;如果找不到方法c;抛出NoSuchMethodException。什么情况会抛出NoSuchMethodError呢?二方包在类冲突时c;仲裁机制可能导致引入非预期的版本使类的方法签名不匹配c;或者在字节码修改框架(比如:ASM)动态创建或修改类时c;修改了相应的方法签名。这些情况c;即使代码编译期是正确的c;但在代码运行期时c;会抛出NoSuchMethodError。
10.【推荐】方法的返回值可以为nullc;不强制返回空集合c;或者空对象等c;必须添加注释充分说明什么情况下会返回null值。 说明:本手册明确防止NPE是调用者的责任。即使被调用方法返回空集合或者空对象c;对调用者来说c;也并非高枕无忧c;必须考虑到远程调用失败、序列化失败、运行时异常等场景返回null的情况。
11.【推荐】防止NPEc;是程序员的基本修养c;注意NPE产生的场景: 1) 返回类型为基本数据类型c;return包装数据类型的对象时c;自动拆箱有可能产生NPE。 反例:public int f() { return Integer对象}c; 如果为nullc;自动解箱抛NPE。 2) 数据库的查询结果可能为null。 3) 集合里的元素即使isnotEmptyc;取出的数据元素也可能为null。 4) 远程调用返回对象时c;一律要求进行空指针判断c;防止NPE。 5) 对于Session中获取的数据c;建议进行NPE检查c;避免空指针。 6) 级联调用obj.getA().getB().getC();一连串调用c;易产生NPE。 正例:使用JDK8的Optional类来防止NPE问题。
12.【推荐】定义时区分unchecked / checked 异常c;避免直接抛出new RuntimeException()c;更不允许抛出Exception或者Throwablec;应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常c;如:DAOException / serviceException等。
13.【参考】对于公司外的http/api开放接口必须使用“错误码”;而应用内部推荐异常抛出;跨应用间RPC调用优先考虑使用Result方式c;封装issuccess()方法、“错误码”、“错误简短信息”。 说明:关于RPC方法返回方式使用Result方式的理由: 1)使用抛异常返回方式c;调用方如果没有捕获到就会产生运行时错误。 2)如果不加栈信息c;只是new自定义异常c;加入自己的理解的error messagec;对于调用端解决问题的帮助不会太多。如果加了栈信息c;在频繁调用出错的情况下c;数据序列化和传输的性能损耗也是问题。
14.【参考】避免出现重复的代码(Don’t Repeat Yourself)c;即DRY原则。 说明:随意复制和粘贴代码c;必然会导致代码的重复c;在以后需要修改时c;需要修改所有的副本c;容易遗漏。必要时抽取共性方法c;或者抽象公共类c;甚至是组件化。 正例:一个类中有多个public方法c;都需要进行数行相同的参数校验操作c;这个时候请抽取:
private Boolean checkParam(DTO dto) {…}
以上是大佬教程为你收集整理的Java秋招,稳了全部内容,希望文章能够帮你解决Java秋招,稳了所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。