1. 例外情况
>
终于,程序员想到了标准化和自动化错误处理。这发生在异常被发明的时候。现在异常机制处理了80%的异常情况。
如果某个学者提出例外,那很可能是他或她的博士论文的主题。如果一个程序员想到了它,那么他可能会从同事那里得到一个友好的拍拍:“看起来不错,兄弟。”
当 Java 程序中出现错误时,例如除法0
,会发生一些奇妙的事情:
步骤1
创建一个特殊的异常对象,其中包含有关发生的错误的信息。
Java 中的一切都是对象,异常也不例外🙂Exception 对象有自己的类,唯一区别于普通类的是它们继承了类Throwable
。
第二步
异常对象被“抛出”。也许这里的措辞会更好。“抛出异常”更像是触发火警或发出“DEFCON 1”警报。
当 Java 机器抛出异常时,程序的正常运行停止,“紧急协议”开始。
第三步
抛出异常的方法立即退出。异常被传递给调用方法,该方法也立即退出。依此类推,直到main
方法退出。当main
方法终止时,程序也终止。
例子:
代码 |
控制台输出 |
class Solution
{
public static void main(String[] args)
{
System.out.println("Your attention, please! Preparing for the end of the world");
endTheWorld();
System.out.println("The world ended successfully");
}
public static void endTheWorld()
{
System.out.println("We're doing something important");
doSomeWork(0);
System.out.println("Everything is working well");
}
public static void doSomeWork(int n)
{
System.out.println("Nothing terrible will happen: " + n);
System.out.println(2 / n);
System.out.println("Nothing terrible happened: " + n);
}
}
|
Your attention, please! Preparing for the end of the world
We're doing something important
Nothing terrible will happen: 0
|
第 20 行发生异常:除以 0。Java机器立即创建异常——一个ArithmeticException
对象并将其“抛”给方法。
方法divide()
立即结束,所以我们永远不会看到字符串:Nothing terrible happened: 0。程序返回到方法endTheWorld()
,情况重复:系统中出现未处理的异常,这意味着方法endTheWorld()
也异常终止。然后该main
方法终止,程序停止。
这些例外的目的是什么?那么,您可以编写自己的代码来捕获特定类型的异常,并编写自己的逻辑来处理异常情况。
2.捕捉异常:try-catch
Java 有一个异常捕获机制,可以让你停止这种异常终止的方法。它看起来像这样:
try
{
// Code where an exception might occur
}
catch(ExceptionType name)
{
// Exception handling code
}
这种构造称为try-catch
块。
可能发生异常的代码用大括号括起来,前面有单词try
。
在大括号之后,我们有关键字catch
,括号内是异常变量的声明。其后是花括号,如果发生指定类型的异常,则将要执行的代码包裹起来。
如果在执行“ primary code ”的过程中没有抛出异常,那么catch块里面的代码就不会被执行。如果发生异常,则为(如果抛出异常的类型与括号中变量的类型相同)。
例子:
代码 |
控制台输出 |
class Solution
{
public static void main(String[] args)
{
System.out.println("Hadron Collider launched");
try
{
launchHadronCollider(1);
launchHadronCollider(0);
}
catch(Exception e)
{
System.out.println("Error! Caught an exception");
System.out.println("The planet was sucked into a black hole!");
}
System.out.println("The Hadron Collider stopped");
}
public static void launchHadronCollider(int n)
{
System.out.println("Everything is working well: " + n);
System.out.println(2/n);
System.out.println("There are no problems: " + n);
}
}
|
Hadron Collider launched
Everything is working fine: 1
2
There are no problems: 1
Everything is working fine: 0
Error! Caught an exception
The planet has been sucked into a black hole!
The Hadron Collider is stopped
|
3.多catch
块
理论上,可以在一段代码中抛出各种异常。有些你想用一种方式处理,有些你想用另一种方式处理,还有一些你会决定根本不处理。
Java 开发人员决定帮助您解决问题,让您catch
在一个块之后编写多个块而不是一个块try
。
try
{
// Code where an exception might occur
}
catch (ExceptionType1 name1)
{
// Code for handling ExceptionType1
}
catch (ExceptionType2 name2)
{
// Code for handling ExceptionType2
}
catch (ExceptionType3 name3)
{
// Code for handling ExceptionType3
}
例子:
代码 |
控制台输出 |
class Solution
{
public static void main(String[] args)
{
System.out.println("Start of main method");
try
{
calculate(0);
}
catch (ArithmeticException e)
{
System.out.println("Division by 0");
}
catch(Exception e)
{
System.out.println("Caught some kind of exception");
}
System.out.println("End of main method");
}
public static void calculate(int n)
{
System.out.println("Start of calculate method: " + n);
System.out.println(2/n);
System.out.println("End of calculate method: " + n);
}
}
|
Start of main method
Start of calculate method: 0
Division by 0
End of main method
|
catch
4.块的顺序
块中发生的异常try
只能由单个块捕获catch
。您不能有来自多个块的代码被执行的异常处理情况。catch
但是块的顺序很重要。
您可能会遇到异常可能被多个块捕获的情况。如果是这种情况,那么异常将被最先出现的catch块(最接近该try
块)捕获。
怎么会出现多个catch块都能捕获到同一个异常的情况呢?
所有异常都属于一个单一的继承层次结构——见图表。
ArithmeticException
可以将一个对象分配给一个变量,该变量的类型是ArithmeticException
或其任何祖先类: RuntimeException
,Exception
和Throwable
— 参见图表。
我们将在第 21 关详细讨论继承和祖先类。
这段代码将编译得很好:
继承的好处: |
ArithmeticException ae = new ArithmeticException();
RuntimeException runtime = new ArithmeticException();
Exception exception = new ArithmeticException();
Throwable trwbl = new ArithmeticException();
|
ArithmeticException
所以你可以用上面 4 个块中的任何一个来捕获 an catch
。
示例 1:
代码 |
控制台输出 |
class Solution
{
public static void main(String[] args)
{
System.out.println("Start of main method");
try
{
calculate(0);
}
catch(ArithmeticException e)
{
System.out.println("Division by 0");
}
catch(Exception e)
{
System.out.println("Caught some kind of exception");
}
System.out.println("End of main method");
}
public static void calculate(int n)
{
System.out.println("Start of calculate method: " + n);
System.out.println(2/n);
System.out.println("End of calculate method: " + n);
}
}
|
Start of main method
Start of calculate method: 0
Division by 0
End of main method
|
在这个例子中, the可以被 the和blocksArithmeticException
捕获。它会被距离该区块最近的区块——第一个区块——捕获。catch (Exception e)
catch (ArithmeticException e)
try
catch
为避免意外,最好将catch
几乎可以捕获所有异常的块放在块列表的末尾附近catch
。
该Throwable
类型通常能够捕获 Java 中的所有可能的异常。如果将它放在第一个catch
块中,则代码将无法编译,因为编译器知道存在无法访问的代码块。
GO TO FULL VERSION