精华内容
下载资源
问答
  • (2)异步请求需要捕获错误 // 首先这是一嵌套回调的例子 http.get('http://www.baidu.com', function (res) { console.log(res) http.get('http://www.baidu.com', function (res) { console.log...

    首先例举一个嵌套回调的例子

    该例子的缺点是

    (1)层层嵌套,可读性差

    (2)每一个异步请求都需要捕获错误

    // 首先这个是一个嵌套回调的例子
    http.get('http://www.baidu.com', function (res) {
        console.log(res)
    
        http.get('http://www.baidu.com', function (res) {
            console.log(res)
    
            http.get('http://www.baidu.com', function (res) {
                console.log(res)
            }).on('error', function (err) {
                console.error('some error3')
            })
        }).on('error', function (err) {
            console.error('some error2')
        })
    }).on('error', function (err) {
        console.error('some error1')
    })

     利用一个try catch来捕获多个await 产生的错误

    var http = require('http')
    var co = require('co')
    
    // 先将 get 函数封装成返回 Promise 对象的函数
    var get = function (url) {
        return new Promise(function (resolve, reject) {
            http.get(url, function (res) {
                resolve(res)
            }).on('error', function (err) {
                reject(err)
            })
        })
    }
    
    async function gen () {
        try {
            var r1 = await get('http://www.baidu.com')
            console.log(r1)
            var r2 = await get('http://www.baidu.com')
            console.log(r2)
            var r3 = await get('http://www.baidu.com')
            console.log(r3)
        } catch (err) {
            // 捕获异步请求的错误统一处理
            console.log(err)
        }
    }
    

     

    展开全文
  • 正文本篇文章主要是通过举例的方式来阐述各种情况,我这里根据 try-catch-finally 语法块分为两种大情况讨论:try-catch 语法块和 try-catch-finally 语句块,然后再在种情况再去具体讨论。一、try-...

    前言

    之前在刷笔试题和面试的时候经常会遇到或者被问到 try-catch-finally 语法块的执行顺序等问题,今天就抽空整理了一下这个知识点,然后记录下来。

    正文

    本篇文章主要是通过举例的方式来阐述各种情况,我这里根据 try-catch-finally 语法块分为两种大情况讨论:try-catch 语法块和 try-catch-finally 语句块,然后再在每种情况里再去具体讨论。

    一、try-catch 语句块

    我们可以看看下面程序:

    public static void main(String[] args) {

    System.out.println(handleException0());

    }

    /**

    * try,catch都有return

    * @return

    */

    private static String handleException0() {

    try{

    System.out.println("try开始");

    String s = null;

    int length = s.charAt(0);

    System.out.println("try结束");

    return "try块的返回值";

    }catch (Exception e){

    System.out.println("捕获到了异常");

    return "catch的返回值";

    }

    }

    执行结果:

    try开始

    捕获到了异常

    catch的返回值

    分析:程序首先执行 try 块里面的代码,try 块里面发现有异常,try 块后面的代码不会执行(自然也不会return),然后进入匹配异常的那个 catch 块,然后进入 catch 块里面将代码执行完毕,当执行到 catch 里面的return 语句的时候,程序中止,然后将此 return 的最终结果返回回去。

    二、try-catch-finally 语句块

    这种语法块我分为了 4 种情况讨论,下面进行一一列举。

    1、第一种情况,try 块里面有 return 的情况,并且捕获到异常

    例1:

    public static void main(String[] args) {

    String result = handleException1();

    System.out.println(result);

    }

    private static String handleException1() {

    try{

    System.out.println("try开始");

    String str = null;

    int length = str.length();

    System.out.println("try结束");

    }catch (Exception e){

    System.out.println("捕获到了异常");

    }finally {

    System.out.println("finally块执行完毕了");

    }

    return "最终的结果";

    }

    例1执行的结果如下:

    try开始

    捕获到了异常

    finally块执行完毕了

    最终的结果

    例2:

    public static void main(String[] args) {

    String result = handleException2();

    System.out.println(result);

    }

    private static String handleException2() {

    try{

    System.out.println("try开始");

    String str = null;

    int length = str.length();

    System.out.println("try结束");

    return "try块的返回值";

    }catch (Exception e){

    System.out.println("捕获到了异常");

    }finally {

    System.out.println("finally块执行完毕了");

    }

    return "最终的结果";

    }

    例2的执行结果如下:

    try开始

    捕获到了异常

    finally块执行完毕了

    最终的结果

    分析:首先 例1 和 例2 的结果是很显然的,当遇到异常的时候,直接进入匹配到相对应的 catch 块,然后继续执行 finallly 语句块,最后将 return 结果返回回去。

    第二种情况:try块里面有return的情况,但是不会捕获到异常

    例3:

    思考:下面代码try语句块中有return语句,那么是否执行完try语句块就直接return退出方法了呢?

    public static void main(String[] args) {

    String result = handleException3();

    System.out.println(result);

    }

    private static String handleException3() {

    try{

    System.out.println("");

    return "try块的返回值";

    }catch (Exception e){

    System.out.println("捕获到了异常");

    }finally {

    System.out.println("finally块执行完毕了");

    }

    return "最终的结果";

    }

    例3的执行结果如下:

    finally块执行完毕了

    try块的返回值

    分析:例3的结果其实我们可以通过打断点的方式去看看程序的具体执行流程,通过打断点我们可以发现,代码先执行 try块 里的代码,当执行到 return 语句的时候,handleException3方法并没有立刻结束,而是继续执行finally块里的代码,finally块里的代码执行完后,紧接着回到 try 块的 return 语句,再把最终结果返回回去, handleException 方法执行完毕。

    第三种情况:try块和finally里面都有return的情况

    例4:

    public static void main(String[] args) {

    System.out.println(handleException4());

    }

    /**

    * 情况3:try和finally中均有return

    * @return

    */

    private static String handleException4() {

    try{

    System.out.println("");

    return "try块的返回值";

    }catch (Exception e){

    System.out.println("捕获到了异常");

    }finally {

    System.out.println("finally块执行完毕了");

    return "finally的返回值";

    }

    // return "最终的结果";//不能再有返回值

    }

    例4的执行结果:

    finally块执行完毕了

    finally的返回值

    分析:需要注意的是,当 try 块和 finally 里面都有 return 的时候,在 try/catch/finally 语法块之外不允许再有return 关键字。我们还是通过在程序中打断点的方式来看看代码的具体执行流程。代码首先执行 try 块 里的代码,当执行到 return 语句的时候,handleException4 方法并没有立刻结束,而是继续执行 finally 块里的代码,当发现 finally 块里有 return 的时候,直接将 finally 里的返回值(也就是最终结果)返回回去, handleException4 方法执行完毕。

    第四种情况:try块,catch块,finally块都有return

    例5:

    public static void main(String[] args) {

    System.out.println(handleException5());

    }

    /**

    * 情况4:try,catch,finally都有return

    * @return

    */

    private static String handleException5() {

    try{

    System.out.println("try开始");

    int[] array = {1, 2, 3};

    int i = array[10];

    System.out.println("try结束");

    return "try块的返回值";

    }catch (Exception e){

    e.printStackTrace();//这行代码其实就是打印输出异常的具体信息

    System.out.println("捕获到了异常");

    return "catch的返回值";

    }finally {

    System.out.println("finally块执行完毕了");

    return "finally的返回值";

    }

    // return "最终的结果";

    }

    例5的执行结果:

    try开始

    捕获到了异常

    finally块执行完毕了

    finally的返回值

    java.lang.ArrayIndexOutOfBoundsException: 10

    at com.example.javabasic.javabasic.ExceptionAndError.TryCatchFinally.handleException5(TryCatchFinally.java:25)

    at com.example.javabasic.javabasic.ExceptionAndError.TryCatchFinally.main(TryCatchFinally.java:14)

    分析:程序首先执行try块里面的代码,try块里面发现有异常,try块后面的代码不会执行(自然也不会return),然后进入匹配异常的那个catch块,然后进入catch块里面将代码执行完毕,当执行到catch里面的return语句的时候,程序不会马上终止,而是继续执行finally块的代码,最后执行finally里面的return,然后将此return的最终结果返回回去。

    总结

    其实,我们通过以上例子我们可以发现,不管return关键字在哪,finally一定会执行完毕。理论上来说try、catch、finally块中都允许书写return关键字,但是执行优先级较低的块中的return关键字定义的返回值将覆盖执行优先级较高的块中return关键字定义的返回值。也就是说finally块中定义的返回值将会覆盖catch块、try块中定义的返回值;catch块中定义的返回值将会覆盖try块中定义的返回值。

    再换句话说如果在finally块中通过return关键字定义了返回值,那么之前所有通过return关键字定义的返回值都将失效——因为finally块中的代码一定是会执行的。

    公众号:良许Linux

    有收获?希望老铁们来个三连击,给更多的人看到这篇文章

    展开全文
  • 我在app的代码里有一些for循环里面有try – catch语句,担心循环里一直执行try – catch语句会影响效率,所以在网上查询了资料,后来发现并不影响性能。这里记录一下。1、JAVA性能调优-将try/catch块移出循环据说把...

    释放双眼,带上耳机,听听看~!

    今天,简单讲讲android里使用try–catch语句是否会影响性能。

    我在app的代码里有一些for循环里面有try – catch语句,担心循环里一直执行try – catch语句会影响效率,所以在网上查询了资料,后来发现并不影响性能。这里记录一下。

    1、JAVA性能调优-将try/catch块移出循环

    据说把try/catch块放入循环体内,会极大的影响性能。因为使用了try/catch模块的使用,会让JAVA虚拟机做很多额外的工作。就好比对每个人说,“嗨,哥们,路上可能有蛇。于是听到的人只好手拿木棍,小心翼翼的往前走”。

    把try/catch块放到循环外面,就好比对一大群人说,“嗨,兄弟们,路上可能有蛇。于是听到的人安排部分人员拿木棍往前走,其他人基本不受影响”

    这个理论蛮不错的,测试下对性能的实际影响

    2、将try/catch块在循环条件进行比对的源代码

    package com.java.test;

    import java.util.ArrayList;

    import java.util.List;

    /**

    * 使用预热模式 JVM参数:-XX:PrintCompilation

    * 目标:测试在循环中使用try/catch对性能的影响

    *

    */

    public class EasyTryCatchTest {

    ListaList = new ArrayList();

    public staticvoid main(String[] args) throws Exception {

    intwarmUpCycles = 10000000; // 预热次数

    inttestCycles = 50000000; // 正式执行次数

    EasyTryCatchTestse = new EasyTryCatchTest();

    System.out.println("...预热循环开始 ...");

    longcatchTime = se.runCatchLoop(warmUpCycles);

    longnotcatchTime = se.runCatchNotLoop(warmUpCycles);

    System.out.println("...预热结束");

    System.out.println("...预热阶段,try/catch在循环中耗时: " + catchTime);

    System.out.println("...预热阶段,try/catch不在循环中耗时: " + notcatchTime);

    System.out.println("...进入正式循环 ...");

    catchTime =se.runCatchLoop(testCycles);

    notcatchTime= se.runCatchNotLoop(testCycles);

    System.out.println("...正式运行阶段,try/catch在循环中耗时: " + catchTime);

    System.out.println("...正式运行阶段,try/catch不在循环中耗时: " + notcatchTime);

    }

    publicEasyTryCatchTest(){

    aList.add("0");

    }

    // try / catch 在具体的循环体(内圈 循环 )中

    private longrunCatchLoop(int iterations) {

    // 开始计时

    longstartTime = System.nanoTime();

    for (intloop = 0; loop < iterations; loop++) {

    try {

    Stringtemp = aList.get(0);

    } catch(Exception e) {}

    }

    // 计时完成

    longelapsedTime = System.nanoTime();

    return(elapsedTime - startTime);

    }

    // try / catch 在不在具体的循环体(内圈 循环 )中

    public longrunCatchNotLoop(int iterations) {

    // 开始计时

    longstartTime = System.nanoTime();

    try {

    for (intloop = 0; loop < iterations; loop++) {

    Stringtemp = aList.get(0);

    }

    } catch(Exception e) {}

    // 计时完成

    longelapsedTime = System.nanoTime();

    return(elapsedTime - startTime);

    }

    }

    3、运行结果

    …预热循环开始 …

    …预热结束

    …预热阶段,try/catch在循环中耗时: 76507316

    …预热阶段,try/catch不在循环中耗时: 76292613

    …进入正式循环 …

    …正式运行阶段,try/catch在循环中耗时: 389151690

    …正式运行阶段,try/catch不在循环中耗时: 389874615

    4、结论

    从测试结果来看,可能我们的JDK(1.6)会自动优化字节码的缘故,因此try/catch是否在循环中,对整体性能的影响几乎微乎其微,389151690 389874615 差距非常的小。

    以上是没有发生异常的情况,如果发生异常,那么也就无法比较了。

    这里再举一个例子:

    讨论的问题

    当时讨论的是这样的问题:

    比较下面两种try catch写法,哪一种性能更好。

    for (int i = 0; i < 1000000; i++) {

    try {

    Math.sin(j);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    try {

    for (int i = 0; i < 1000000; i++) {

    Math.sin(j);

    }

    } catch (Exception e) {

    e.printStackTrace();

    }

    结论

    在没有发生异常时,两者性能上没有差异。如果发生异常,两者的处理逻辑不一样,已经不具有比较的意义了。

    分析

    要知道这两者的区别,最好的办法就是查看编译后生成的Java字节码。看一下try catch到底做了什么。

    下面是我的测试代码

    import org.openjdk.jmh.annotations.Benchmark;

    /**

    * Created by kevin on 16-7-10.

    */

    public class ForTryAndTryFor {

    public static void main(String[] args) {

    tryFor();

    forTry();

    }

    public static void tryFor() {

    int j = 3;

    try {

    for (int i = 0; i < 1000; i++) {

    Math.sin(j);

    }

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    public static void forTry() {

    int j = 3;

    for (int i = 0; i < 1000; i++) {

    try {

    Math.sin(j);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    }

    使用javap -c fileName.class输出对应的字节码

    Compiled from "ForTryAndTryFor.java"

    public class com.kevin.java.performancetTest.ForTryAndTryFor {

    public com.kevin.java.performancetTest.ForTryAndTryFor();

    Code:

    0: aload_0

    1: invokespecial #1 // Method java/lang/Object."":()V

    4: return

    public static void main(java.lang.String[]);

    Code:

    0: invokestatic #2 // Method tryFor:()V

    3: invokestatic #3 // Method forTry:()V

    6: return

    public static void tryFor();

    Code:

    0: iconst_3

    1: istore_0

    2: iconst_0

    3: istore_1

    4: iload_1

    5: sipush 1000

    8: if_icmpge 23

    11: iload_0

    12: i2d

    13: invokestatic #4 // Method java/lang/Math.sin:(D)D

    16: pop2

    17: iinc 1, 1

    20: goto 4

    23: goto 31

    26: astore_1

    27: aload_1

    28: invokevirtual #6 // Method java/lang/Exception.printStackTrace:()V

    31: return

    Exception table:

    from to target type

    2 23 26 Class java/lang/Exception

    public static void forTry();

    Code:

    0: iconst_3

    1: istore_0

    2: iconst_0

    3: istore_1

    4: iload_1

    5: sipush 1000

    8: if_icmpge 31

    11: iload_0

    12: i2d

    13: invokestatic #4 // Method java/lang/Math.sin:(D)D

    16: pop2

    17: goto 25

    20: astore_2

    21: aload_2

    22: invokevirtual #6 // Method java/lang/Exception.printStackTrace:()V

    25: iinc 1, 1

    28: goto 4

    31: return

    Exception table:

    from to target type

    11 17 20 Class java/lang/Exception

    }

    指令含义不是本文的重点,所以这里就不介绍具体的含义,感兴趣可以到Oracle官网查看相应指令的含义The Java Virtual

    Machine Instruction Set

    好了让我们来关注一下try catch 到底做了什么。我们就拿forTry方法来说吧,从输出看,字节码分两部分,code(指令)和exception table(异常表)两部分。当将java源码编译成相应的字节码的时候,如果方法内有try catch异常处理,就会产生与该方法相关联的异常表,也就是Exception table:部分。异常表记录的是try

    起点和终点,catch方法体所在的位置,以及声明捕获的异常种类。通过这些信息,当程序出现异常时,java虚拟机就会查找方法对应的异常表,如果发现有声明的异常与抛出的异常类型匹配就会跳转到catch处执行相应的逻辑,如果没有匹配成功,就会回到上层调用方法中继续查找,如此反复,一直到异常被处理为止,或者停止进程。具体介绍可以看这篇文章How

    the Java virtual machine handles exceptions

    所以,try 在反映到字节码上的就是产生一张异常表,只有发生异常时才会被使用。由此得到出开始的结论。

    这里再对结论扩充:

    try catch与未使用try catch代码区别在于,前者禁止try语句块中的代码进行优化,例如重排序,try catch里面的代码是不会被编译器优化重排的。对于上面两个函数而言,只是异常表中try起点和终点位置不一样。至于刚刚说到的指令重排的问题,由于for循环条件部分符合happens- before原则,因此两者的for循环都不会发生重排。当然只是针对这里而言,在实际编程中,还是提倡try

    catch范围尽量小,这样才可以充分发挥java编译器的优化能力。

    至于网上得出的for-try比try-catch要快是由于cpu执行代码时可能有环境的影响因素,因为手机可能同时执行其他线程,所以测试的时间不准确。具体来说:

    原因至少有下面这些:System.currentTimeMillis()测量的只是逝去的时间,并没有反映出cpu执行该函数真正消耗的时间。

    这导致线程未被分配cpu资源时,等待cpu的时间也会被计算进去

    JIT优化导致结果出现偏差。

    像这种多次循环非常容易触发JIT的优化机制,关于JIT,这里简短的介绍一下

    在Java编程语言和环境中,即时编译器(JIT compiler,just-in-time compiler)是一个把Java的字节码(包括需要被解释的指令的程序)转换成可以直接发送给处理器的指令的程序。当你写好一个Java程序后,源语言的语句将由Java编译器编译成字节码,而不是编译成与某个特定的处理器硬件平台对应的指令代码(比如,Intel的Pentium微处理器或IBM的System/390处理器)。字节码是可以发送给任何平台并且能在那个平台上运行的独立于平台的代码。

    简单来说,JIT会将某些符合条件(比如,频繁的循环)的字节码被编译成目标的机器指令直接执行,从而加快执行速度。可以通过配置-XX:+PrintCompilation参数,观察JIT。当JIT执行优化时,会在终端输出相应的优化信息。

    类加载时间也被统计进来了。

    类首次被使用时,会触发类加载,产生了时间消耗。

    由上面的分析不难看出为什么绝大多数时候tryFor会比forTry快了,JIT编译耗时和类加载时间会被统计到第一个执行的函数forTry里面。要验证这个也非常简单,把两个函数的调用顺序互换,然后再进行测试。

    当然,还有一点不能忽略的是System.currentTimeMillis()并不是统计cpu真正执行时间,所以可能测试的结果会有出入。可以使用JProfiler配合Intellij IDEA进行测试,下面会提到。由于这些因素影响着测试结果,从而使得测试结果扑朔迷离

    所以总结一下,在没有异常时,try-catch不影响性能,当发生异常时,才会有多余的消耗。

    android try catch并不影响性能就讲完了。

    就这么简单。

    展开全文
  • Java中关于try…catch…finally异常处理的细节辨析什么时候执行finally;...首先需要明确几点:try语句块中的代码应是可能出现异常的代码,可能会抛出一个或多个异常,因此,try后面可跟一个或多个catch如果异常...

    Java中关于try…catch…finally异常处理的细节辨析

    什么时候执行finally; finally后面的语句执行吗; try…catch…finally块中的finally语句是不是一定会被执行; Java中finally与return的执行顺序详解;

    首先需要明确几点:

    try语句块中的代码应是可能出现异常的代码,可能会抛出一个或多个异常,因此,try后面可跟一个或多个catch

    如果异常间关系不大,则catch的顺序可以随意。但如果异常间有父类子类继承关系,则必须将子类异常catch放置在父类异常catch前面,以防止一场直接被父类catch接住,没有输出我们想要的具体子类异常信息

    如果try中没有出现异常,则catch不被执行。但不管catch接没接住,try有没有异常,只要有finally,则都会执行finally(general情况,其他情况详见后)。

    finally后面的语句是否执行与try或catch中有无return有关

    这篇博客耗的时间比较长,我仔细验证了几个猜测。现在记录下来。

    整篇文章较长,阅读大约需要8min

    finally后面的语句什么时候执行?

    还是先看一个例子:

    public class TestFinally {

    public static void main(String[] args){

    try{

    return;

    }

    finally{

    System.out.println("Finally");

    }

    }

    }

    输出:

    Finally

    可以看出:当try中无异常发生,finally仍执行

    如果去除return更换为其它普通语句

    public class TestFinally {

    public static void main(String[] args){

    try{

    int a=3;

    a+=5;

    System.out.println(a);

    }

    finally{

    System.out.println("Finally");

    }

    int b=5;

    b+=5;

    System.out.println(b);

    }

    }

    输出:

    Finally

    可以看出:finally后面语句正常执行

    如果try中加入return,不能编译,提示

    int b=5;

    b+=5;

    System.out.println(b);

    这部分代码是unreachable code

    得证如果try中有return,则finally后面的代码不会执行(for ‘catch’ is the same thing)

    附上一些证明栗子,可以跳过

    例1

    public class TestFinally {

    public static void a() throws Exception{

    try{

    throw new Exception();

    }

    catch(Exception e){

    System.out.println("exception000");

    }

    finally{

    System.out.println("finally111");

    }

    }

    public static void main(String[] args){

    try{

    a();

    }

    catch(Exception e){

    System.out.println("exception");

    }

    System.out.println("finished");

    }

    }

    输出:

    exception000

    finally111

    finished

    异常在方法中被接住,main中catch不会执行,catch后的代码正常执行

    删去exception000项后

    public class TestFinally {

    public static void a() throws Exception{

    try{

    throw new Exception();

    }

    /catch(Exception e){

    System.out.println("exception000");

    }/

    finally{

    System.out.println("finally111");

    }

    }

    public static void main(String[] args){

    try{

    a();

    }

    catch(Exception e){

    System.out.println("exception");

    }

    System.out.println("finished");

    }

    }

    输出:

    finally111

    exception

    finished

    异常方法中没被接住,但在main中被接住,catch后代码正常执行

    删去finally111项后

    package trycatchfinally;

    public class TestFinally {

    public static void a() throws Exception{

    try{

    throw new Exception();

    }

    catch(Exception e){

    System.out.println("exception000");

    }

    /finally{

    System.out.println("finally111");

    }/

    }

    public static void main(String[] args){

    try{

    a();

    }

    catch(Exception e){

    System.out.println("exception");

    }

    System.out.println("finished");

    }

    }

    输出:

    exception000

    finished

    finally被注释,故不执行,异常被方法中的catch接住,main中catch后代码正常执行

    例2

    public class TestFinally {

    public static String output="";

    public static void a(int i){

    try{

    if(i==1){

    throw new Exception();

    }

    output+="1";

    }

    catch(Exception e){

    output+="2";

    return;

    }

    finally{output+="3";}

    output+="4";

    }

    public static void main(String[] args){

    a(0);

    a(1);

    System.out.println(TestFinally.output);

    }

    }

    输出:

    13423

    可以看出,catch中有return,则finally后面的代码不会执行

    去掉return后

    package trycatchfinally;

    public class TestFinally {

    public static String output="";

    public static void a(int i){

    try{

    if(i==1){

    throw new Exception();

    }

    output+="1";

    }

    catch(Exception e){

    output+="2";

    //return;

    }

    finally{output+="3";}

    output+="4";

    }

    public static void main(String[] args){

    a(0);

    a(1);

    System.out.println(TestFinally.output);

    }

    }

    输出:

    1234234

    finally后代码执行,得证。

    什么时候finally执行?什么时候不执行?

    经过搜索,找到一位前辈的博客,她写到至少两种情况下finally是出现但不执行的

    try语句没有被执行到,如在try语句之前就返回了,这样finally语句就不会执行,这也说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。

    在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。

    接下来的内容就比较深入细节了,没有这方面了解的需求可直接略过

    现在我们已经知道finally后面的语句执行与try/catch中有无return有关,但finally块本身执行是在return的前面还是后面还是什么时候?

    一个我比较认同的结论:

    finally块的语句在try或catch中的return语句执行之后返回之前执行且finally里的修改语句可能影响也可能不影响try或catch中 return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回

    要想明白这个问题,需要一些背景知识:

    java方法是在栈帧中执行,栈帧是线程私有栈的单位,执行方法的线程会为每一个方法分配一小块栈空间来作为该方法执行时的内存空间,栈帧分为三个区域:

    操作数栈,用来保存正在执行的表达式中的操作数,数据结构中学习过基于栈的多项式求值算法,操作数栈的作用和这个一样

    局部变量区,用来保存方法中使用的变量,包括方法参数,方法内部声明的变量,以及方法中使用到的对象的成员变量或类的成员变量(静态变量),最后两种变量会复制到局部变量区,因此在多线程 环境下,这种变量需要根据需要声明为volatile类型

    字节码指令区,这个不用解释了,就是方法中的代码翻译成的指令

    return语句:

    return语句的格式如下:

    return [expression];

    其中expression(表达式)是可选的,因为有些方法没有返回值,所以return后面也就没有表达式,或者可以看做是空的表达式。

    我们知道return语句的作用可以结束方法并返回一个值,那么他返回的是哪里的值呢?返回的是return指令执行的时刻,操作数栈顶的值,不管expression是一个怎样的表达式,究竟做了些什么工作,对于return指令来说都不重要,他只负责把操作数栈顶的值返回。

    而return expression是分成两部分执行的:

    执行:expression;

    执行:return指令;

    例如:return x+y;

    这句代码先执行x+y,再执行return;首先执行将x以及y从局部变量区复制到操作数栈顶的指令,然后执行加法指令,这个时候结果x+y的值会保存在操作数栈的栈顶,最后执行return指令,返回操作数栈顶的值。

    对于return x;先执行x,x也是一个表达式,这个表达式只有一个操作数,会执行将变量x从局部变量区复制到操作数栈顶的指令,然后执行return,返回操作数栈顶的值。

    因此return x实际返回的是return指令执行时,x在操作数栈顶的一个快照或者叫副本,而不是x这个值。

    finally语句在return语句执行之后还是之前执行?

    栗子1:

    public class TestFinally {

    public static void main(String[] args) {

    System.out.println(test1());

    }

    public static int test1() {

    int b = 20;

    try {

    System.out.println("try");

    return b += 80;

    }

    catch (Exception e) {

    System.out.println("catch");

    }

    finally {

    System.out.println("finally");

    if (b > 25) {

    System.out.println("b>25, b = " + b);

    }

    }

    return b;

    }

    }

    输出:

    try

    finally

    b>25, b = 100

    100

    说明return语句已经执行了再去执行finally语句,不过并没有直接返回,而是等finally语句执行完了再返回结果。即:finally语句在return语句执行之后return返回之前执行的。

    再来一个栗子2:

    public class TestFinally {

    public static void main(String[] args) {

    System.out.println(test11());

    }

    public static String test11() {

    try {

    System.out.println("try");

    return test12();

    } finally {

    System.out.println("finally");

    }

    }

    public static String test12() {

    System.out.println("return statement");

    return "after return";

    }

    }

    输出:

    try

    return statement

    finally

    after return

    如果finally里也有return语句,那么是不是就直接返回了,try中的return就不能返回了?

    public class TestFinally {

    public static void main(String[] args) {

    System.out.println(test2());

    }

    public static int test2() {

    int b = 20;

    try {

    System.out.println("try");

    return b += 80;

    } catch (Exception e) {

    System.out.println("catch");

    } finally {

    System.out.println("finally");

    if (b > 25) {

    System.out.println("b>25, b = " + b);

    }

    return 200;

    }

    // return b;

    }

    }

    输出:

    try

    finally

    b>25, b = 100

    200

    说明finally里的return直接返回了,就不管try中是否还有返回语句,这里还有个小细节需要注意,finally里加上return过后,finally外面的return b就变成不可到达语句了,也就是永远不能被执行到,所以需要注释掉否则编译器报错。即finally块中的return语句会覆盖try块中的return返回。

    如果finally中没有return,会如何返回?

    try{

    return expression;

    }finally{

    do some work;

    }

    首先我们知道,finally语句是一定会执行,但他们的执行顺序是怎么样的呢?他们的执行顺序如下:

    1.执行:expression,计算该表达式,结果保存在操作数栈顶;

    2.执行:操作数栈顶值(expression的结果)复制到局部变量区作为返回值;

    3.执行:finally语句块中的代码;

    4.执行:将第2步复制到局部变量区的返回值又复制回操作数栈顶;

    5.执行:return指令,返回操作数栈顶的值;

    我们可以看到,在第一步执行完毕后,整个方法的返回值就已经确定了,由于还要执行finally代码块,因此程序会将返回值暂存在局部变量区,腾出操作数栈用来执行finally语句块中代码,等finally执行完毕,再将暂存的返回值又复制回操作数栈顶。所以无论finally语句块中执行了什么操作,都无法影响返回值,所以试图在finally语句块中修改返回值是徒劳的。因此,finally语句块设计出来的目的只是为了让方法执行一些重要的收尾工作,而不是用来计算返回值的。

    但我前面刚说finally里的return直接返回了,就不管try中是否还有返回语句,都不管try直接返回了,这是不是矛盾呢?

    并不是。仔细阅读刚才的代码,可以看到,执行return后面的表达式,但值并没有立即返回,会转去执行finally,然后再返回刚才没有返回的值。如果finally里面返回了一个常值如return 200,这时才会直接返回,不管之前要返回的值。

    如果finally里没有return语句,但修改了b的值,那么try中return返回的是修改后的值还是原值?

    public class TestFinally {

    public static void main(String[] args) {

    System.out.println(test3());

    }

    public static int test3() {

    int b = 20;

    try {

    System.out.println("try");

    return b += 80;

    } catch (Exception e) {

    System.out.println("catch");

    } finally {

    System.out.println("finally");

    if (b > 25) {

    System.out.println("b>25, b = " + b);

    }

    b = 150;

    }

    return 2000;

    }

    }

    输出:

    try

    finally

    b>25, b = 100

    100

    如果return使用在基本数据变量上,则finally中对改基本数据变量的修改不会生效!如果作用的是对象如Integer包装类或者其他正常对象如`Map

    每次返回的一定是try中的return语句?那么finally后面的return语句(如果有)永远不会执行?

    try块里的return语句在异常的情况下不会被执行,这样具体返回哪个看情况

    public class TestFinally {

    public static void main(String[] args) {

    System.out.println(test4());

    }

    public static int test4() {

    int b = 20;

    try {

    System.out.println("try");

    b = b / 0;

    return b += 80;

    } catch (Exception e) {

    b += 15;

    System.out.println("catch");

    } finally {

    System.out.println("finally");

    if (b > 25) {

    System.out.println("b>25, b = " + b);

    }

    b += 50;

    }

    return 26;

    }

    }

    输出:

    try

    catch

    finally

    b>25, b = 35

    26

    这里因为在return之前发生了除0异常,所以try中的return不会被执行到,而是接着执行捕获异常的catch 语句和最终的finally语句,此时两者对b的修改都影响了最终的返回值,这时return b;就起到作用了。当然如果将return b改为return 300什么的,最后返回的就是300。

    如果catch中有return,则执行情况与未发生异常时try中return的执行情况完全一样。

    public class TestFinally {

    public static void main(String[] args) {

    System.out.println(test5());

    }

    public static int test5() {

    int b = 20;

    try {

    System.out.println("try");

    b = b /0;

    return b += 80;

    } catch (Exception e) {

    System.out.println("catch");

    return b += 15;

    } finally {

    System.out.println("finally");

    if (b > 25) {

    System.out.println("b>25, b = " + b);

    }

    b += 50;

    }

    //return b;

    //Unreachable code

    }

    }

    输出:

    try

    catch

    finally

    b>25, b = 35

    35

    说明了发生异常后,catch中的return语句先执行,确定了返回值后再去执行finally块,执行完了catch再返回,finally里对b的改变对返回值无影响,原因同前面一样,也就是说情况与try中的return语句执行完全一样。

    如果想输出85,需要这么改,即finally中return,覆盖catch中的try。

    public class TestFinally {

    public static void main(String[] args) {

    System.out.println(test5());

    }

    public static int test5() {

    int b = 20;

    try {

    System.out.println("try block");

    b = b /0;

    return b += 80;

    } catch (Exception e) {

    System.out.println("catch block");

    return b += 15;

    } finally {

    System.out.println("finally block");

    if (b > 25) {

    System.out.println("b>25, b = " + b);

    }

    b += 50;

    return b;

    }

    //return b;

    }

    }

    输出:

    try block

    catch block

    finally block

    b>25, b = 35

    85

    至此,此篇结束。关于这块的问题相信我已经明白了二三事,希望看到这的你也有收获 :)

    展开全文
  • Java异常之catch语句块

    2021-03-10 07:07:07
    今天在阅读项目代码时看到如下奇怪的代码,以为是竖线 | 可以作为类型赋值,经过网上搜索才知道是Java SE 7新增的功能:一个catch捕获多种类型的异常。原文是Java官方的文档,现翻译如下。红字为个人备注。public ...
  • try catch中的catch里写什么

    千次阅读 2021-02-25 10:15:29
    如果没有写异常处理代码,程序遇到异常就会停止。 而写了异常处理,程序会跳过这错误,继续执行。...但异常种,我们很难记住是什么类型的异常,一般情况下按 Ctrl+Alt+t 会生成异常处理代码
  • 我在PHP代码中使用了try..catch块,但我不确定是否正确使用了它们。例如,我的一些代码如下:try {$tableAresults = $dbHandler->doSomethingWithTableA();...} catch (Exception $e) {retur...
  • 异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。...这样做如下的弊端:(1)易混淆:例如函数返回-1代表出现异常,但是如果函数确实要返回-1这正确的...
  • php try catch捕获错误

    2021-04-26 21:48:14
    本文实例讲述了php中try catch捕获异常。分享给大家供大家参考。具体方法分析如下:php中try catch可以帮助我们捕获程序代码的异常了,这样我们可以很好的处理一些不必要的错误了,感兴趣的朋友可以一起来看看。PHP...
  • 对于Checked异常,java程序要么声明抛出,要么使用try……catch进行捕获。1.1 正确关闭资源的方式在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接,网络连接,磁盘文件等,打开这些物理资源之后必须...
  • java中try 与catch的使用

    2021-02-27 11:37:14
    try{//代码区}catch(Exception e){//异常处理}代码区如果错误,就会返回所写异常的处理。首先要清楚,如果没有try的话,出现异常会导致程序崩溃。而try则可以保证程序的正常运行下去,比如说:try{int i = 1/0;}...
  • 作者:Ashish Lahoti 译者:前端小智 来源:codingnconcept ...最近开源了一 Vue 组件,还不够完善,欢迎大家来一起完善它,也希望大家能给 star 支持一下,谢谢各位了。 github 地址:https://github.com/q.
  • 前言:java编程基础的人对java的异常处理机制都会一定了解,而且可能感觉使用起来也比较简单,但如果在try catch finally语句块中遇到return语句,开发者可能就会遇到一些逻辑问题,甚至步入编程的陷阱。...
  • 这大概就是我要做的,而且必须更好的方法:try {JSONObject jsonObject = new JSONObject(jsonString);int aCount = jsonObject.getInt("acount");String devTok = jsonObject.getString("dt");String q...
  • 在Java中,所有的问题可以使用一类来表示,这类叫做Throwable。Throwable是Java中所有异常和错误的父类。Throwable|-- Error: 表示错误。 指的是不可挽回的严重问题。 相当于人得了绝症。|-- Exception:表示...
  • 尽管有时可能会对此主题进行过多的讨论,但并非篇文章包含有用且相关的信息。Java 中最常见的异常处理机制通常与 try-catch 块关联 。我们使用它来捕获异常,然后提供在发生异常的情况下可以执行的逻辑。的确,...
  • 一、Java 异常处理编写程序时,要在出现可能出现错误的时候加上检测的代码,如判断分母为0,数据为空,过多的 if...二、异常处理:抓抛模型1、抛出Java 程序的执行过程中出现异常,会生成一异常类对象,该异常对象...
  • 就好比对每个人说,“嗨,哥们,路上可能蛇。于是听到的人只好手拿木棍,小心翼翼的往前走”。把try/catch块放到循环外面,就好比对一大群人说,“嗨,兄弟们,路上可能蛇。于是听到的人安排部分人员拿木棍往前...
  • Catch2是一简单的c++单元测试框架,v2版本基于c++11开发,v3版本需要c++14及以上,最初版本Catch1.x基于c++98。 项目地址是 Catch2 或 镜像。 Catch2简单易用,v2版本只需要下载catch.hpp,先选择v2.x分支,路径是...
  • 本文链接:https://blog.csdn.net/qq_38225558/article/details/82054100try {可能出现异常的代码(包括不会出现异常的代码)} catch (Exception e) { //()为接收try{}代码块中出现异常的类型如...
  • 本文实例讲述了php中try catch捕获异常。分享给大家供大家参考。具体方法分析如下:php中try catch可以帮助我们捕获程序代码的异常了,这样我们可以很好的处理一些不必要的错误了,感兴趣的朋友可以一起来看看。PHP...
  • php try catch必要吗

    2021-03-31 08:34:40
    throw 对应一 catch , try 代码块中通过throw抛出的异常会被 catch 代码块接收到,并创建一包含异常信息的对象 ($e)。通过从这 exception 对象调用 $e->getMessage(),输出来自该异常的错误消息。...
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此...关键字1、try2、catch3、throw其中关键字try表示定义一受到监控、受到保护的程序代码块;关键字catch与try遥相呼应,定义当tryblock(受监控的程序块)出现异常时,错误...
  • 一个页面多个ajax请求

    2021-08-06 09:49:56
    你是在一个页面多个子页面,然后每个子页面里面使用了一个回调函数吧?wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww由于include...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 438,408
精华内容 175,363
关键字:

多个catch,每个catch里面都有return