一, 异常
什么是异常
尽管人人希望自己身体健康,处理的事情都能顺利进行,但在实际生活中总会遇到各种状况,比如感冒发烧,工作时电脑蓝屏、死机等。同样,在程序运行的过程中,也会发生各种非正常状况,比如程序运行时磁盘空间不足、网络连接中断、被装载的类不存在等。针对这种情况,在Java语言中,引入了异常,以异常类的形式对这些非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理。
代码
结果
接下来通过一张图来展示Throwable类的继承体系,如下图所示:
通过图中可以看出,Throwable有两个直接子类Error和Exception,其中Error代表程序中产生的错误,Exception代表程序中产生的异常。
接下来就对这两个直接子类进行详细的讲解。
Error类称为错误类,它表示Java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠修改程序本身是不能恢复执行的。举一个生活中的例子,在盖楼的过程中因偷工减料,导致大楼坍塌,这就相当于一个Error。使用iava命令去运行一个不存在的类就会出现Error错误
Exception类称为异常类,它表示程序本身可以处理的错误,在开发Java程序中进行的异常处理,都是针对Exception类及其子类。在Exception类的众多子类中有一个特殊的RuntimeException类,该类及其子类用于表示运行时异常,除了此类,Exception类下所有其他的子类都用于表示编译时异常。本节主要针对Exception类及其子类进行讲解。
通过前面的学习读者已经了解了Throwable类,为了方便后面的学习,接下来将Throwable类中的常用方法罗列出来。
try...catch和finally
Java中提供了一种对异常进行处理的方式一一异常捕获。异常捕获通常使用try...catch语句,具体语法格式如下:
try{ //程序代码块}catch(ExceptionTye(Exception类及其子类) e){ //对 ExceptionType的处理
}
其中在try代码块中编写可能发生异常的Java语句,catch代码块中编写针对异常进行处理的代码。当try代码块中的程序发生了异常,系统会将这个异常的信息封装成一个异常对象,并将这个对象传递给catch代码块。catch代码块需要一个参数指明它所能够接收的异常类型,这个参数的类型必须是Exception类或其子类。
代码
结果
代码
结果
throws关键字
在上一小节学习的文件中,由于调用的是自己写的divide()方法,因此很清楚该方法可能会发生异常。试想一下,如果去调用一个别人写的方法时,是否能知道别人写的方法是否会有异常呢?这是很难做出判断的。针对这种情况,Java中允许在方法的后面使用throws关键字对外声明该方法有可能发生的异常,这样调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理,否则编译无法通过。
throws关键字声明抛出异常的语法格式如下:
修饰符 返回值类型 方法名([参数1,参数2....])throws ExcepsionTypel[,ExceptionType2.....]{
}
从上述语法格式中可以看出,throws关键字需要写在方法声明的后面,throws后面需要声明方法中发生异常的类型,通常将这种做法称为方法声明抛出一个异常。
代码
结果
运行时异常和编译时异常\n在实际开发中,经常会在程序编译时产生一些异常,而这些异常必须要进行处理,这种异常被称为编译时异常,也称为checked异常。另外还有一种异常是在程序运行时产生的,这种异常即使不编写异常处理代码,依然可以通过编译因此被称为运行时异常,也称为unchecked异常。
编译时异常
在Java中,Exception类中除了RuntimeException类及其子类都是编译时异常。编方译时异常的特点是Java编译器会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。处理编译时期的异常有两种方式:使用try...catch语句对异常进行捕获
使用throws关键字声明抛出异常,调用者对其处理。
2.运行时异常
RuntimeException类及其子类都是运行时异常。运行时异常的特点是Java编译器不会对其进行检查,也就是说,当程序中出现这类异常时,即使没有使用try..catch语句捕获或使用throws关键字声明抛出,程序也能编译通过。运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复。比如通过数组的角标访问数组的元素时,如果超过了数组的最大角标,就会发生运行时异
常,代码如下所示:
int[] arr=new int[5];
System.out.println(arr[6]);
上面代码中,由于数组arr的length为5,最大角标应为4,当使用arr[6]访问数组中的元素就会发生数组角标越界的异常。
自定义异常
JDK中定义了大量的异常类,虽然这些异常类可以描述编程时出现的大部分异常情况,但是在程序开发中有时可能需要描述程序中特有的异常情况,例如文件4-38中在divide()方法中不允许被除数为负数。为了解决这个问题,在Java中允许用户自定义异常,但自定义的异常类必须继承自Exception或其子类。
自定义异常
代码
package W;
//下面的代码是自定义一个异常类继承Excption
public class DivideByMinusExcption extends Exception{
public DivideByMinusExcption() {
super ();//调用Excption无参构造方法
}
public DivideByMinusExcption(String message) {
super(message);
}
}
package W;
public class Excption {
public static void main(String[] args) {
super(message);
}
}
package W;
public class Excption {
public static void main(String[] args) {
int result=divide(4,-2);//调用divide()方法,传入一个负数作为被除数
System.out.println(result);
}
//下面的方法实现了两种整数相除
public static int divide(int x,int y){
if (y<0) {
//throw new DivideByMinusExcption("除数是负数");//使用throw关键字抛出异常对象
}
int result=x/y;//定义变量result记录两个数相除的结果
return result;
}
}
代码
package W;
public class Excption2 {
public static void main(String[] args) {
try {
int result=divide(4,-2);//调用divide()方法,传入一个负数作为被除数
System.out.println(result);
}catch (DivideByMinusExcption e) {//对捕获的异常进行处理
System.out.println(e.getMessage());//打印捕获的异常信息
}
}
//下面的方法实现了两种整数相除,使用throws关键字声明抛出异常
public static int divide(int x,int y)throws DivideByMinusExcption{
if (y<0) {
throw new DivideByMinusExcption("除数是负数");//使用throw关键字抛出异常对象
}
int result=x/y;//定义变量result记录两个数相除的结果
return result;
}
}
自定义异常
package W;
//下面的代码是自定义一个异常类继承Excption
public class DivideByMinusExcption extends Exception{
public DivideByMinusExcption() {
super ();//调用Excption无参构造方法
}
public DivideByMinusExcption(String message) {
super(message);
}
}
package W;
public class Excption {
public static void main(String[] args) {
int result=divide(4,-2);//调用divide()方法,传入一个负数作为被除数
System.out.println(result);
}
//下面的方法实现了两种整数相除
public static int divide(int x,int y){
if (y<0) {
//throw new DivideByMinusExcption("除数是负数");//使用throw关键字抛出异常对象
}
int result=x/y;//定义变量result记录两个数相除的结果
return result;
}
}
package W;
public class Excption2 {
public static void main(String[] args) {
try {
int result=divide(4,-2);//调用divide()方法,传入一个负数作为被除数
System.out.println(result);
}catch (DivideByMinusExcption e) {//对捕获的异常进行处理
System.out.println(e.getMessage());//打印捕获的异常信息
}
}
//下面的方法实现了两种整数相除,使用throws关键字声明抛出异常
public static int divide(int x,int y)throws DivideByMinusExcption{
if (y<0) {
throw new DivideByMinusE
StringBuilder类
Java中的StringBuilder类用于动态地构建字符串。在之前的文章中,已经提到过了,在Sting类中它的存储数据的数组是被final修饰了的,所以说在Java中的String类是不可变的,也就是说,一旦创建了一个String对象,它的值就不能被更改。
而StringBuilder类提供的方法允许我们添加、删除和修改其字符串缓冲区中的内容。
它的底层实现也是使用char类型数组实现存储数据的,但是没有被final修饰,且空参构造初始化时默认给定16个char类型大小的空间,每次在添加数据时,会判断需要添加的目标字符产与本身数组的空间是否足够,足够的话直接添加进数组中,不足的话,会先进行扩容,然后再添加。
访问控制
在Java中,针对类、成员方法和属性提供了四种访问级别,分别是private、default、protected和public。接下来通过一个图将这四种控制级别由小到大依次列出,如下图所示。
上图中展示了Java中的四种访问控制级别,具体介绍如下:
private(类访问级别):如果类的成员被private访问控制符来修饰,则这个成员只能被该类的其他成员访问,其他类无法直接访问。类的良好封装就是通过private关键字来实现的。default(包访问级别): 如果一个类或者类的成员不使用任何访问控制符修饰,则称它为默认访问控制级别,这个类或者类的成员只能被本包中的其他类访问。protected(子类访问级别): 如果一个类的成员被protected访问控制符修饰,那么这个成员既能被同一包下的其他类访问,也能被不同包下该类的子类访问。public(公共访问级别):这是一个最宽松的访问控制级别,如果一个类或者类的成员被public访问控制符修饰,那么这个类或者类的成员能被所有的类访问,不管访问类与被访问类是否在同一个包中。
接下来通过一个表将这四种访问级别更加直观的表示出来,如下表所示。
JavaAPI类的初始化
5.1 string类和stringBuffer类
API(Application Programming Interface)指的是应用程序编程接口。假设使用Java语言编写一个机器人程序去控制机器人踢足球,程序就需要向机器人发出向前跑、向后跑、射门、抢球等各种命令,没有编过程序的人很难想象这样 的程序如何编写。但是对于有经验的开发人员来说知道机器人厂商一定会提供一些用于控制机器人的Java类,这些类中定义好了操作机器人各种动作的方法。其实,这些Java类就是机器人厂商提供给应用程序编程的接口,通常把这些类称为Xxx Robot API(意思是Xxx厂家的机器人API)。
在应用程序中经常会用到字符串,所谓字符串就是指一连串的字符,它是由许多单个字符连接而成的,如多个英文字母所组成的一个英文单词。字符串中可以包含任意字符,这些字符必须包含在一对双引号“”之内,例如“abc”。在Java中定义了String和StringBuffer两个类来封装字符串,并提供了一系列操作字符串的方法,它们都位于java.lang包中,因此不需要导包就可以直接使用。
String类的初始化
在操作String类之前,首先需要对String类进行初始化,在Java中可以通过以下两种方式对string类进行初始化,具体如下:
使用字符串常量直接初始化一个String对象,具体代码如下:
String str1 = \"abc\";
使用String的构造方法初始化字符串对象,String类的构造方法如下表所示。
代码
结果
string类的常见操作
string类在实际开发中的应用非常广泛,因此灵活地使用string类是非常重要的,接下来介绍string类常用的一些方法如下表所示
代码
结果
string buffer类
由于字符串是常量,因此一旦创建,其内容和长度是不可改变的。如果需要对一个字符串进行修改,则只能创建新的字符串。为了便于对字符串进行修改,在JDK中提供了一个StringBuffer类(也称字符串缓冲区)。StringBuffer类和String类最大的区别在于它的内容和长度都是可以改变的。StringBuffer类似-个字符容器,当在其中添加或删除字符时,并不会产生新的StringBuffer对象。\n\n针对添加和删除字符的操作,StringBuffer类提供了一系列的方法,具体如下表所示。
代码
结果
JDK7新特性
JDK 7(Java SE 7)在Java语言中引入了一些新特性,以下是其中的一些:
1.String在switch中可用:在Java SE 7之前,在switch语句中只允许使用数字和枚举类型的常量。但是,在Java SE 7中,我们可以使用字符串(String)作为开关变量。
2.自动资源管理:Java SE 7引入了try-with-resources语句,它是一种保证实现了必要释放资源的try语句的简化写法。在try代码块中初始化的资源(如文件流)将在try块退出时自动关闭。这种机制可以帮助程序员避免资源泄漏问题,使代码更加简洁。
3.数字字面量增强:在Java SE 7中,我们可以使用下划线来分隔数字字面量,使其更易读。例如,我们可以使用1_000_000表示一百万。
4.泛型实例化类型自动推断:在Java SE 7之前,当我们创建一个泛型实例时,必须明确地提供类型参数。但是现在,我们可以让编译器根据左侧的引用变量自动推断类型,从而使代码更加简洁。
5.异常多重捕获:在Java SE 7中,我们可以使用管道符(|)来捕获多个异常类型,这使得代码更加简洁。
6.Fork/Join框架:Java SE 7引入了Fork/Join框架,它是一种用于在多个处理器上并行执行任务的框架。它提供了一种简单的编程模型,可以让开发者更容易地实现并行算法和任务。
7.NIO 2.0:Java SE 7引入了NIO 2.0,它提供了更加强大和灵活的文件系统API。新的API支持异步IO和文件锁定等功能,提供了更高效和可伸缩的IO操作。
8.G1垃圾回收器:Java SE 7引入了G1垃圾回收器,它是一种可预测的垃圾回收器,可以在多处理器和大内存环境中提高性能。
9.增强的Java安全性:Java SE 7引入了许多新的安全性特性,如增强的XML处理器、增强的启动类加载器和支持加密协议的JSSE等。这些功能为Java应用程序提供了更高的安全性。