1 javapuzzler 36 一条语句或一个语句块在它抛出了一个异常,或者对某个封闭型语句执行了一个break 或continue,或是象这个程序一样在方法中执行了一个return 时,将发生意外结束。它们之所以被称为意外结束
package arkblue.javapuzzler.n35; public class Indecisive { public static void main(String[] args) { System.out.println(decision()); } static boolean decision() { try { return true; } finally { return false; } } }
打印 false
千万不要用一个return、break、continue 或throw 来退出一个finally 语句块,并且千万不要允许将一个受检查的异常传播到一个finally 语句块之外去。
2 java puzzler 37
package arkblue.javapuzzler.n37; public class Arcane1 { public static void main(String[] args) { try { System.out.println("Hello world"); } catch (IOException e) { System.out.println("I've never seen println fail!"); } } } class Arcane2 { public static void main(String[] args) { try { // If you have nothing nice to say, say nothing } catch (Exception e) { System.out.println("This can't happen"); } } } interface Type1 { void f() throws CloneNotSupportedException; } interface Type2 { void f() throws InterruptedException; } interface Type3 extends Type1, Type2 { } class Arcane3 implements Type3 { public void f() { System.out.println("Hello world"); } public static void main(String[] args) { Type3 t3 = new Arcane3(); t3.f(); } }
(1)如果一个catch 子句要捕获一个类型为E 的被检查异常,而其相对应的try 子句不能抛出E 的某种子类型的异常,那么这就是一个编译期错误。
(2)但是捕获Exception 或Throwble 的catch 子句是合法的,不管与其相对应的try 子句的内容为何
(3)一个方法可以抛出的被检查异常集合是它所适用的所有类型声明要抛出的被检查异常集合的交集,而不是合集
3 java puzzler 38
要确定一个程序是否可以不止一次地对一个空final 进行赋值是一个很困难的问题。事实上,这是不可能的。这等价于经典的停机问题,它通常被认为是不可能解决的[Turing 36]。为了能够编写出一个编译器,语言规范在这一点上采用了保守的方式。在程序中,一个空final 域只有在它是明确未赋过值的地方才可以被赋值。规范长篇大论,对此术语提供了一个准确的但保守的定义[JLS 16]。因为它是保守的,所以编译器必须拒绝某些可以证明是安全的程序。
package arkblue.javapuzzler.n38; public class UnwelcomGuest { public static final long GUEST_USER_ID = -1; private static final long USER_ID; static { try { USER_ID = getUserIdFromEnvironment(); } catch (IdUnavailableException e) { USER_ID = GUEST_USER_ID; System.out.println("Logging in as guest"); } } private static long getUserIdFromEnvironment() throws IdUnavailableException { throw new IdUnavailableException(); } public static void main(String[] args) { System.out.println("User ID: " + USER_ID); } } class IdUnavailableException extends Exception { }
4 java puzzler 40
(1)System.exit 方法将停止当前线程和所有其他当场死亡的线程。finally 子句的出现并不能给予线程继续去执行的特殊权限。
(2)。通过调用System.halt 可以在不执行关闭挂钩的情况下停止VM。
package arkblue.javapuzzler.n39; public class HelloGoodbye { public static void main(String[] args) { try { System.out.println("Hello world"); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.out.println("Hook on shutdown!"); } }); System.exit(0); } finally { System.out.println("Goodbye world"); } } }
5 java puzzler
(1)第一个错误是该程序使用了一种可怕的循环惯用法,该惯用法依赖的是对数组的访问会抛出异常。这种惯用法不仅难以阅读,
而且运行速度还非常地慢。不要使用异常来进行循环控制。
(2)& 操作符有其他的含义。除了常见的被当作整型操作数的位AND 操作符之外,当被用于布尔操作数时,它的功能被重载为逻辑AND 操作符[JLS15.22.2]。这个操作符与更经常被使用的条件AND 操作符有所不同,& 操作符总是要计算它的两个操作数,而 && 操作符在其左边的操作数被计算为false 时,就不再计算右边的操作数了[JLS 15.23]
(3)逻辑OR 操作符(|)也伴随着条件OR 操作符(||)[JLS 15.22.2,15.24]。| 操作符总是要计算它的两个操作数,而 || 操作符在其左边的操作数被计算为true 时,就不再计算右边的操作数了
package arkblue.javapuzzler.n42; public class Loop { public static void main(String[] args) { int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } }; int successCount = 0; try { int i = 0; while (true) { if (thirdElementIsThree(tests[i++])) successCount++; } } catch (ArrayIndexOutOfBoundsException e) { // No more tests to process } System.out.println(successCount); } private static boolean thirdElementIsThree(int[] a) { return a.length >= 3 & a[2] == 3; } }