异常
异常:
即程序在运行过程中,没有按照自己的预先想法输出结果所产生的特殊情况。如:除数为0时候 产生的ArithmeticException异常。
Java中的异常就是用来处理程序中发生不可控或者错误情况的机制。当我们希望错误被我们处理而不是直接中断程序的时候,就需要使用到异常
异常处理有2种方式
-
捕获
当java运行出错时,把错误捕找到,交给能处理当前错误的对象进行处理的行为就是捕获
-
抛出
当java运行过程中,产生一个异常对象,该对象包含了当前错误的信息。把这一对象提交给调用的对象 的行为就是抛出。
Error:称为错误,由Java虚拟机生成并抛出,包括动态链接失败、虚拟机错误等,程序对其不做处理。Error 类层 次描述了 Java 运行时系统内部错误和资源耗尽错误。这类错误是我们无法控制的,所以在编程中,不去处理这类错误。Error 表明系统 JVM 已经处于不可恢复的崩溃状态中。我们不需要管他。 如内存溢出。
Exception:所有异常的父类,其子类对应了各种各样可能出现的异常事件,一般需要用户抛出或捕获。
RuntimeException:运行时异常,Java中几乎所有的运行时候可能出错的异常类都直接或者间接的继承自这个类。
这类异常推荐优化代码来解决,而不推荐使用异常处理机制。有助于提高自己考虑问题的全面性和编程能力。
如
- NullPointerException: 当程序访问只有引用没有对象的成员属性或成员方法。
- ArithmeticException: 除数为 0
- ArrayIndexOutOfBoundsException: 访问的元素下表超过数组长度
都是依靠代码可以避免的异常
CheckException:凡是继承自Exception,但不继承RuntimeException的异常都是此类异常。此类异常必须处理,否则无法通过编译。此类异常通常不是自身产生的,而是外界带来的原因。比如反射类时 产生ClassNotFoundExcetion.。通常是该类不存在。
异常的产生
异常通常是程序员手动产生,或者是系统自己产生。
public static void main(String[] args) throws MyException {
throw new MyException("");
}
此段代码就在方法中手动生成了一个异常。
异常的处理
对于检查时异常,我们一开始就必须将他处理。处理的方式有以下两种
1、捕获异常
try{
//可能产生异常的代码
//可能产生异常的代码
//可能产生异常的代码
}catch(//异常的类型 e){
//处理异常的方式。
}catch(//异常的类型 e){
//处理异常的方式。
}catch(//异常的类型 e){
//处理异常的方式。
}finally{
//不管有没有发生异常。这段代码都会被执行
}
try中用来包裹可能发生异常的代码的范围,只要中间某一处发生错误,那么try中那段代码之后的代码都不会被执行。如果没发生异常所有的catch
try{
System.out.println("111");
System.out.println("111");
int a =1/0; //这里会产生ArithMeticException异常
System.out.println("111");//这里的代码就不会被执行到
System.out.println("111");
}catch(ArithMeticException e){ //会直接跳到这里
}
catch
在catch中声明的异常对象封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息。
常用方法
getMessage()方法,用来得到有关异常事件的信息
printStackTrace()方法,用来跟踪异常事件发生时执行堆栈的内容
finally
是异常块的统一出口,能在流程跳转到别的方法之前,对程序的状态做统一的管理。无论try中是否发生异常,都会执行。就算前面发生return 了也会执行。try 或catch中的return会被暂存,执行完finally的语句才会执行。
通常用来清理状态。
如关闭流,删除临时文件。
注意
try代码段后跟有一个或多个catch代码段
每个catch代码段声明其能处理的一种特定类型的异常并提供处理的方法
当异常发生时,程序会中止当前的流程,根据获取异常的类型去执行相应的catch代码段
一个 try 后面可以跟多个 catch(用于处理可能产生的 不同类型的异常对象),但不管多少个, 最多只会有一个catch 块被执行(因为出现一个异常就会跳出到catch)。
finally段的代码无论是否发生异常都有执行
catch的顺序最好是从小到大,父类放最下。
2、往外抛异常
public void test() throws Exception{
//可能发生异常的代码
//异常发生 后面的代码就不会执行,和try一样。只是整个方法体都被try包裹。
}
在可能产生异常的方法后面加上throws +【异常类型】将异常抛出到外面上一层(交给上一层处理)。
子类重写父类方法的时候,如果父类有异常抛出,则子类的异常抛出不能大于父类(必须是父类异常或者父类异常的子类)。
抛出多个异常用 , 连接
自定义异常
指的是定义一个类,去继承Exception类或者其子类。一般直接继承Exception类。
class MyException extends Exception{
public MyException(){
super();
}
public MyException(String s){
super(s);
}
}
通过new 来产生异常类。并用throw来抛出异常。抛出后需要处理该异常,处理方式同上。
数组
数组就是将数据类型相同的元素按照一定的顺序进行排列(一类数据的集合)。这组数据共用一个变量名称,按编号进行区分。变量名称为数组名,编号称为数组下标。数组是一个对象。数组可分为一维数组,二维数组。
特点:
1、其长度是一定的,数组在进行创建时候就必须指明长度,并且大小都是不可改变的。但是其值可以改变。
2、其元素必须是相同类型,不允许出现混合类型
3、数组中的元素可以是任何数据类型,包括基本类型和引用类型。
4、数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。
5、数组开辟的是连续的空间,如果定义数量太大会报错。
一维数组的创建
数组的声明
int[] a;// 声明数组方式一
int a[]; //声明数组方式二
声明时候并没有实例化数组。只是声明了一个数组变量。
数组的构建
语法:【数组类型】 [] 【变量名】 = new 【数组类型】[【数组长度】] ;
int [] array = new int[10]; //必须指明数组长度,此例为int类型。(默认初始化)
int [] array = new int[]{1,2,3};//后面跟元素列表,元素列表决定数组的长度。(静态初始化)
int [] array = {1,2,3}; //定义元素列表的简写方式。
数组构建后,因为每个编号的位置可以看成是对象的成员,所以都会有一个初始值,数值类型是0,引用类型是null,char类型是\u0000;
数组的遍历
1、普通for循环
int [] arrays = new int[10]; //此时length属性值为10;
for(int i=0;i<arrays.length;i++){ //数组对象属性length为当前数组长度。
System.out.println(arrays[i]); //通过数组[下标值] 来访问下标对应元素。
}
2、增强for循环
增强for循环语法
for(【集合存储的单个类型】 【变量】 : 【需要遍历的集合】 ){
// 【变量】 ——变量指代的就是当前集合中的元素,会从第一个位置开始遍历到最后一个。
}
int [] arrays = new int[10];
for(int i:arrays){
//i指代的是arrays中的元素。从第一位遍历,
System.out.println(i);
}
缺点:丢失了下标索引信息,因此操作数据比较麻烦,适合遍历查看,不适合修改。
数组的界限
1、数组必须开辟出空间才可以使用,否则容易发生NullPointerException异常。
2、索引的范围 [0,length) 闭区间,[0]的时候创建对象,但是并没有空间。长度为0
3、范围定义为-1或者以下的时候,编译通过,运行错误java.lang.NegativeArraySizeException异常
数组的常用方法属性
1、length属性
每个数组都有一个length属性,表示数组的长度。length是只读的,并且是final属性,一旦创建了
就不能修改。
2、equals()方法 比较两个数组
数组本身继承了object类的equals方法,但是他并没有重写equals方法
public boolean equals(Object obj) {
return (this == obj);
}
我们一般使用Arrays这个数组工具类的方法。
传入2个参数 ,为互相比较的数组。
以下是equals()源码
public static boolean equals(int[] a, int[] a2) {
if (a==a2) //如果是同一个对象 直接返回true
return true;
if (a==null || a2==null) //如果有一个对象是空,直接false
return false;
int length = a.length; //比较两个数组的长度,
if (a2.length != length)//不一样长直接false
return false;
for (int i=0; i<length; i++)
if (a[i] != a2[i])//遍历比较两个元素。
return false;
return true;
}
使用 Arrays.equals(【数组1】,【数组2】); 返回值为Boolean
3、**Arrays.sort();**排序
//源码
public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}
//使用
int [] b = new int []{123,22,45,65,33};
Arrays.sort(b);
改变的是原数组。并没有返回值。默认从小到大的顺序。如果想从大到小排序需要重写Comparator接口的compare方法
Comparator<Integer> com = new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
};
这样只能排序Integer类型的数组。其他数组改变泛型。
4、Arrays.binarySearch(数组,元素) 二分法查找元素
条件:数组必须从小到大排序好才能进行二分法查找元素
如果存在,则返回数组下标,如果不存在,则返回二分法算法后的负值。
如果查询的值存在两个重复的元素,则返回较小的下标。
Integer [] b = new Integer []{123,22,45,65,33};
Arrays.sort(b);//必须从小到大排序好
int c= Arrays.binarySearch(b,66); //第一个参数为目标数组,第二个为要查的元素值
5、数组拷贝
两种方式
1、Arrays. copyOf(源数组,长度) ;
Integer [] b = new Integer []{123,22,45,65,33,33};
Integer[] g = Arrays.copyOf(b, 10);
可以用来进行数组扩容。参数2指定的长度大于原数组长度则后面的值为类型初始化值
如果小于则copy指定长度。从0开始拷贝。
Arrays.copyOfRange(原数组,起始位置,结束位置) 可以拷贝指定位置的数组 。左闭右开区间。
2、void System.arraycopy(源数组,源起始索引,目标数组,目标起始索引,长度)
//定义好新数组再进行copy。
二维数组
本质上是一个元素为一维数组的数组,数组里面存储的还是数组。
初始化
行数必须指定,列数随意。
1、int[][] arr = {{},{},{}};相当于定义了一个3行 0列的数组。
2、int[][] arrs = new int[3][]; 必须给定高纬数字。后面的可以使用时候进行创建。此时相当于定义了一个3个空间的数组用来存储数组,但是里面的内容只声明为数组并没有进行初始化。
arrs[1] = new int[100]; 这样初始化第二维度。
3、int[][] arr2 = new int[2][3]; 直接指定行数和列数。都固定死。
使用方式参考一维数组。