企业真题

Java 的异常体系简单介绍下

来源:网?、软??力、上海?冉信息

Java 异常体系

Java异常处理机制

来源:?科软

两种处理方案:try-catch-finallythrows

异常的两种类型,ErrorException 的区别

来源:上海冠?新创、北京中??译、?度

Java 异常体系

运行时异常与一般异常有何异同?

来源:华?思为

运行时异常:RuntimeException

  • 编译可以通过。在运行时可能抛出。出现的概率高一些;一般针对于运行时异常,都不处理。 一般异常:Exception
  • 编译不能通过。要求必须在编译之前,考虑异常的处理。不处理编译不通过。

5. 说几个你常见到的异常

来源:华油??普、百?园、?蝶

异常:

  • 异常:java.lang.Exception,是所有异常的基类,用以描述应用程序希望捕获的情况
  • 运行时异常:java.lang.RuntimeException,是所有 Java 虚拟机正常操作期间可以被抛出的异常的父类
  • 算术异常:ArithmeticExecption,譬如:整数除零
  • 空指针异常:NullPointerException,当试图在要求使用对象的地方使用了 null 时,抛出该异常。譬如:调用 null 对象的实例方法、访问 null 对象的属性、计算 null 对象的长度、使用 throw 语句抛出 null 等等
  • 类型强制转换异常:ClassCastException,也叫类造型异常
  • 数组大小为负值异常:java.lang.NegativeArraySizeException,当使用负数大小值创建数组时抛出该异常
  • 数组下标越界异常:ArrayIndexOutOfBoundsException,当对数组的索引值为负数或大于等于数组大小时抛出
  • 字符串索引越界异常:java.lang.StringIndexOutOfBoundsException,当使用索引值访问某个字符串中的字符,而该索引值小于 0 或大于等于序列大小时,抛出该异常
  • 数组存储异常:java.lang.ArrayStoreException,当向数组中存放非数组声明类型对象时抛出
  • 数字格式异常:java.lang.NumberFormatException,当试图将一个 String 转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常
  • 实例化异常:java.lang.InstantiationException,当试图通过 newInstance() 方法创建某个类的实例,而该类是一个抽象类或接口时,抛出该异常
  • 违法的访问异常:java.lang.IllegalAccessException,当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法,而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常
  • 违法的监控状态异常:java.lang.IllegalMonitorStateException,当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常
  • 违法的状态异常:java.lang.IllegalStateException,当在 Java 环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常
  • 违法的线程状态异常:java.lang.IllegalThreadStateException,当线程尚未处于某个方法的合法调用状态,而调用了该方法时,抛出异常
  • 被中止异常:java.lang.InterruptedException,当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过 Threadinterrupt 方法终止该线程时抛出该异常
  • 违背安全原则异常:SecturityException,由安全管理器抛出,用于指示违反安全情况的异常
  • 输入输出异常:IOException
  • 文件已结束异常:EOFException
  • 文件未找到异常:FileNotFoundException
  • 操作数据库异常:SQLException
  • 枚举常量不存在异常:java.lang.EnumConstantNotPresentException,当应用试图通过名称和枚举类型访问一个枚举对象,但该枚举对象并不包含常量时,抛出该异常
  • 找不到类异常:java.lang.ClassNotFoundException,当应用试图根据字符串形式的类名构造类,而在遍历 CLASSPAH 之后找不到对应名称的 class 文件时,抛出该异常
  • 类型不存在异常:java.lang.TypeNotPresentException
  • 属性不存在异常:java.lang.NoSuchFieldException,当访问某个类的不存在的属性时抛出该异常
  • 方法不存在异常:NoSuchMethodException,当访问某个类的不存在的方法时抛出该异常
  • 不支持克隆异常:java.lang.CloneNotSupportedException,当没有实现 Cloneable 接口或者不支持克隆方法时,调用其 clone() 方法则抛出该异常

错误:

  • 错误:java.lang.Error,是所有错误的基类,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况
  • 抽象方法错误:java.lang.AbstractMethodError,当应用试图调用抽象方法时抛出
  • 断言错误:java.lang.AssertionError,用来指示一个断言失败的情况
  • 类循环依赖错误:java.lang.ClassCircularityError,在初始化一个类时,若检测到类之间循环依赖则抛出该异常
  • 类格式错误:java.lang.ClassFormatError,当 Java 虚拟机试图从一个文件中读取 Java 类,检测到该文件的内容不符合类的有效格式时抛出
  • 初始化程序错误:java.lang.ExceptionInInitializerError,当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的 static 语句段
  • 违法访问错误:java.lang.IllegalAccessError,当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出
  • 不兼容的类变化错误:java.lang.IncompatibleClassChangeError,当正在执行的方法所依赖的类定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误
  • 实例化错误:java.lang.InstantiationError,当一个应用试图通过 Java 的 new 操作符构造一个抽象类或者接口时抛出
  • 内部错误:java.lang.InternalError,用于指示 Java 虚拟机发生了内部错误
  • 链接错误:java.lang.LinkageError,该错误及其所有子类指示某个类依赖于另外一些类,在该类编译之后,被依赖的类改变了其类定义而没有重新编译所有的类,进而引发错误的情况
  • 未找到类定义错误:java.lang.NoClassDefFoundError,当 Java 虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误
  • 域不存在错误:java.lang.NoSuchFieldError,当应用试图访问或者修改某类的某个域,而该类的定义中没有该域的定义时抛出该错误
  • 方法不存在错误:java.lang.NoSuchMethodError,当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误
  • 内存不足错误:java.lang.OutOfMemoryError,当可用内存不足以让 Java 虚拟机分配给一个对象时抛出该错误
  • 堆栈溢出错误:java.lang.StackOverflowError,当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误
  • 线程结束:java.lang.ThreadDeath,当调用 Thread 类的 stop 方法时抛出该错误,用于指示线程结束
  • 未知错误:java.lang.UnknownError,用于指示 Java 虚拟机发生了未知严重错误的情况
  • 未满足的链接错误:java.lang.UnsatisfiedLinkError,当 Java 虚拟机未找到某个类的声明为 native 方法的本机语言定义时抛出
  • 不支持的类版本错误:java.lang.UnsupportedClassVersionError,当 Java 虚拟机试图从读取某个类文件,但是发现该文件的主、次版本号不被当前 Java 虚拟机支持的时候,抛出该错误
  • 验证错误:java.lang.VerifyError,当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误
  • 虚拟机错误:java.lang.VirtualMachineError,用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况

说说 finalfinallyfinalize 的区别

来源:北京中??译、艾?软件、拓?思、?科软

  • final:常量,修饰类、方法、变量各自的含义
  • finallytry-catch-finally 语句
  • finalize:属于 java.lang.Object 上的一个方法,其设计目的是保证对象在被 GC 之前完成特定资源的回收作业(相当于 C++ 的析构函数)。不过由于种种弊端,所以从 JDK 9 开始已经被标记 deprecated
    • 沒法确保 finalize 的执行时间,就算执行了,也不确定是否能符合预期 (扯到 JVM 的 GC 机制)。使用不当还会影响性能,进而导致 dead lock、hanging 等问题

如果不使用 try-catch,程序出现异常会如何?

来源:上海冠?新创科技

一直往上(调用者)抛,抛到 main 还没有被处理就会终止程序的执行。

try-catch 捕捉的是什么错误?

来源:北京亿?东方

Exception,非 Error

如果执行 finally 代码块之前方法返回了结果或者 JVM 退出了,这时 finally 块中的代码还会执行吗?

来源:恒?电子

除了 System.exit(0); 都会执行

try 语句中有 return 语句,最后写 finally 语句,finally 语句中的 code 会不会执行?何时执行?如果执行是在 return 前还是后

来源:拓?思、华??为、?蓝

会执行。return 分两步,

  1. return 的值放到“返回值”寄存器
  2. 弹出函数调用栈,继续执行上一个方法

finally 中的代码在这两步之间执行

catchreturn 一样

throwthrows 的区别?

来源:北京亿??方、北京新?阳光

角度1:“形”,即使用的格式

  • throw:使用在方法内部,“throw 异常类的对象”
  • throws:使用在方法的声明处,“throws 异常类1, 异常类2, …”

角度2:“角色”或作用不同。

上游排污,下游治污。

  • 过程 1:“抛”,throw
  • 过程 2:“抓”,try-catch; throws

子类重写父类抛出异常的方法,能否抛出比父类更高级别的异常类

来源:顺?

不能!

如何自定义一个异常?

来源:?软国际

如何自定义异常类

拓展练习

finally 中代码执行时机

public static void main(String[] args) {
	int test = test(3, 5);
	System.out.println(test);
}
 
public static int test(int x, int y) {
	int result = x;
	try {
		if(x < 0 || y < 0){
			return 0;
		}
		result = x + y;
		return result;
	} finally {
		result = x - y;
	}
}
  • finally 块中的代码是无论 try 中是否发生异常,也无论 catch 是否可以捕获异常,也无论 trycatch 中是否有 return 语句,都会执行的部分
  • 如果 finally 中有 return 语句,那么 try-catch-finally 结构一定从 finally 中的 return 回去
  • 如果 finally 中没有 return 语句,那么 try-catch-finally 结构才会从 trycatch 中的 return 回去

return 分两步:

  1. return 的值放到“返回值”寄存器
  2. 弹出函数调用栈,继续执行上一个方法

finally 中的代码在这两步之间执行

finallyreturn

public class Exercise3 {
	{
		System.out.println("a");
	}
 
	static {
		System.out.println("b");
	}
 
	Exercise3() {
		System.out.println("c");
	}
 
	public static String getOut() {
		try {
			return "1";
		} catch (Exception e) {
			return "2";
		} finally {
			return "3";
		}
	}
 
	public static void main(String[] args) {
		System.out.println(getOut());
	}
}

finallyreturn 执行细节

public class Exercise4 {
	static int i = 0;
 
	public static void main(String[] args) {
		System.out.println(test());
	}
 
	public static int test() {
		try {
			return ++i;
		} finally {
			return ++i;
		}
	}
}

catch 匹配顺序

import java.io.IOException;
 
public class Exercise5 {
	public static void main(String[] args) {
		int a = -1;
		try {
			if (a > 0) {
				throw new RuntimeException("");
			} else if (a < 0) {
				throw new IOException("");
			} else {
				return;
			}
		} catch (IOException ioe) {
			System.out.println("IOException");
		} catch (Throwable e) {
			System.out.println("Throwable");
		} finally {
			System.out.println("finally");
		}
	}
}

catch 是多分支结构,从上到下按顺序匹配,只会进入第一个匹配上的 catch 分支

catch 声明顺序

import java.io.IOException;
 
public class Exercise5 {
	public static void main(String[] args) {
		int a = -1;
		try {
			if (a > 0) {
				throw new RuntimeException("");
			} else if (a < 0) {
				throw new IOException("");
			} else {
				return;
			}
		} catch (Throwable e) {
			System.out.println("Throwable");
		} catch (IOException ioe) {
			System.out.println("IOException");
		} finally {
			System.out.println("finally");
		}
	}
}

catch 如果有“包含”关系,声明从上到下必须是先“特”后“泛”

try-catch-finally 执行顺序

public class Exercise6 {
	public static int fun() {
		int result = 5;
		try {
			result = result / 0;
			return result;
		} catch (Exception e) {
			System.out.println("Exception");
			result = -1;
			return result;
		} finally {
			result = 10;
			System.out.println("I am in finally.");
		}
	}
 
	public static void main(String[] args) {
		int x = fun();
		System.out.println(x);
	}
}

throws

public class Exercise7 {
    public static int aMethod(int i) throws Exception {
        try {
            return 10 / i;
        } catch (Exception ex) {
            throw new Exception("exception in aMethod");
        } finally {
            System.out.println("finally");
        }
    }
 
    public static void main(String[] args) {
        try {
            aMethod(0);
        } catch (Exception e) {
            System.out.println("exception in main");
        }
    }
}