异常和集合
异常
throw
异常就是当程序执行到一段代码,发生异常后,就new
一个对应的类的对象,这个类是一个异常类,如:NullPointerException
和NumberFormatException
,然后throw
或者catch
,throw
就是抛出一个异常,和return
对比。
throw | return |
---|---|
异常退出 | 正常退出 |
throw后执行的代码不定,看异常处理机制动态决定 | 返回位置确定:上一级调用者 |
try/catch
1 | System.out.println("请输入一个数字"); |
如果在try内跑出来异常,可以由catch来捕获,捕获后程序还会继续运行而不会退出,只是try后续的代码不会执行。
异常类体系(记下来)
Throwable是所有异常类的基类,他有两个子类Error和Exception。
Error表示系统错误或资源耗尽,应用程序不抛出或处理,虚拟机错误及其子类,内存溢出错误和栈溢出错误。Error及子类都是未受检异常。
Exception中有很多子类,也可以继承Exception自定义异常,其中列出来数据库异常,IO异常,和运行时异常(未受检异常)受检异常不能通过编译。
异常 | 说明 |
---|---|
NullPointerException |
空指针异常 |
IllegalStateException |
非法状态 |
ClassCastException |
非法强制类型转换 |
IllegalArgumentException |
参数错误 |
异常 | 说明 |
---|---|
NumberFormatException |
数字格式错误 |
IndexOutOfBoundsException |
索引越界 |
ArrayIndexOutOfBoundsException |
数组索引越界 |
StringIndexOutOfBoundsException |
字符串索引越界 |
这些异常大部分只是定义了几个父类的构造函数。
自定义异常
然后自定义异常继承的RuntimeException或他的某个子类,则自定义异常也是未受检异常;如果继承的是Exception和Exception其他子类,则自定义异常是受检异常。
1 | public class AppException extends Exception { |
异常处理
异常处理包括catch、throw、finally、try-with-resources和throws
catch匹配
1 | try{ |
上方异常要是下方异常的子类,java7开始支持一种新语法
1 | try{ |
throw和finally
处理完异常之后,可以通过throw抛出异常给上一层,可以是原来的异常,也可以是新异常。
finally内代码,无论有无异常发生都会执行。
如果没有异常发生,try执行后执行finally
如果有异常被catch,catch执行后执行finally
如果有异常发生但没被catch,在异常被抛出前执行finally
注意:如果try或catch中有return时,也会先执行完finally中的代码再去执行return;如果finally内有return或抛出异常,则会覆盖掉catch和try中的return和异常。
try-with-resources
finally一般用于释放资源,java7之前要实现AutoCloseable接口之后,在finally中调用close()
方法,代码如
1 | public interface AutoCloseable { |
java7支持了一种新语法,在执行完try语句之后自动执行close()
方法。
1 | public static void useResource() throws Exception { |
throws
throws跟在方法后面,可以声明多个异常,以逗号分隔。表示:这个方法可能会抛出这些异常,且没有处理或者没有处理完,调用者必须进行处理。
集合
Collection
1 | //添加 |
List
存取有序,有索引,元素可重复
ArrayList(增删慢,改查快)
底层是数组
默认参数化容量是10,每次扩容为原先容量的1.5倍
增删时,用数组拷贝复制
删除元素时不会减少容量,若希望减少容量则调用trimToSize()
Linkedlist(改查慢,增删快)
底层是双向链表【双向列表便于实现往前遍历】
Vector
底层是数组,基本被ArrayList代替,原因如下:
所有方法都是同步的,有性能损失。
初始长度是10,超过后以100%增长,相比ArrayList更消耗内存
对比
ArrayList的增删慢并不是绝对的
如果增加的一直是add()增加到末尾的话
一直删除末尾的元素
如果删除中间位置的元素,还是ArrayList快
但是一般来说:增删多还是用LinkedList
Set
存取无序,元素不可重复,set也是Collection的子接口
可以使用迭代器
可以使用增强for
不能使用索引
HashSet(数组+链表+红黑树)
原则参考HashMap
实现了Set接口
实际上是HashMap
可以存放一个null
不能重复,存取无序
LinkedHashSet
LinkedHashSet继承了HashSet,底层是一个LinkedHashMap,底层维护了一个双向链表。每一个节点都有before和after属性,添加元素的原则和hashset一样
Map
map和collection并列,用于保存有映射关系的数据:ket-value
key和value可以是任何引用类型的数据,会被封装到HashMap$Node对象中
key值不可以重复,value可以重复
key值只能有一个null,value可以有多个null
常用String类作为Map的key
添加相同的key,相当于修改value
Map的遍历
1.通过set取出所有的key,然后通过for进行遍历
1 | Set keyset = map.Keyset(); |
2.迭代器
1 | Iterator iterator = keyset.iterator(); |
3.4.同1、2取出value
5.通过EntrySet
1 | Set entryset = map.entrySet(); |
HashMap(数组+链表+红黑树)
数组用来存储元素数据,链表解决冲突,红黑树提高查询效率。
如果链表长度>8&数组大小≥64,链表转为红黑树
红黑树节点数<6,转为链表
put的过程:
哈希值为32位int类型,计算的新哈希值是16高位和16低位异或,然后对数组长度(初始16)取模,取模的方法是和15进行&操作,直接保留后几位二进制数。
如果传入的不是2 的整数次方时,则向上找到2的整数次方大小,比如传入17是应该找到32。
哈希函数的构造方法:除留取余法、直接定址法、数字分析法、平方取中法、折叠法
扩容要rehash,十分耗时,为什么扩容因子取0.75?如果取得比较大,元素很多空位很少才扩容,那么发生哈希冲突的概率就增大了,查找的时间成本增加。如果设置比较小,查找时间成本降低,但是需要更多的空间,空间成本增加了。
HashTable
hashtable和hashmap的使用方法基本一样,他是线程安全的,但键和值都不能为null
线程安全 | 效率 | 运行null键null值 | |
---|---|---|---|
HashMap | 不安全 | 高 | 可以 |
Hashtable | 安全 | 较低 | 不可以 |
Properties
使用特点和Hashtable类似,properties还可以用于从xxx.properties文件中加载数据到properties对象进行读取和修改,xxx.properties文件通常作为配置文件
总结
1.先判断存储的类型(单列或双列)
2.单列:collection接口
允许重复:List
增删多:LinkedList
改查多:ArrayList
不允许重复:Set
无序:hashset
排序:TreeSet
插入和取出顺序一致:LinkedHashSet
3.双列:Map
键无序:HashMap
键排序:TreeMap
键插入和取出顺序一致:LinkedHashMap
读取文件Properties