31.枚举
枚举编译之后也是生成class文件;
枚举也是一种引用数据类型;
枚举中的每一个值可以看作是常量;
结果超过两种,并且可以一枚一枚列举出来的可以使用枚举类型,例如颜色、四季、星期等;
public static void main(String[] args) throws Exception {
Res r = App.divide(3, 5);
if (r == Res.SUCCESS) {
System.out.println("成功");
}
Res r2 = App.divide(3, 0);
if (r2 == Res.FAIL) {
System.out.println("失败");
}
}
public static Res divide(int a, int b) {
try {
int c = a / b;
return Res.SUCCESS;
} catch (Exception e) {
// TODO: handle exception
return Res.FAIL;
}
}
enum Res {
SUCCESS, FAIL
}
32.异常
异常:程序运行过程中的不正常情况;
异常作用:增强程序的健壮性;
异常在java中以类的形式存在,每个异常类都可以创建异常对象;
异常Exception分为两大类:运行时异常(未受检异常/非受控异常)与编译时异常(受检异常/受控异常);
编译时异常表示必须在编写程序的时候预先对这种异常进行处理,否则编译报错;
运行时异常在编写程序时可以选择处理与不处理;
所有异常都是在运行时发生的,编译阶段是不会发生的,因为只有运行阶段才能new异常对象,异常的发生就是new异常对象;
编译时异常发生的概率比较高,对于发生概率比较高的异常需要在运行前进行预处理;运行时异常发生的概率比较低,没有必要对发生概率比较低的异常在运行前预处理;
异常的处理:
java中对异常的处理有2中方式:
①在方法声明的位置上使用throws关键字,抛给上一级(调用者);
②使用try...catch语句进行方法的捕捉;
如果异常一直上抛,直到main方法,main方法未处理,则抛给jvm,jvm则终止程序执行;
编译时异常:
//必须在编写代码时处理该异常,否则程序报错
public static void main(String[] args) {
App.test();
}
public static void test() throws ClassNotFoundException {
System.out.println("aaaa");
}
异常处理机制的作用就是增加程序的健壮性,即使发生了异常也不会影响程序的执行;所以一般建议在main方法中使用try...catch捕获异常;
33.try...catch
程序new异常对象,抛出异常后,进行try...catch捕捉的话,最终会把异常对象的内存地址赋值给e;
try语句块中的代码有异常的话程序不会执行try语句块的代码,而是执行catch语句块中的代码,后溪代码继续执行;
catch后面的括号可以是具体类型也可以是具体类型的父类型;
catch可以写多个,建议写精确的异常类型捕获,可以利于代码快速查找bug;
catch写多个的时候,从上到下依次不能是从父类到子类;
public static void m3() {
System.out.println("m3");
try {
FileInputStream f = new FileInputStream("D://a.txt");
System.out.println(100 / 0);
f.read();
} catch (FileNotFoundException | NullPointerException | ArithmeticException e) {
// TODO Auto-generated catch block
System.out.println("文件不存在");
// e.printStackTrace();
} catch (IOException e) {
System.out.println("文件无法读取");
}
System.out.println("m3-2");
}
如果希望调用者处理异常则用throws,否则都用try...catch处理异常;
异常对象的两个重要方法:
获取异常的简单描述信息:
NullPointerException n = new NullPointerException("空指针");
System.out.println(n.getMessage());
打印异常追踪的堆栈信息:
public static void main(String[] args) {
try {
m1();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("m000");
}
实际开发中建议使用e.printStackTrace(),更加便于观察代码错误;
异常追踪信息从上往下看,跳过SUN公司代码,即可发现bug代码所在位置;
异常只有抛出throw了,才会被系统当做异常对象处理,否则只是一个普通类;
捕获异常可以让程序不会因为一个异常而停止运行,导致发生程序停止运行,影响用户体验;
重写父类的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少;
34.try...catch的finally子句
在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常;
finally必须与try...catch同时出现,不能单独编写;
public static void m3() {
System.out.println("m3");
FileInputStream f = null;
try {
f = new FileInputStream("D://a.txt");
System.out.println(f.toString());
} catch (FileNotFoundException e) {
// TODO: handle exception
e.printStackTrace();
} finally {
// finally中的代码一定会执行
// 流会占用资源,所以要关闭,在finally中执行是比较合适的
if(f!=null){
try {
f.close();
} catch (IOException e) {
//TODO: handle exception
}
}
}
}
try可以与finally一起使用
try {
System.out.println("try");
return;
} finally {
System.out.println("fffff");
}
finally的代码一定会执行,除非退出java虚拟机jvm
try {
System.out.println("try");
System.exit(0);
} finally {
System.out.println("fffff");
}
//java方法体中的代码必须遵循一条基本原则,即代码是自上而下依次执行;
public static void main(String[] args) {
int i = m1();
System.out.println(i); //100
}
public static int m1() {
int i = 100;
try {
return i;
} finally {
i++;
}
}
35.Error错误
错误是不能处理的,所有的错误只要一发生就会终止程序的执行,退出jvm;
36.自定义异常
package exec;
public class MyException extends RuntimeException {
public MyException() {
}
public MyException(String s) {
super(s);
}
}
public class App {
public static void main(String[] args) {
try {
m1();
} catch (MyException e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
}
}
37.集合
集合实际上就是一个容器,一个载体,可以用来容纳其他类型的数据,可以容纳多个对象;
假如从数据库查出10条数据,java会将10条数据封装成10个对象,放入一个集合当中;
集合不能存储基本数据类型,不能存储java对象,集合中存储的都是java对象的内存地址(引用);
集合本身也是一个对象,也对应一个内存地址;
java中每一个不同的集合,对应不同的数据结构,往不同的集合中存储数据,就相当于把数据放到了不同的数据结构当中,不同的数据结构,数据的存储的方式不同,数据结构有:数组、二叉树、链表、哈希表;
使用不同的集合等同于使用不同的数据结构;
所有的集合类跟接口都在java.util包下;
java中集合分为两大类,一类是单个方式存储元素,一类是以键值对方式存储元素;
单个方式存储元素:这一类中超级父接口是java.util.Collection;
键值对方式存储元素:这一类中超级父接口是java.util.Map;
所有实现类:
ArrayList :底层是数组;
LinkedList :底层是双向链表;
Vector :底层是数组,线程安全,效率较低,使用较少;
HashSet :底层是HashMap,放到HashSet集合的中的元素,等同于放到了HashMap集合的key部分;
TreeSet : 底层是TreeMap,放到TreeSet中的元素相当于放到了TreeMap集合的key部分了;
HashMap :底层是Hash表;
HashTable :底层也是hash表,只不过线程安全,效率较低,使用较少;
Properties :线程安全的,key和value只能存储字符串String;
TreeMap :底层是二叉树,TreeMap的key可以自动按照大小顺序排序;
List集合存储元素的特点:
有序:存进去和取出的顺序相同,每个元素都有下标;
可重复:存进去的元素可以是相同的;
Set(Map)集合存储元素的特点:
无序:存进去与取出来的顺序不一定相同,set集合的元素没有下标;
不可重复:不能存储相同的元素;
SortedSet(SortedMap)集合存储特点:
无序不可重复,但是SortedSet里面的元素是可以排序(按照大小顺序排列)的;
Map集合的key就是一个Set集合;往Set集合中存放数据,就是放到了Map集合的Key部分;
38.Collection
没有使用泛型的情况下,Collection中可以存储所有Object子类型元素,使用泛型后,collection中只能存储某种具体类型;
集合中不能直接存储基本数据类型,也不能存对象,只能存对象的引用地址;
Collection c = new ArrayList<>();
c.add(500); //自动装箱
c.add(true);
c.add(new Random());
System.out.println(c.size());
c.clear();
System.out.println(c.contains("八佰2"));
c.remove("八佰");
Object[] objs = c.toArray();
Collection的contains方法底层是调用equals方法,所以存放在集合中的类型一定要重写equals方法,remove方法同理;
while(it.hasNext()){
//next方法返回值类型必须是Object
Object o=it.next();
}
Collection c = new ArrayList();
//此时获取的迭代器,指向的是集合中没有元素状态下的迭代器;
//集合结构一旦发生改变,迭代器必须重新获取;
Iterator it = c.iterator();
String a1 = "abc";
String a2 = "abc";
c.add(a1);
c.add(a2);
获取迭代器,相当于对当前集合拍了一张快照,然后迭代器参照这个快照进行迭代;
c.remove()方法只删除集合的元素,导致迭代器的快照和原集合不同,it.remove()删除集合的元素,同时删除快照的元素;
39.List
List特点:有序可重复;
List c = new ArrayList();
String a1 = "海王";
String a2 = "敦刻尔克";
String a3 = "阿凡达";
c.add(a1);
c.add(a2);
c.add(a3);
// 在指定位置添加元素,后面元素往后移动一位;
// 使用不多,因为对于ArrayList来说效率较低
c.add(1, "无间道");
//修改某个下标的元素
c.set(0, "蜘蛛侠");
Iterator it = c.iterator();
for (int i = 0; i < c.size(); i++) {
//List的get方法遍历
System.out.println(c.get(i));
}
//第一次出现的索引
System.out.println(c.indexOf("海王"));
//元素最后一次出现的索引
System.out.println(c.lastIndexOf("阿凡达"));
//删掉指定下标的元素
c.remove(0);
40.ArrayList
容量是虚拟的预留内存空间;
//默认数组容量是10(底层先创建一个容量为0的数组,当添加元素的时候,初始化容量为10)
ArrayList c = new ArrayList();
ArrayList c2 = new ArrayList<>(20);
// size方法是获取集合中元素的个数,不是容量
System.out.println(c2.size()); // 0
Collection c = new HashSet();
c.add(1);
c.add(2);
c.add(3);
ArrayList c2 = new ArrayList(c);
Iterator it = c.iterator();
for (int i = 0; i < c2.size(); i++) {
System.out.println(c2.get(i));
}
ArrayList的扩容是原容量的1.5倍;
ArrayList底层是数组,建议尽可能少的扩容,因为数组扩容效率比较低,建议在使用ArrayList集合的时候预估一个较为准确的初始化容量;
数组的优点:检索效率高;缺点:随机增删效率较低,向末位增删效率不受影响,无法存储大容量数据,因为很难找到一段连续的大内存空间;
ArrayList不是线程安全的集合;
//非线程安全转线程安全
List l = new ArrayList<>();
Collections.synchronizedList(l);