Java基础笔记5——异常、集合

Java基础笔记5
九、异常
异常的顶级父类:Throwable
异常子类——Error:错误。一旦出现,无法处理。
StackOverflowError堆栈溢出错误
OutOfMemoryError内存溢出错误
异常子类——Exception:异常。出现之后可以处理。
①编译时异常Exception,必须处理。(也叫已检查异常)
②运行时异常RunTimeException,可以处理也可以不处理。(也叫未检查异常)
处理异常方式:
1.try catch捕获异常
2.throws抛出异常
异常是java中一套反馈和处理问题的机制。
一个方法的运行过程如果出现了异常,这个方法就会产生代表该异常的一个对象,把它交给运行时系统,运行时系统寻找相应的代码来处理这一异常。
生成异常对象并把它交给运行时系统的过程称为抛出throw。
运行时系统在方法的调用栈中查找,直到找到能处理该异常的对象的过程称为捕获catch。
异常机制关键字:throw、throws、try、catch、finally。
try语句不能独立存在,要紧跟catch语句或finally语句。
try{
可能会出现异常的语句
}catch(可能会出现的异常的类型 引用类型变量){
处理语句 //有异常才会执行,无异常时跳过
}
注意:在try语句里出现异常则跳过余下try语句执行catch语句,catch语句执行完后往下执行,不会再返回执行try语句里未执行的部分。
自定义异常:如果继承的是Exception或者是其他子类,那么这个异常就是一个编译时异常;如果继承的是RuntimeException或者是其子类,那么这个异常就是一个运行时异常。
例如定义PathNotExistException路径不存在异常
异常的捕获方式:

  1. 如果多个异常的处理方式各不一样,那么多个catch分别捕获分别处理
  2. 如果多个异常的处理方式都一样,那么捕获这些异常的父类进行统一的处理
  3. 如果多个异常分了不同的组进行处理,那么同一组之间的异常可以用 | 隔开用一个catch来捕获处理 — JDK1.7开始
    注意:1.在catch异常的表达式里,必须小异常写在前,大异常写在后。
    2.捕获异常的对象里必须有抛出异常对象。
    运行时异常可以随意抛出随意捕获,编译时异常必须抛出后才能捕获。
    异常抛出后,后续代码无法继续执行,除非捕获处理完异常。
    printStackTrace():打印异常栈轨迹。倒着看异常信息。
    finally语句块:无论异常处理成功与否,都会执行一次。
    项目开发阶段→出现异常:打印异常栈轨迹,处理异常。
    项目上线阶段→出现异常:记录错误日志,跳转错误页面。
    方法体里throw new Exception,那么方法上必须写throws Exception。RuntimeException例外。
    e.toString()获取的信息包括异常类型和异常详细消息,而e.getMessage()只是获取了异常原因的详细消息字符串。
    十、集合
    存储数据的容器:变量、数组、集合
    集合是一个能够存储多个数据的容器,大小不固定。
    集合已经重写了ToString方法,打印集合对象时直接输出集合里面的元素。
    集合存储的都是引用类型元素,并且集合只保存每个元素对象的引用,并非将元素对象本身存入集合。

Collection
collection是集合的顶级接口。
不能实例化。
E——泛型,用于规定存储元素类型。泛型的类型只能使用引用类型/包装类型(例如:Integer),不能使用基本类型(例如:int)。
由于泛型的限定。集合只能存储对象。
int[] arr:数据类型是数组,元素类型是int。
Collect:数据类型是集合,元素类型是int。
Collect<int[]> c:集合也可以存储数组
方法摘要
返回值类型 方法说明
 boolean add(E e) 确保此 collection 包含指定的元素(可选操作)。
 boolean addAll(Collection<? extends E> c)  将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
 void clear()   移除此 collection 中的所有元素(可选操作)。
 boolean contains(Object o)  如果此 collection 包含指定的元素,则返回 true。
 boolean containsAll(Collection<?> c)
 如果此 collection 包含指定 collection 中的所有元素,则返回 true。
 boolean equals(Object o) 比较此 collection 与指定对象是否相等。
 int hashCode() 返回此 collection 的哈希码值。
 boolean isEmpty()  如果此 collection 不包含元素,则返回 true。
 Iterator iterator()  返回在此 collection 的元素上进行迭代的迭代器。
 boolean remove(Object o)  从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
 boolean removeAll(Collection<?> c)    移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
 boolean retainAll(Collection<?> c)
    仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
 int size()   返回此 collection 中的元素数。
 Object[] toArray()  返回包含此 collection 中所有元素的数组。
T[]
toArray(T[] a)  返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。
int size() 返回: 此 collection 中的元素数
Object类型的数组不能强转为String类型
List列表
是一个接口,不能实例化,需要实现类。
Collection c = new ArrayList();//等号前面是声明类,等号后面是实现类。
元素有序——保证元素的存入顺序,可对元素进行编号——下标从0开始。
里面存储的元素可以重复。
add():添加(指定下标)元素
set():替换(指定下标)元素
get():获取指定下标元素
indexOf():返回指定元素的下标
move():移除指定(下标)元素
equal():逐位比较元素是否一样
clear():清空所有元素
isEmpty():判断列表是否为空
size():获取元素个数

注意:修改截取出来的集合(例:subList),会影响到原集合list。反之亦然~本质上子集合是原集合的一部分。
ArrayList ——顺序表——实现类
底层以数组形式存储,初始容量为10的空列表。
每次扩容是在原来的基础上增加一半。10→15→22→33→49
容量有限,数组列表的最大容量231-9=2147483639,耗费2GB内存。
特点:①内存空间连续。②增删操作相对复杂,查询相对简单。③线程不安全。
trimToSize():将ArrayList实例的容量调整为列表的当前大小。
 Object[] toArray()
    返回按适当顺序包含列表中的所有元素的数组(从第一个元素到最后一个元素)。
T[]
toArray(T[] a)
          返回按适当顺序(从第一个元素到最后一个元素)包含列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。
Object[] o = c.toArray(); //将集合c转化成数组o
String[] s = c.toArray(new String[0]); //传入0个元素的数组作为参数
// 传入一个和集合元素长度一致的数组——最优做法,只产生一个新的数组对象
String[] s = list.toArray(new String[list.size()]);
Arrays类中提供了一个静态方法asList,使用该方法我们可以将数组转换为对应的List集合。转换后的集合只提供了get、set、size、indexOf的基本方法,不支持remove、add之类的方法。
方法定义为staticListasList(T…a)
List list=Arrays.asList(str);
返回的List的集合元素类型有传入的数组的元素类型决定。
注意:返回的集合不能增删元素,否则会抛出异常,并且对集合的元素进行修改会影响到数组对应的元素。
ArrayList使用remove删除元素常见的问题——
1.无法用for循环遍历删除所有集合元素

  • 通过for循环的方法无法删完集合所有元素,因为每删掉一个元素,后面的元素会往前挪一位,
  • 元素的下标会发现改变,导致无法遍历完所有元素。
  • 如下例,删掉下标为0的元素“You”,结果原本下标为1的元素“are”向前挪了一位,变为下标0
  • 继续遍历删除下一个元素,新下标为1的元素“the”被删除,下一位元素“best”又向前挪到了下标1的位置
  • 继续遍历删除下一个元素,新下标为2的元素“one”被删除
    ArrayList list=new ArrayList<>();
    list.add(“You”);
    list.add(“are”);
    list.add(“the”);
    list.add(“best”);
    list.add(“one”);
    System.out.println(list); //[You, are, the, best, one]
    for (int i = 0; i < list.size(); i++) {
    list.remove(i);
    }
    System.out.println(list);//[are, best]
    2.调用集合List的remove方法运行报错
  • Iterator被创建之后会建立一个指向原来对象的单链索引表,这个索引表的内容不会同步改变,
  • 所以当通过集合的remove方法把元素删除后,索引指针往后移动的时候就找不到要迭代的对象了, 所以运行会抛出并发修改异常。
    *调用Iterator的remove方法,删除的是当前迭代对象。
    Iterator it=list.iterator();//获取迭代器,迭代器不能单独存在,要在集合的基础上创建
    while(it.hasNext()) { //判断是否有下一个元素
    String str=it.next();//挪动指针获取这个元素
    list.remove(str);//运行出错,抛出并发修改异常
    3.正确做法:利用Iterator里的remove方法删除集合所有元素
    将list.remove(str)改为it.remove()
    如何让数组转换后集合实现正常集合的功能呢?
    step1:新建一个集合对象
    List list=new ArrayList();
    step2:asList转换后的集合利用addAll()方法传入这个新集合
    list.addAll(Arrays.asList(str));
    LinkedList——链表——实现类
    底层基于链表(节点)来实现。
    初始容量为0。
    特点:①内存空间不连续。②增删元素相对简单,查找元素相对复杂。③线程不安全。
    在增删和查询操作频率相差不大的情况下,优先选择LinkedList,节省内存空间。
    当增删的位置靠前时,链表效率高;
    当增删的位置靠后时,顺序表效率高;
    整体而言,链表效率稍高。

Vector——向量——实现类
最早的集合,从JDK1.0开始。
底层基于数组。
默认初始容量10,每次扩容默认增加一倍(底层基于三元运算),可以指定初始容量及扩容大小。
内存空间连续。
增删相对复杂,查询相对简单。
capacity():获取容量(专属Vector的方法)
缺点:有很多功能重复的方法。
优点:是一个线程安全的集合。
Enumeration迭代器
无法通过迭代遍历的方法清空集合。
Vector v = new Vector(7); //创建一个向量集合
v.add(“d”); //添加元素
v.add(“e”);
v.add(“s”);
Enumeration e = v.elements(); // 获取迭代器
while (e.hasMoreElements()) { // 判断后续是否有更多的元素
String str = e.nextElement();// 挪动指针获取元素
System.out.println(str);
}
Stack——栈
继承了Vector。元素有序。
特点:遵循先进后出原则。
最先放入的元素——栈底元素,最后放入的元素——栈顶元素。
向栈中放入元素——入栈/压栈push(),向栈中取出元素——出栈/弹栈pop():取出栈顶元素。
isEmpty():判断栈是否为空。
peek():获取而不移除栈顶元素。(在没有元素的情况下会出现EmptyStackException空栈异常)
search():从栈顶到栈底依次查找元素,输出下标。
Queue——队列——接口
队列通常(但并非一定)以 FIFO(先进先出)的方式排序各个元素。不过优先级队列和 LIFO 队列(或堆栈)例外,前者根据提供的比较器或元素的自然顺序对元素进行排序,后者按 LIFO(后进先出)的方式对元素进行排序。
常用实现类:LinkedList
方法摘要
 boolean add(E e)
          将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。
 E element()
          获取,但是不移除此队列的头。
 boolean offer(E e)
          将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。
 E peek()
          获取但不移除此队列的头;如果此队列为空,则返回 null。
 E poll()
          获取并移除此队列的头,如果此队列为空,则返回 null。
 E remove()
          获取并移除此队列的头。
从接口 java.util.Collection 继承的方法
addAll, clear, contains, containsAll, equals, hashCode, isEmpty, iterator, remove, removeAll, retainAll, size, toArray, toArray

Set——接口
不保证集合元素的顺序。

HashSet——实现类
元素存储无序,元素不重复。
是一个线程不安全的集合。
底层基于HashMap存储元素。初始容量16,加载因子0.75f。
HashMap底层基于数组+链式栈结构存储元素。
每个位置——桶bucket
使用桶的数量/桶的总数量>加载因子0.75f时扩容,每次增加一倍。将所有的元素重新计算哈希码,重新分布——rehash——目的:减少每个桶中链式栈的长度。
加载因子越小,内存浪费越大,频繁扩容,导致频繁进行rehash。
加载因子越大,内存利用率逐渐提高,但是就意味着每一个桶中的链的长度会越长,会导致增删以及查询的效率变低。
加载因子为1,意味着用不扩容。
add()相同元素,新元素会被抛弃,保留原有元素。
LinkedhashSet——HashSet的子类
此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。
TreeSet
存放元素的时候会对元素进行自然排序——升序。
要求存储元素的类必须实现Comparable接口。
比较器
Comparable——如果对某一个类的素有的对象进行统一的排序,实现接口,重写compareTo方法,指定比较规则。
Comparator——如果需要给某一个集合单独执行比较规则,重写compare方法。
迭代器
Iterator——接口
提供了一个iterator()方法类获取一个Iterator对象。
增强for循环本质上是一个迭代遍历的过程。
本质:在遍历集合的时候,是将集合做一个复制,然后在复制过程中对每一个元素进行标记,表示该元素是否存在。
注意:在迭代过程不允许增删元素。
实现这个接口的对象可以实现增强for循环遍历。
增强for循环是JDK 1.5特性之一。
方法摘要
 boolean hasNext()
          如果仍有元素可以迭代,则返回 true。
 E next()
          返回迭代的下一个元素。
 void remove()
          从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

Iterator it=list.iterator();//获取迭代器,迭代器不能单独存在,要集合的基础上创建
while(it.hasNext()) { //判断是否有下一个元素
String str=it.next();//挪动指针获取这个元素
System.out.println(str);
注意:若未定义泛型,则使用方法过程需要强转类型。
Iterator it=list.iterator();//未定义元素类型
while(it.hasNext()) {
String str=(String) it.next();//迭代器默认类型是Object,需要强转为String类型

Enumeration
比较古老的迭代器,现在比较少用。

collections——集合工具类
addAll(Collection<? super T> c, T… elements)
          将所有指定元素添加到指定 collection 中。
copy(List<? super T> dest, List<? extends T> src)
          将所有元素从一个列表复制到另一个列表。
fill(List<? super T> list, T obj)
          使用指定元素替换指定列表中的所有元素。
indexOfSubList(List<?> source, List<?> target)
          返回指定源列表中第一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
lastIndexOfSubList(List<?> source, List<?> target)
          返回指定源列表中最后一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
max(Collection<? extends T> coll)
          根据元素的自然顺序,返回给定 collection 的最大元素。
max(Collection<? extends T> coll, Comparator<? super T> comp)
          根据指定比较器产生的顺序,返回给定 collection 的最大元素。
min(Collection<? extends T> coll)
          根据元素的自然顺序 返回给定 collection 的最小元素。
min(Collection<? extends T> coll, Comparator<? super T> comp)
          根据指定比较器产生的顺序,返回给定 collection 的最小元素。
replaceAll(List list, T oldVal, T newVal)
          使用另一个值替换列表中出现的所有某一指定值。
reverse(List<?> list)
          反转指定列表中元素的顺序。
sort(List list)
          根据元素的自然顺序 对指定列表按升序进行排序。
sort(List list, Comparator<? super T> c)
          根据指定比较器产生的顺序对指定列表进行排序。
swap(List<?> list, int i, int j)
          在指定列表的指定位置处交换元素。
Map<K,V>——映射
K:key键
V:value值
映射不能包含重复的键。
一个键对应一个值——键值对。
Map对象由多个键值对组成。
把每一个键值对看成一个对象,就可以抽取一个代表键值对的接口——Entry——是Map接口中的一个内部接口。每一个Entry对象代表一个键值对。
Map不是集合,是集合框架的一员。
集合框架(Collections Famework)包含的不只是集合,而是包含了数组(部分)、集合、映射以及操作它们的工具类。常见的有:Map、 Arrays、 Collections、 Compare、 Iterator。
put(key,value):添加元素方法。如果键重复,值会被覆盖。
get(key):根据键获取对应的值。如果键值对不存在则返回null,但是返回null并不一定表示这个键不存在。map.put(“key”,null)
containsKey():判断是否包含指定键
containsValue():判断是否包含指定的值
clear():清空元素
equals():判断两个集合包含元素是否相同,不看元素顺序
size():获取键值对个数。被覆盖的元素不计算在内。
values():将映射中所有的值(不包含键)放入一个集合中。
如何遍历一个映射?
方式1:获取所有的键,然后遍历这个键,根据键来获取值。
方式2:直接获取所有的键值对(Entry对象),从Entry对象中获取键和值。
keySet():获取所有的键——将所有的键放到一个set集合中
entrySet():返回此映射中包含的映射关系的 Set 集合。
Map.Entry<K,V> :映射项(键-值对)。代表键值对的接口。
getKey():获取键值对应的键
getValue():获取键值对应的值
如何遍历Map集合?
1.获取到所有的键 — 将所有的键放到一个Set集合中
Set keys = map.keySet();
for (String key : keys) {
System.out.println(key + “:” + map.get(key));
}

2.直接获取所有的键值对
Set中放的是键值对,所以元素类型是键值对类型 — Map.Entry
方法(1): Set<Map.Entry<String, Integer>> entrys = map.entrySet();
for (Map.Entry<String, Integer> entry : entrys) {
System.out.println(entry.getKey() + “:” + entry.getValue());
}
方法(2): for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + “:” + entry.getValue());
}
HashMap<K,V>——实现类
允许键或者值为null。
是一个异步式线程不安全的映射。
底层基于键的哈希码进行存储,底层结构是数组+链表(也叫链式栈结构)。
数组的每一个位置称为一个同,每一个桶中维持一个链表结构。
在存储元素的时候先计算键的哈希码,然后根据哈希码分配到不同的桶中,然后根据桶中的键一一比较,如果一致则舍弃,如果不一致则插到这个链表的最前面。
缺点:在元素个数比较多的情况下,每一个桶中维持的链表会比较长,会导致效率降低,所以需要扩容,而是否扩容依赖的是加载因子。
元素不能重复。不保证映射的顺序。
是一个异步式线程不安全的映射。
初始容量16,默认加载因子是0.75f,每次默认增加一倍。
扩容后需要重新计算所有元素的哈希码,重新分布。这个叫rehash操作。
如果桶的容量小或加载因子过小,会导致频繁进行扩容和rehash操作,同时还会浪费内存空间。
如果加载因子过大,会导致每个桶中的链表过长,从而降低效率。
Hashtable
不允许键或值为null。
默认初始容量是11,默认加载因子是0.75f。
是一个同步式线程安全的映射。
JDK1.0开始,很少用。
线程不安全比线程安全效率高。
异步比同步效率高。
CocurrentHashMap——异步式线程安全。(后续讲~)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值