异常处理
基本概念
异常(exception) :是指在硬件和操作系统正常时,程序遇到的运行错误。如数组下标越界、除数为0、用户输入非法、打开一个不存在的文件、网络连接中断、正在加载的类文件丢失等都会引发异常。异常会导致程序非正常终止。Java中不同的异常用不同的异常类来表示。当程序运行过程中发生一个可识别的异常时,系统会产生一个相应的异常类对象,即产生一个异常。 在“异常”类层次上的最上层有一个单独的类叫做Throwable,它是java.lang包中的一个类。它派生了两个子类:Error类和Exception类。 Error类 :定义了程序中不能恢复的严重错误。如内存溢出、类文件格式错误等。这一类错误由Java运行系统处理,不需要编程者处理。Exception类 :定义了程序中可能遇到的轻微错误。可以写代码来捕捉和处理这些异常。由它派生出很多子类,每个子类代表了一种运行错误。 自动捕获和处理异常:把可能产生异常的代码用try包起来,try之后,通过catch来捕捉异常并处理。
处理过程
Java程序在执行过程中如出现异常,系统会自动生成一个异常类对象,该异常对象将被提交给Java系统,这个过程称为抛出(throw )异常。 当Java系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch )异常。 如果Java系统找不到可以捕获异常的方法,则系统将自动做一些处理,并中止程序。 使用try-catch-finally语句 捕获和处理异常:
try
{ 要检查的语句序列 ;
}
catch ( 异常类名 形参对象名)
{ 异常发生时的处理语句序列;
}
finally
{ 一定会运行的语句序列
}
public static void main ( String args[ ] ) { int i= 0 ; String greetings [ ] = { "Hello world!" , "No,I mean it!" , "HELLO WORLD!!" } ; while ( i< 4 ) { try { System . out. println ( greetings[ i] ) ; } catch ( ArrayIndexOutOfBoundsException e) { System . out. println ( "Re-setting Index Value" ) ; } finally { System . out. println ( “This is always printed”) ; } i++ ;
}
异常处理有两种方法 : 如果知道如何处理异常,则用try-catch语句捕获异常并处理它。 如果在一个方法中,有的异常不知如何处理或不想处理,可将异常抛出到其上一级,即调用它的方法。上一级的方法必须处理:捕获或继续抛出到更上一级。一直可追溯到main()方法。最后抛给系统,由系统处理。 抛出异常的两种方式 : 系统自动抛出的异常:所有RuntimeException由系统自动地抛出。 throw语句抛出的异常:除了RuntimeException外的其他异常,以及用户自定义的异常,不可能依靠系统自动抛出,必须用throw语句明确地抛出一个异常。 异常抛出 使用throws
关键字抛出异常:throws关键字通常被应用在声明方法时,用来指定方法可能抛出的异常。多个异常可使用逗号分开 。 使用throw
关键字抛出异常:throw关键字通过用于方法体中,并且抛出一个异常对象 。程序在执行到throw语句时立即终止,它后面的语句都不执行。
void MyMethod ( ) throws Exception1 , Exception2 , Exception3
{
}
void MyMethod ( ) throws Super_Exception
{
}
public static void main ( String [ ] args) { try { throw new MyException ( "This is a custom exception" ) ; } catch ( MyException e) { System . out. println ( e. getMessage ( ) ) ; }
}
自定义异常类:因为所有的异常类均继承自Exception类,所以自定义类通常继承这个类。用户自定义异常必须用throw来抛出。
class 自定义异常类名 extends Exception
{ 类体
}
Java泛型与容器类
泛型
实质就是将数据的类型参数化(即数据的类型可变),通过为类、接口及方法设置类型参数来定义泛型。 泛型类的定义:[修饰符] class 类名<T>
泛型接口的定义:[public] interface 接口名<T>
泛型方法的定义:[public] [static] <T> 返回值类型 方法名(T 参数)
要实例化泛型类对象,也使用new运算符,但在类名后面需加上要传递的具体类型 。泛型类生成对象时,实际类型必须是引用类型(String
、Integer
、Double
等),不能是int、double、char等基本类型。 当我们定义一个方法,希望它能遍历各种类型的ArrayList(泛型类)集合。我们不知道ArrayList集合使用什么数据类型,此时可以使用泛型通配符"?" 来接收各种不同的数据类型。 限制泛型的可用类型: 上界用extends指定,例如: List<? extends Number>
下界用super指定,例如:List<? super Integer>
public class Node < T > { private T data; public Node ( ) { } public Node ( T data) { this . data = data; } public T getData ( ) { return data; } public void setData ( T data) { this . data = data; } public void showType ( ) { System . out. println ( "T的类型是:" + data. getClass ( ) . getName ( ) ) ; }
}
var intNode = new Node < Integer > ( ) ;
public interface Entry < K , V > { public K getKey ( ) ; public V getValue ( ) ;
} public class Pair < K , V > implements Entry < K , V > { private K key; private V value; public Pair ( K key, V value) { this . key = key; this . value = value; } public void setKey ( K key) { this . key = key; } public K getKey ( ) { return key; } public void setValue ( V value) { this . value = value; } public V getValue ( ) { return value; }
}
var p1 = new Pair < Integer , String > ( 20 , “twenty”) ;
var p2 = new Pair < String , String > ( “china”, “Beijing ”) ;
public static < T > void swap ( T [ ] array, int i, int j) { T temp = array[ i] ; array[ i] = array[ j] ; array[ j] = temp;
}
public static void printList ( ArrayList < ? > list)
{ System . out. println ( list) ;
} ArrayList < String > list1 = new ArrayList ( ) ;
list1. add ( "123" ) ;
list1. add ( "abc" ) ; ArrayList < Integer > list2 = new ArrayList ( ) ;
list2. add ( 123 ) ;
list2. add ( 456 ) ; printList ( list1) ;
printList ( list2) ;
容器类
容器类是Java以类库的形式 提供给用户开发程序时可直接使用的各种数据结构 。 Java提供了一个容器框架,也叫集合框架(Collections Framework),其中包含了一组接口和类,可以很方便地对一组对象进行操作。 常用的类型参数名有:E表示元素;K表示键;N表示数字;T表示类型;V表示值等。 容器框架由两种类型构成: Collection ,用于存放一组对象。包含有List、Set、Queue。Set:不能包含重复的元素。SortedSet是一个按照升序排列元素的Set。List:是一个有序的集合,可以包含重复的元素。提供了按索引访问的方式。Map ,用于存放一组“关键字/值 对”的对象。包含了key-value对。Map不能包含重复的key。SortedMap是一个按照升序排列key的Map。 ArrayList :即顺序表。我们可以将其看作是能够自动增长容量的数组。利用ArrayList的toArray()
返回一个数组,利用Arrays.asList()
返回一个列表。常用方法: void add(int index, E element)
E get(int index)
E set(int index, E element)
E remove(int index)
size()
java.util.Iterator接口(迭代器)的功能:对集合进行遍历。主要有以下三个方法: boolean hasNext()
:判断是否有下一个元素E next()
:返回下一个元素void remove()
:删除最近一个next()所返回的元素 Collection接口中有一个iterator()方法,该方法返回的就是迭代器的实现类对象。 迭代器的使用步骤: 调用集合对象的iterator()方法获取Iterator对象,即迭代器的实现类对象,使用Iterator接口接收(多态)。 使用Iterator接口中的hasNext()方法判断还有没有下一个元素。 使用Iterator接口中的next()方法取出集合中的下一个元素。 Collections类 :java.util .Collections类是工具类,该类中的所有方法都是static的。Collections.sort()
的实现方法: 实现Comparable接口中的compareTo()方法。按compareTo()方法进行的排序叫自然排序。 实现比较器(Comparator)接口,把比较器跟某个类相关联。 Comparable接口 : 如果一个类实现了Comparable接口(需要重写compareTo方法),则该类支持排序。 如果一个List或者一个数组中的对象是实现了Comparable接口的类,则可以通过Collections.sort()或者Arrays.sort()来对该列表或数组进行排序。 ArrayList和LinkedList(链表类)的比较:LinkedList是采用双向循环链表实现的。 ArrayList底层采用数组完成,而LinkedList则是以一般的双向链表(double-linked list)完成,其内每个对象除了数据本身外,还有两个 引用,分别指向前一个元素和后一个元素。 如果我们经常在List的开始处增加元素,或者在List中进行插入和删除操作,我们应该使用LinkedList,否则的话,使用ArrayList将更加快速。 Set接口及实现类: Set接口实现类的对象类似于数学上的集合概念,其中不允许有重复的元素。 Set接口没有定义新的方法,只包含从Collection接口继承的方法。 Set接口的常用实现类有:HashSet类、TreeSet类。 散列存储的基本思想:把线性表中每个元素的关键字值与存放该元素的地址(数组下标值)之间建立起一个函数关系h。 散列表又称为哈希表 。散列表算法的基本思想是:以结点的关键字为自变量,通过一定的函数关系(散列函数)计算出对应的函数值,以这个值作为该结点存储在散列表中的地址。HashSet类用散列方法存储元素,具有最好的存取性能,但元素没有顺序。TreeSet实现一种树集合,它使用红-黑树算法为元素排序。添加到TreeSet中的元素必须是可比较的,即元素的类必须实现Comparable<T>
接口。 Map接口及实现类: Map是用来存储“键/值”对的对象,也称为“映射”。 在Map中存储的关键字和值都必须是对象,并要求关键字是唯一的,而值可以重复。 HashMap类以散列方法存放“键/值”对,TreeMap类保证Map中的“键/值”对按关键字(key)升序排序。