java语言对异常处理运行的初步探索(try-catch-finally)(下)

简介: java语言对异常处理运行的初步探索(try-catch-finally)()

我们还可以在外层套循环来保证输入的数据不会出现异常,出现异常则会一直在循环中重复进行输入,甚至之后我们可以自定义异常来使得输入的数据符合我们的要求(异常除了系统自己规定的类以外还可以自定义,毕竟异常本质上也还是一种类)。

在出现异常的情况下,代码是按照try-catch-finally的执行顺序来的,finally可以省略,finally是语句必须执行的内容,一般是在执行一段代码中不管是否发生异常都必须执行其中的业务逻辑的应用场景中,比如不管是否发生异常都需要关闭一些文件流,关闭一些资源等等。catch其实也可以省略,不过这样的话程序异常会和之前一样由JVM来处理:中断程序,输出异常信息。

try-catch-finally的具体使用实例
import java.util.Scanner;
public class Try {
    public static void main(String[] args) {
        while(true) {
            try {
                Scanner scanner = new Scanner(System.in);
                System.out.println("请输入一个整数");
                int a = scanner.nextInt();
                System.out.println("a的值为:" + a);
                break;
            } catch (Exception e) {
                System.out.println("输入错误,请重新输入");
            }
        }
    }
}

以上就实现了数据输入时限定只能得到整数,输入异常时还不会退出程序的数据输入。我们还可以在其中添加我们想要具体限定的条件,比如大小,位长等等。

多说一句,如果尝试在循环外部创建Scanner对象,然后内部依旧使用nextInt方法,并在调试时第一次输入异常的话,那么之后就不会再有输入的机会了,会陷入一个死循环,无法实现我们想要的功能。有兴趣的朋友可以看一下。

我们在出现异常的时候是直接跳出代码的执行的,通过断点追踪进去Scanner具体的原码后发现,本来退出被调用方法时为了不影响下一次操作需要对一些参数进行重置的操作,现在因为异常直接跳出导致重置操作无法进行,这样就会对下一次数据的读取造成影响。关于上面那个问题,我发现的是Scanner里面的skipped属性(用来判断分隔符是否被跳过了,应该就是字段是否已经被读取完毕)没有被改回false,所以导致之后的循环中scanner对象的每一次使用skipped属性都无法被修改。(因为skipped每次都是true,就代表字段已经被读取完毕了;被读取的字段token是空,无法进行重置参数的操作;needInput初始就是false,而且只有第一次正常的读取中readInput后也被修改为false,不需要更多的输入,跳过了输入阶段;所以又抛出异常throwFor()退出方法的调用到nextInt(),但是退出时又没有修改skipped属性,所以下一次还是true,就这样进入了一个死循环)具体有问题的源码内容如下:

我们可以通过在循环体内创建对象,这样scanner会在每次调用的时候重新创建从而来进行更新;或者我们可以通过使用Integer.paseInt(scanner.next())来改变数据类型,这样就不会让scanner的属性没有重新初始化遭受异常强制中断了,因为这个时候异常时发生在外部的paseInt中的。

当然严谨来说我其实应该还要具体进去看看getCompleteTokenInBuffer方法的,并且我的解释在自己看来都不是很好,但是这对于我这个小垃圾来说源码看着属实是有点头晕了,看着getCompleteTokenInBuffer的注释大概应该可能是这么回事吧,但是又想具体搞清楚,属于是又菜又爱玩了。之后要是实力有所精进会更加具体详实的搞清楚这个问题。诚心欢迎各位大佬朋友、兄弟姐妹指正我说法里面的错误和不足,拜谢!

异常处理的整体机制

知道try-catch-finally的用法之后我们可以来看看异常处理的整体的处理机制了。我们知道,在使用try-catch-finally之前,异常都是由我们的JVM系统来处理的,JVM在异常处理中有着我们Object类一样的顶级地位,Object是所有类的最终父类,JVM也是所有类的异常处理的最终处理单位。具体是像下图中的结构:

我们的main调用了f1方法,f1方法又调用了f2方法。这里用到了我们的throws了,throws就像是摆烂摸鱼,如果f2中没有显式地处理这个异常,那么f2就会把这个异常抛给调用他的f1,这个异常我不想管,不管了。所以在没有使用try处理前,异常会被一层一层的被抛给最高级的JVM系统,并最终由他来处理这个异常。同时我们可以修改异常类型来选择性的抛弃指定的异常。(将Exception修改为具体的异常类型)

try-catch-finally的使用细节
public class Try {
   public static void main(String[] args) {
       System.out.println(a.method());
   }
}
class a{
   public static int method() {
       int i = 0;
       try {
           return 9 / i;
       } catch (Exception e) {
           System.out.println("catch");
           return ++i;
       } finally {
           System.out.println("finally");
           return ++i;
       }
   }
}

关于这一段代码的执行顺序,我们只需要明确一个概念就可以迎刃而解了——finally中的代码是必须执行的业务逻辑。在这个语句中try中发生了异常被捕获到了catch中,执行完之后到return ++i;当然是先执行完  ++i 之后发现finally没有被执行,所以就在return之前先去执行finally 的语句,并最终在finally中return。所以最后的结果是2;

如果将catch中的 ++i 换成 i - 8,我们的过程其实没有变化,只不过 i - 8 和 ++i有很大的区别,后者是可以作为一个独立的语句来执行的,而前者没有接收者,所以return i - 8;这里其实在底层先用一个临时变量temp储存了 i - 8 的值,然后再去执行finally的代码。如果finally中的代码没有出口return,就算finally中修改了 i ,最终还是会返回temp的值;如果有,那么会在finally中直接return。

public class Try {
    public static void main(String[] args) {
        System.out.println(a.method());
    }
}
class a{
    public static int method() {
        int i = 0;
        try {
            return 9 / i;
        } catch (Exception e) {
            System.out.println("catch");
            return i - 8;
        } finally {
            System.out.println("finally");
            i++;
//            return ++i; //返回2
        }
    }
}

结果如下:

catch

finally

-8

 

 

 

目录
相关文章
|
17天前
|
Oracle Java 关系型数据库
Java基础(一):语言概述
Java基础(一):语言概述
Java基础(一):语言概述
|
15天前
|
Java 数据库连接 数据处理
探究Java异常处理【保姆级教程】
Java 异常处理是确保程序稳健运行的关键机制。它通过捕获和处理运行时错误,避免程序崩溃。Java 的异常体系以 `Throwable` 为基础,分为 `Error` 和 `Exception`。前者表示严重错误,后者可细分为受检和非受检异常。常见的异常处理方式包括 `try-catch-finally`、`throws` 和 `throw` 关键字。此外,还可以自定义异常类以满足特定需求。最佳实践包括捕获具体异常、合理使用 `finally` 块和谨慎抛出异常。掌握这些技巧能显著提升程序的健壮性和可靠性。
35 4
|
26天前
|
存储 监控 算法
探秘局域网桌面监控:深入剖析 Java 语言核心算法
在数字化办公时代,局域网桌面监控如同企业的“智慧鹰眼”,确保工作效率与数据安全。本文以Java为载体,揭示哈希表在监控中的关键应用。通过高效的数据结构和算法,哈希表能快速索引设备连接信息,大幅提升监控的时效性和响应速度。代码示例展示了如何用Java实现设备网络连接监控,结合未来技术如AI、大数据,展望更智能的监控体系,助力企业在数字化浪潮中稳健前行。
|
2月前
|
Java
Java 异常处理:11 个异常处理最佳实践
本文深入探讨了Java异常处理的最佳实践,包括早抛出晚捕获、只捕获可处理异常、不忽略异常、抛出具体异常、正确包装异常、记录或抛出异常但不同时执行、不在finally中抛出异常、避免用异常控制流程、使用模板方法减少重复代码、抛出与方法相关的异常及异常处理后清理资源等内容,旨在提升代码质量和可维护性。
134 3
|
2月前
|
Java 程序员
深入理解Java异常处理机制
Java的异常处理是编程中的一块基石,它不仅保障了代码的健壮性,还提升了程序的可读性和可维护性。本文将深入浅出地探讨Java异常处理的核心概念、分类、处理策略以及最佳实践,旨在帮助读者建立正确的异常处理观念,提升编程效率和质量。
145 1
|
2月前
|
Java 开发者 UED
深入探索Java中的异常处理机制##
本文将带你深入了解Java语言中的异常处理机制,包括异常的分类、异常的捕获与处理、自定义异常的创建以及最佳实践。通过具体实例和代码演示,帮助你更好地理解和运用Java中的异常处理,提高程序的健壮性和可维护性。 ##
67 2
|
2月前
|
Java 开发者
Java 中的异常处理:不仅仅是 try-catch
在Java的世界里,异常处理是代码的守护神,它保护着程序不会因为意外错误而崩溃。但异常处理远不止try-catch那么简单。本文将深入探讨Java的异常处理机制,从基本的try-catch到更复杂的自定义异常和finally块的使用,带你理解如何在Java中优雅地处理错误。
63 1
|
2月前
|
Java API 开发者
深入理解Java中的异常处理机制
本文探讨了Java编程语言中异常处理的核心概念,包括异常类型、异常捕获与抛出、以及最佳实践。通过分析常见的异常场景和处理策略,旨在帮助开发者更好地理解和运用异常处理机制,提高代码的健壮性和可维护性。文章不仅涵盖了基本的try-catch结构,还深入讨论了自定义异常的创建与使用,以及finally块的重要性和应用。此外,还将介绍一些高级技巧,如多异常捕获和嵌套异常处理,为读者提供全面的技术指导。
108 0
|
3月前
|
设计模式 Java 开发者
Java中的异常处理:理解与实践
【10月更文挑战第42天】在Java的世界中,异常处理是每个开发者必须面对的挑战。它就像是一场不可预知的风暴,可能会在任何时候突然降临,打乱我们的计划。但是,如果我们能够掌握正确的处理方法,这场风暴也可以变成推动我们前进的力量。本文将带你深入理解Java中的异常处理机制,通过代码示例,我们将一起学习如何捕获、处理和预防异常,让你的程序在面对任何挑战时都能保持稳健和优雅。
|
2月前
|
安全 Java 数据库连接
Java中的异常处理:理解与实践
在Java的世界里,异常处理是维护代码健壮性的守门人。本文将带你深入理解Java的异常机制,通过直观的例子展示如何优雅地处理错误和异常。我们将从基本的try-catch结构出发,探索更复杂的finally块、自定义异常类以及throw关键字的使用。文章旨在通过深入浅出的方式,帮助你构建一个更加稳定和可靠的应用程序。
43 5