JAVA面试题(十)

72、 try{}里有一个 return 语句,那么紧跟在这个 try 后的finally{}里的 code 会不会被执行,什么时候被执行,在 return前还是后?


        肯定会执行。finally{}块的代码只有在 try{}块中包含遇到 System.exit(0);之类的导致 Java虚拟机直接退出的语句才会不执行。当程序执行 try{}遇到 return 时,程序会先执行 return 语句,但并不会立即返回——也就是把 return 语句要做的一切事情都准备好,也就是在将要返回、但并未返回的时候,程序
把执行流程转去执行 finally 块,当 finally 块执行完成后就直接返回刚才 return 语句已经准备好的结果。
        例如我们有如下程序:

public class Test {
	public static void main(String[] args) {
		System.out.println(new Test().test());
		;
	}

	static int test() {
		int x = 1;
		try {
			return x;
		} finally {
			System.out.println("finally 块执行:" + ++x);
		}
	}
}


        此时的输出结果为:

finally 块执行:2
1


        看到上面程序中 finally 块已经执行了, 而且程序执行 finally 块时已经把 x 变量增加到 2了。但 test()方法返回的依然是 1,这就是由 return 语句执行流程决定的, Java 会把 return 语句先执行完、把所有需要处理的东西都先处理完成,需要返回的值也都准备好之后,但是还未返回之前,程序流程会转去执行 finally 块,但此时 finally 块中的对 x 变量的修改已经不会影响 return 要返回的值了。
        但如果 finally 块里也包含 return 语句,那就另当别论了, 因为 finally 块里的 return 语句也会导致方法返回,例如把程序该为如下形式:

public class Test {
	public static void main(String[] args) {
		System.out.println(new Test().test());
		;
	}

	static int test() {
		int x = 1;
		try {
			return x++;
		} finally {
			System.out.println("finally 块执行:" + ++x);
			return x;
		}
	}
}


此时的输出结果为:

finally 块执行:3
3


        正如介绍的,程序在执行 return x++;时,程序会把 return 语句执行完成,只是等待返回,此时 x 的值已经是 2 了,但程序此处准备的返回值依然是 1。接下来程序流程转去执行 finally块,此时程序会再次对 x 自加,于是 x 变成了 3,而且由于 finally 块中也有 return x;语句,因此程序将会直接由这条语句返回了,因此上面 test()方法将会返回 3。


73、下面的程序代码输出的结果是多少?

public class smallT {
	public static void main(String args[]) {
		smallT t = new smallT();
		int b = t.get();
		System.out.println(b);
	}

	public int get() {
		try {
			return 1;
		} finally {
			return 2;
		}
	}
}


        输出结果是: 2。
        这个程序还是刚才介绍的 return 语句和 finally 块的顺序问题。
        Java 会把 return 语句先执行完、把所有需要处理的东西都先处理完成,需要返回的值也都准备好之后,但是还未返回之前,程序流程会转去执行 finally 块。但如果在执行 finally块时遇到了 return 语句, 程序将会直接使用 finally 块中的 return 语句来返回——因此上面程序将会输出 2。

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


        Checked 异常体现了 Java 的设计哲学:没有完善错误处理的代码根本就不会被执行!
        对于 Checked 异常的处理方式有两种:
        A.当前方法明确知道如何处理该异常,程序应该使用 try...catch 块来捕获该异常,然后在对应的 catch 块中修补该异常。
        B.当前方法不知道如何处理这种异常,应该在定义该方法时声明抛出该异常。
        运行时异常指的就是 RuntimeException 或其子类的实例,运行时异常则更加灵活,编译器不会强制要求程序员必须处理该异常,运行时异常可以既不显式声明抛出,也不使用try...catch 进行捕捉。但如果程序需要捕捉运行时异常,也可以使用 try...catch 块来捕捉运行时异常。
        运行时异常的优点在于灵活:程序员想处理就处理,不想处理直接忽略该异常即可。但
由于编译器不会强制检查运行时异常,因此程序完全有可能在运行时因为这些异常而结束。
常 见 的 运 行 时 异 常 有 NullPointerException 、 ArrayIndexOutOfBoundsException 、
ClassCastException、 ArithmeticException、 IllegalArgumentException 等。
76、 error 和 exception 有什么区别?
        Error 错误,一般是指虚拟机相关的问题,如系统崩溃、虚拟机出错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错
误,因此应用程序不应该试图使用 catch 块来捕获 Error 对象。
        由于编译器会对 Error 进行检查,不会强制要求程序员必须处理 Error,因此 Error 也被归入 unchecked 异常分类中(另外:运行时异常也属于 unchecked 异常)。
        Exception 表示一种设计或实现问题。也就是说,程序员应该对这些情况进行考虑、并提供相应的处理。
77、 Java 中的异常处理机制的简单原理和应用。
        程序运行过程中可能出现各种“非预期”情况,这些非预期情况可能导致程序非正常结
束。为了提高程序的健壮性, Java 提供了异常处理机制:
try
{
    s1...
    s2...
    s3...
}
catch(Exception ex)
{
    // 对异常情况的修复处理
}
        对于上面处理流程,当程序执行 try 块里的 s1、 s2、 s3 遇到异常时, Java 虚拟机将会把这个异常情况封装成异常对象,这个异常对象可以被后面对应的 catch 块捕捉到,这样保证这些异常会得到合适的处理。
        Java 对异常进行了分类,不同类型的异常分别用不同的 Java 类表示,所有异常的根类为 java.lang.Throwable, Throwable 下面又派生了两个子类: Error 和 Exception, Error 错误,一般是指虚拟机相关的问题,如系统崩溃、虚拟机出错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该试图使用 catch 块来捕获 Error 对象。
        Exception 表示一种设计或实现问题。也就是说,程序员应该对这些情况进行考虑、并提供相应的处理。
        异常有可分为 Runtime 异常和 Checked 异常, Checked 异常体现了 Java 的设计哲学:没有完善错误处理的代码根本就不会被执行!对于 Checked 异常的处理方式有两种:
        A.当前方法明确知道如何处理该异常,程序应该使用 try...catch 块来捕获该异常,然
后在对应的 catch 块中修补该异常。
        B.当前方法不知道如何处理这种异常,应该在定义该方法时声明抛出该异常。实际上 Java 的 Checked 异常后来“争议不断”,因为 Checked 异常要求程序员要么显式声明抛出,要么进行捕捉,不能对 Checked 异常不闻不问,这样就给编程带来了一定的复杂度,比如 Spring、 Hibernate 框架的一大特点就是把 Checked 异常包装成了 Runtime 异常。
        Runtime 异常则比较灵活,开发者既可以选择捕获 Runtime 异常,也可以不捕获。


78、请写出你最常见到的 5 个 runtime exception。


        对于一个有 1~2 年左右编程经验的人来说,总会经常遇到一些常见的异常,其中有些就是 Runtime Exception。比如:
        NullPointerException - 当调用一个未初始化的引用变量(实际值为 null)的实例 Field、实例方法时都会引发该异常。
        ArithmeticException - 算术异常。比如 5/0 将引发该异常。
        ArrayIndexOutOfBoundsException:数组索引越界异常。
        ClassCastException:类型转换异常。
        IllegalArgumentException:参数非法的异常。


79、 Java 语言如何进行异常处理,关键字: throws、 throw、try、 catch、 finally 分别代表什么意义?在 try 块中可以抛出异常吗?


        try 块表示程序正常的业务执行代码。如果程序在执行 try 块的代码时出现了“非预期”情况, JVM 将会生成一个异常对象,这个异常对象将会被后面相应的 catch 块捕获。
        catch 块表示一个异常捕获块。当程序执行 try 块引发异常时,这个异常对象将会被后面相应的 catch 块捕获。
        throw 用于手动地抛出异常对象。 throw 后面需要一个异常对象。
        throws 用于在方法签名中声明抛出一个或多个异常类, throws 关键字后可以紧跟一个或多个异常类。
        finally 块代表异常处理流程中总会执行的代码块。
对于一个完整的异常处理流程而言, try 块是必须的, try 块后可以紧跟一个或多个 catch
块,最后还可以带一个 finally 块。 Java 7 引入了自动关闭资源的 try 语句,这种自动关闭资
源的 try 语句可以单独存在。例如如下代码是正确的:
try(
    // 声明、并创建可以被自动关闭的资源
)
{
    // 执行语句
}
        在上面 try 关键字的圆括号内,可用于声明、并创建能被自动关闭的资源,这些能被自动关闭的资源必须实现 Closeable 或 AutoCloseable 接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章