第1章 异常与异常处理(上)

本章主要讲解,什么是异常、Java 中的异常体系结构、如何处理异常、如何自定义异常以及异常链的相关知识

1 - 1:Java异常简介

异常简介:异常处理的作用、Java异常体系结构简介

处理异常:try-catch及try-catch-finally、抛出异常、自定义异常、异常链

异常:有异于常态,和正常情况不一样,有错误出现。

阻止当前方法或作用域,称之为异常。

异常好比说一家工厂,本来是正常生产,但突然原料用完了的异常情况,没人处理这个问题,这就出现了工人没法干活,损失客户,老板赔本。如果原料用完时,员工把这样的问题给上级反映,管理人员作出处理,让采购那边订购原料,跟客户说明情况,保证不耽误出货,最后拉闸断电关机器,把所有占用资源释放,老板的损失就会降到最低。

上面这样一说,就是说什么是异常、异常处理的作用和意义。我们来看一下Java中异常体系结构。

在Java中有一个类叫Throwable类,这是异常体系的总类,Java中所有不正常类都继承与它,Throwable主要有两个“儿子”,一个是Error类,一个是Exception类。一般我们很少接触Error这个类,它指的是系统错误,有VirtualMachineError(虚拟机错误)ThreadDeath(线程死锁),如果出现了Error类,程序完全无法运行了。我们来看Exception类,这个类出现代表着编码、环境、用户操作输入出现问题。Exception也有“儿子”,有RuntimeException(非检查异常)CheckException(检查异常)。能够引起运行时异常的情况有很多,就像引用了一个空对象的属性或方法,也可能是数组访问越界,又或是类型转换出错,也有可能是算术方面引起的异常:

Runtime(非检查异常):

NullPointerException(空指针异常),如:
String str = null;
System.out.println(str.length());

ArrayIndexOutOfBoundsException(数组下标越界异常),如:
int array = {1, 2, 3};
for(int i = 0; i <= 3; i++){
	System.out.println(array[i]);
}

ClassCastException(类型转换异常),如:
class Animal(){
	
}
class Dog extends Animal(){
	
}
class Cat extends Animal(){
	
}
public class Test(){
	public static void main(String[] args){
		Animal a1 = new Dog();
		Animal a2 = new Cat();
		Dog d1 = (Dog)a1;
		Dog d2 = (Dog)a2;
	}
}

ArithmeticException(算术异常),如:
int one = 12;
int two = 0;
System.one.println(one/two);

当然还会有其他异常,要列举会要好多时间。

运行时异常会有Java虚拟机自动抛出,自动捕获,运行时异常的出现大部分情况下说明代码本身有问题,应该从逻辑上改变代码。

再看CheckException(检查异常),比如IOException(文件不存在)、SQLException(链接错误)。

 

1 - 2:Java中使用try...catch...finally实现异常处理

在Java中,我们使用try...catch或try...catch...finally这样的语句块来捕获并处理异常,我们先来看try...catch语句块。

try{
	//一些会抛出异常的方法
}catch(Exception e){
	//处理该异常的代码块
}

如果try块中发生异常,就会中止执行程序,然后程序的控制权会交由控制块中的异常处理程序进行处理。catch块中的代码该怎么写,如何处理这个异常则是根据不同业务情景再去不同对待。比如可以发出一些警提示用户或编程人员去检查一些配置、网络连接,也可以在catch中进行错误日志地记录等,就像下面代码:

try{
	System.out.print("请输入你的年龄:");
	Scanner input = new Scanner(System.in);
	int age = input.nextInt();
	System.out.println("十年后你" + (age + 10) + 岁);
}catch(InputMismatchException e){
	System.out.println("你应该输入整数!");
}
System.out.print("程序结束");

在try块中,首先提示用户输入年龄,通过Scanner对象去尝试捕获从键盘上输入的整数,如果我们输入的不是整数,就会抛出输入不匹配的异常,这个就会被系统捕获进入catch中,输出你应该输入整数。

注意,在try...catch块执行完后在catch块外面的其他语句会顺序的继续执行,最后无论怎样,程序结束都会显示在屏幕上。

如果try抛出很多异常,对于不同异常我们的处理方法不尽相同。如果所有类型异常都用catch块处理,那这个处理就会变得含糊不清,就相当于没有处理了。这时候我们就用到了多重catch块的语法:

try{
	//一些会抛出异常的方法
}catch(Exception e){
	//处理该异常的代码块
}catch(Exception e){
	//处理该异常的代码块
}

来康康这个:

Scanner input = new Scanner(System.in);
try{
	System.out.print("请输入第一个数:");
	int one = input.nextInt();
	System.out.print("请输入第二个数:");
	int two = input.nextInt();
	System.out.println("两数相除结果为:" + (one/two));
}catch(InputMismatchException e){
	System.out.println("你应该输入整数!");
}catch(ArithmeticException e){
	System.out.println("除数不能为0");
}catch(Exception e){
	System.out.println("我是不知名异常");
}
System.out.println("程序结束");

在try块后面用多个catc块来捕获异常,对其进行相应处理,上面在try块中定义了两个整形变量,one和two,它们都取自键盘上输入的整数值,这时候如果咱们输入第一个“one”的时候,我输入hello,就会抛出输入不匹配异常,程序就会输出你应该输入整数。在输入“two”的时候我们输入了0,程序里就会显示除数不能为0的字样。

写try...catch块注意事项:顺序问题。要按照先小后大,就是先子类后父类的顺序来编写多重catch语句块。因为当程序抛出异常的时候,异常处理系统会就近寻找匹配的处理异常程序,而子类继承于父类,针对于父类的异常处理程序对于子类也是适用的。上面的Exception e是上面异常的父类,所以要把针对于Exception的catc块放到最后。当然如果这个多重catch块顺序写错了,编译器在编译的时候也不会通过,会报错,

我们在写完try...catch语句之后也要做一些善后工作,比如关闭连接、或关闭一些已经打开的文件。而这种善后工作我们就在大括号后面加上finall语句块来进行善后。

try{
	//一些会抛出异常的方法
}catch(Exception e){
	//处理该异常的代码块
}catch(Exception2 e){
	//处理该异常的代码块
}finally{
	//最终要执行的代码
}

 

1 - 3:Java中通过案例学习fry...catch...finally

打开eclipse,建立imooc_exception_demo项目,在src创建个类,放在com.imooc.test包下,叫TryCatchTest类,自动生成main方法:

创建一个test方法,返回int类型值,先暂时让它返回0以免编译器报错。

这个test方法要先给他创建两个变量:divider(除数)、result(结果),try-catch用来捕获while循环,每次循环divider减一,result=result+100/result,如果捕获异常,打印输出抛出异常了,返回-1,否则返回result:

然后我们在main方法里调用一下这个方法了,先建一个try-catch的实例,名字为tct,建立一个int变量叫result接受tct的Task值,然后打印:

package com.imooc.test;

public class TryCatchTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TryCatchTest tct = new TryCatchTest();
		int result = tct.Test();
		System.out.println("test()方法执行完毕,返回值是" + result);
	}
	
	public int Test() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return -1;
		}
	}
}


/*结果:
java.lang.ArithmeticException: / by zero
	at com.imooc.test.TryCatchTest.Test(TryCatchTest.java:18)
	at com.imooc.test.TryCatchTest.main(TryCatchTest.java:8)
循环抛出异常了
test()方法执行完毕,返回值是-1
*/

确实,Test方法抛出了个异常,这个异常被catch语句块捕获,然后发现并在第18行中显示。

我们再写一个Test2方法,Test2方法和Test方法功能一样,但我们在Test2后面要加一个finally语句块,我们在finally中输出这是finally,哈哈,再输出result值。

package com.imooc.test;

public class TryCatchTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TryCatchTest tct = new TryCatchTest();
		int result = tct.Test2();
		System.out.println("test2()方法执行完毕");
	}
	
	public int Test() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return -1;
		}
	}
	
	public int Test2() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return result = 999;
		}finally {
			System.out.println("这是finally,哈哈");
			System.out.println("我是result,值是" + result);
		}
	}
}

/*结果:
java.lang.ArithmeticException: / by zero
	at com.imooc.test.TryCatchTest.Test2(TryCatchTest.java:34)
	at com.imooc.test.TryCatchTest.main(TryCatchTest.java:8)
循环抛出异常了
这是finally,哈哈
我是result,值是999
test2()方法执行完毕
*/

这里可以看到,在Test2抛出算术异常后,被catch语句块捕获,在方法返回到main方法之前,try调用了finally中的语句,输出了这是finally,哈哈,然后输出我是result,值是999,然后回到main方法。刚才我们讲到了try-catch-finally语句块中的语句和语句块之外的语句的执行顺序的问题,我们再改一下这个方法。我们把result等于999删去,在最后返回1111作为结果。

package com.imooc.test;

public class TryCatchTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TryCatchTest tct = new TryCatchTest();
		int result = tct.Test3();
		System.out.println("test3()方法执行完毕,返回值为" + result);
	}
	
	public int Test() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return -1;
		}
	}
	
	public int Test2() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return result = 999;
		}finally {
			System.out.println("这是finally,哈哈");
			System.out.println("我是result,值是" + result);
		}
	}
	
	public int Test3() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
		}finally {
			System.out.println("这是finally,哈哈");
			System.out.println("我是result,值是" + result);
		}
		System.out.println("我是test3,我运行完了!");
		return 1111;
	}
}

/*结果:
java.lang.ArithmeticException: / by zero
	at com.imooc.test.TryCatchTest.Test3(TryCatchTest.java:53)
	at com.imooc.test.TryCatchTest.main(TryCatchTest.java:8)
循环抛出异常了
这是finally,哈哈
我是result,值是381
我是test3,我运行完了!
test3()方法执行完毕,返回值为1111
*/

上面那个try块里的while算出来的结果是381,所以值是381。这里可以看出来,如果try-catch里面没有return语句,就会调用这三个语句块之外的语句。

 

1 - 4:练习题

下列关于 try-catch-finally 语句的描述中,错误的是( )

A、try 语句可以独立存在

B、catch 块跟在 try 语句后面,它可以是一个或多个

C、catch 块有一个参数,该参数是某种异常类的对象

D、多重 catch 语句中,异常类型必须子类在前父类在后

 

答案:A。解析:try 语句块不可以独立存在,必须与 catch 或者 finally 块同存。

在使用Python来安装geopandas包时,由于geopandas依赖于几个其他的Python库(如GDAL, Fiona, Pyproj, Shapely等),因此安装过程可能需要一些额外的步骤。以下是一个基本的安装指南,适用于大多数用户: 使用pip安装 确保Python和pip已安装: 首先,确保你的计算机上已安装了Python和pip。pip是Python的包管理工具,用于安装和管理Python包。 安装依赖库: 由于geopandas依赖于GDAL, Fiona, Pyproj, Shapely等库,你可能需要先安装这些库。通常,你可以通过pip直接安装这些库,但有时候可能需要从其他源下载预编译的二进制包(wheel文件),特别是GDAL和Fiona,因为它们可能包含一些系统级的依赖。 bash pip install GDAL Fiona Pyproj Shapely 注意:在某些系统上,直接使用pip安装GDAL和Fiona可能会遇到问题,因为它们需要编译一些C/C++代码。如果遇到问题,你可以考虑使用conda(一个Python包、依赖和环境管理器)来安装这些库,或者从Unofficial Windows Binaries for Python Extension Packages这样的网站下载预编译的wheel文件。 安装geopandas: 在安装了所有依赖库之后,你可以使用pip来安装geopandas。 bash pip install geopandas 使用conda安装 如果你正在使用conda作为你的Python包管理器,那么安装geopandas和它的依赖可能会更简单一些。 创建一个新的conda环境(可选,但推荐): bash conda create -n geoenv python=3.x anaconda conda activate geoenv 其中3.x是你希望使用的Python版本。 安装geopandas: 使用conda-forge频道来安装geopandas,因为它提供了许多地理空间相关的包。 bash conda install -c conda-forge geopandas 这条命令会自动安装geopandas及其所有依赖。 注意事项 如果你在安装过程中遇到任何问题,比如编译错误或依赖问题,请检查你的Python版本和pip/conda的版本是否是最新的,或者尝试在不同的环境中安装。 某些库(如GDAL)可能需要额外的系统级依赖,如地理空间库(如PROJ和GEOS)。这些依赖可能需要单独安装,具体取决于你的操作系统。 如果你在Windows上遇到问题,并且pip安装失败,尝试从Unofficial Windows Binaries for Python Extension Packages网站下载相应的wheel文件,并使用pip进行安装。 脚本示例 虽然你的问题主要是关于如何安装geopandas,但如果你想要一个Python脚本来重命名文件夹下的文件,在原始名字前面加上字符串"geopandas",以下是一个简单的示例: python import os # 指定文件夹路径 folder_path = 'path/to/your/folder' # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 构造原始文件路径 old_file_path = os.path.join(folder_path, filename) # 构造新文件名 new_filename = 'geopandas_' + filename # 构造新文件路径 new_file_path = os.path.join(folder_path, new_filename) # 重命名文件 os.rename(old_file_path, new_file_path) print(f'Renamed "{filename}" to "{new_filename}"') 请确保将'path/to/your/folder'替换为你想要重命名文件的实际文件夹路径。
在使用Python来安装geopandas包时,由于geopandas依赖于几个其他的Python库(如GDAL, Fiona, Pyproj, Shapely等),因此安装过程可能需要一些额外的步骤。以下是一个基本的安装指南,适用于大多数用户: 使用pip安装 确保Python和pip已安装: 首先,确保你的计算机上已安装了Python和pip。pip是Python的包管理工具,用于安装和管理Python包。 安装依赖库: 由于geopandas依赖于GDAL, Fiona, Pyproj, Shapely等库,你可能需要先安装这些库。通常,你可以通过pip直接安装这些库,但有时候可能需要从其他源下载预编译的二进制包(wheel文件),特别是GDAL和Fiona,因为它们可能包含一些系统级的依赖。 bash pip install GDAL Fiona Pyproj Shapely 注意:在某些系统上,直接使用pip安装GDAL和Fiona可能会遇到问题,因为它们需要编译一些C/C++代码。如果遇到问题,你可以考虑使用conda(一个Python包、依赖和环境管理器)来安装这些库,或者从Unofficial Windows Binaries for Python Extension Packages这样的网站下载预编译的wheel文件。 安装geopandas: 在安装了所有依赖库之后,你可以使用pip来安装geopandas。 bash pip install geopandas 使用conda安装 如果你正在使用conda作为你的Python包管理器,那么安装geopandas和它的依赖可能会更简单一些。 创建一个新的conda环境(可选,但推荐): bash conda create -n geoenv python=3.x anaconda conda activate geoenv 其中3.x是你希望使用的Python版本。 安装geopandas: 使用conda-forge频道来安装geopandas,因为它提供了许多地理空间相关的包。 bash conda install -c conda-forge geopandas 这条命令会自动安装geopandas及其所有依赖。 注意事项 如果你在安装过程中遇到任何问题,比如编译错误或依赖问题,请检查你的Python版本和pip/conda的版本是否是最新的,或者尝试在不同的环境中安装。 某些库(如GDAL)可能需要额外的系统级依赖,如地理空间库(如PROJ和GEOS)。这些依赖可能需要单独安装,具体取决于你的操作系统。 如果你在Windows上遇到问题,并且pip安装失败,尝试从Unofficial Windows Binaries for Python Extension Packages网站下载相应的wheel文件,并使用pip进行安装。 脚本示例 虽然你的问题主要是关于如何安装geopandas,但如果你想要一个Python脚本来重命名文件夹下的文件,在原始名字前面加上字符串"geopandas",以下是一个简单的示例: python import os # 指定文件夹路径 folder_path = 'path/to/your/folder' # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 构造原始文件路径 old_file_path = os.path.join(folder_path, filename) # 构造新文件名 new_filename = 'geopandas_' + filename # 构造新文件路径 new_file_path = os.path.join(folder_path, new_filename) # 重命名文件 os.rename(old_file_path, new_file_path) print(f'Renamed "{filename}" to "{new_filename}"') 请确保将'path/to/your/folder'替换为你想要重命名文件的实际文件夹路径。
在使用Python来安装geopandas包时,由于geopandas依赖于几个其他的Python库(如GDAL, Fiona, Pyproj, Shapely等),因此安装过程可能需要一些额外的步骤。以下是一个基本的安装指南,适用于大多数用户: 使用pip安装 确保Python和pip已安装: 首先,确保你的计算机上已安装了Python和pip。pip是Python的包管理工具,用于安装和管理Python包。 安装依赖库: 由于geopandas依赖于GDAL, Fiona, Pyproj, Shapely等库,你可能需要先安装这些库。通常,你可以通过pip直接安装这些库,但有时候可能需要从其他源下载预编译的二进制包(wheel文件),特别是GDAL和Fiona,因为它们可能包含一些系统级的依赖。 bash pip install GDAL Fiona Pyproj Shapely 注意:在某些系统上,直接使用pip安装GDAL和Fiona可能会遇到问题,因为它们需要编译一些C/C++代码。如果遇到问题,你可以考虑使用conda(一个Python包、依赖和环境管理器)来安装这些库,或者从Unofficial Windows Binaries for Python Extension Packages这样的网站下载预编译的wheel文件。 安装geopandas: 在安装了所有依赖库之后,你可以使用pip来安装geopandas。 bash pip install geopandas 使用conda安装 如果你正在使用conda作为你的Python包管理器,那么安装geopandas和它的依赖可能会更简单一些。 创建一个新的conda环境(可选,但推荐): bash conda create -n geoenv python=3.x anaconda conda activate geoenv 其中3.x是你希望使用的Python版本。 安装geopandas: 使用conda-forge频道来安装geopandas,因为它提供了许多地理空间相关的包。 bash conda install -c conda-forge geopandas 这条命令会自动安装geopandas及其所有依赖。 注意事项 如果你在安装过程中遇到任何问题,比如编译错误或依赖问题,请检查你的Python版本和pip/conda的版本是否是最新的,或者尝试在不同的环境中安装。 某些库(如GDAL)可能需要额外的系统级依赖,如地理空间库(如PROJ和GEOS)。这些依赖可能需要单独安装,具体取决于你的操作系统。 如果你在Windows上遇到问题,并且pip安装失败,尝试从Unofficial Windows Binaries for Python Extension Packages网站下载相应的wheel文件,并使用pip进行安装。 脚本示例 虽然你的问题主要是关于如何安装geopandas,但如果你想要一个Python脚本来重命名文件夹下的文件,在原始名字前面加上字符串"geopandas",以下是一个简单的示例: python import os # 指定文件夹路径 folder_path = 'path/to/your/folder' # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 构造原始文件路径 old_file_path = os.path.join(folder_path, filename) # 构造新文件名 new_filename = 'geopandas_' + filename # 构造新文件路径 new_file_path = os.path.join(folder_path, new_filename) # 重命名文件 os.rename(old_file_path, new_file_path) print(f'Renamed "{filename}" to "{new_filename}"') 请确保将'path/to/your/folder'替换为你想要重命名文件的实际文件夹路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值