java中throw和try的区别(catch的几种情况的后续代码会不会执行)
java中throw和try的区别(catch的几种情况的后续代码会不会执行)在parse处Alt Enter,选择Surround with try/catch,代码变为: 我们用try…catch: 在parse处Alt Enter,选择Add exception to method signature,会自动在main后面添加throws ParseException。代码变为:import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class MyException { public static void main(String[] args) throws ParseException { SimpleDateFormat sdf=new SimpleDateFormat("yyyy
背景
下面均以ParseException(解析异常)为例叙述。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyException {
public static void main(String[] args){
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2021-0829");
System.out.println("执行后续代码...");
}
}
这种情况下,那么 parse() 会报错,因为这里要防止ParseException,它属于编译异常,必须用throws或者try…catch解决。
方式一:throws我们这里先用throws:
在parse处Alt Enter,选择Add exception to method signature,会自动在main后面添加throws ParseException。代码变为:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyException {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2021-0829");
System.out.println("执行后续代码...");
}
}
用throws这样写,就是把异常交给JVM(java虚拟机)处理。这样做的缺点是会造成:
控制台直接显示异常信息,并终止了程序,返回退出码1,表示不正常退出。请注意,这样后面的代码将不会执行。
方式二:try…catch我们用try…catch:
在parse处Alt Enter,选择Surround with try/catch,代码变为:
public class MyException {
public static void main(String[] args) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse("2021-0829");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("执行后续代码...");
}
这样的话,显示了异常,后面的代码也还会执行,返回退出码0,表示正常退出。
既然有了这两种方式处理异常,我们再来看看几种变体:
变体一:自定义方法,均用throws
如果可能会异常的代码在自定义方法里,(两个throws都不能少)例如:
public class MyException {
public static void main(String[] args) throws ParseException{
method();
System.out.println("执行后续main代码...");
}
public static void method() throws ParseException {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2021-0829");
System.out.println("执行后续method代码...");
}
}
运行结果如下,分析一下,这个异常是在进入method()执行到Date这一行的时候,抛出的异常。
method自己处理不了而终止,然后throws交给方法的调用者,也就是传给main函数处理。
但是main函数也是throws,同样处理不了而终止,最后交给虚拟机处理。
虚拟机处理的方式就是显示异常并终止程序,然后Date这一行下面的任务全部被终止,退出码1,非正常退出。
结果不管是method方法里面的sout,还是回到main()的sout,均未执行。
变体二:自定义方法,均用try…catch
其实不用都用try…catch,如果都用,那么会有重复现象,只能删掉main函数里面的try…catch。
那么实际上就只有一个try…catch了:
public class MyException {
public static void main(String[] args) {
method();
System.out.println("执行后续main代码...");
}
public static void method() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse("2021-0829");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("执行后续method代码...");
}
}
这种情况是什么结果呢,在method方法中,自己处理异常后,执行catch{}里面的代码,打印出异常信息。
并继续执行了method的后续代码,然后返回main,又执行了main的后续代码,退出码0,正常退出。
所以这种方式, 两个后续代码均能执行,从代码上很容易知道是哪的问题,但是从输出上,很难看出来。
变体三:自定义方法,main中throws,method中try…catch
此时代码如下:
public class MyException {
public static void main(String[] args) throws ParseException{
method();
System.out.println("执行后续main代码...");
}
public static void method() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse("2021-0829");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("执行后续method代码...");
}
}
这种情况的结果,步骤基本上同变体二,在method方法中,自己处理异常后,打印了异常输出,执行了method后续代码,然后返回main。
注意,method方法并没有把异常转给main处理,而是自己处理,(相当于儿子做错了事情,并没有告诉父亲)。
所以main中的throws并没有捕获到异常,然后执行main后续代码,最终退出码0,正常退出,但是两个后续代码均能执行,同样不容易发现是哪部分的问题。
再次思考,上面这个异常信息是method里面的try…catch还是main里面的throws?
答案肯定是method里面的try…catch。
不信的话我们把method方法里的e.printStackTrace();替换为System.out.println(e); 再来看看结果:
变体四:自定义方法,main中try…catch,method中throws
这个变体就有意思了,代码如下:
public class MyException {
public static void main(String[] args){
try {
method();
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("执行后续main代码...");
}
public static void method() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2021-0829");
//后续代码
System.out.println("执行后续method代码...");
}
}
这种情况,method里面出现了异常被throws捕获,自己处理不了导致method自身被终止。
传给给main处理,然后主函数的try…catch再来处理异常,打印异常信息,随后继续执行了main的后续代码,退出码0,程序正常退出。
(相当于儿子闯了祸进了局子,自己做不了事情了,然后父亲得知,替儿子收拾烂摊子,然后能做其他事)
好就好在,哪部分有问题,哪部分的后续代码就不继续执行了,这样问题就很明显了,所以推荐这种。
这里注意,这个异常是主函数打印出来的,不信我们把主函数的e.printStackTrace();替换为System.out.println(e); 然后再来看看结果:
总结:上述讨论都是以ParseException为例,它是编译异常,是编译时程序出现的问题,必须用throws或者try…catch解决。
1. 如果用throws,那么会把异常交给方法的调用者处理(自己不处理,专门转给别人处理),那你转我也转,最终最终就交给java虚拟机处理,然后就是终止程序,后续代码不执行。
2. 如果用try…catch就是自己处理,不交给java虚拟机,后续代码也会执行。
所以工作中,我们一般采用变体四,即儿子闯祸向上抛(throws),交给最外层的父亲用try…catch处理,这样既能知道问题所在(儿子的后续动作都没执行,很容易看出来问题),又能执行main的后续代码,又能正常退出,何乐而不为呢!