异常

概述

  1. 程序在进行过程中发生的错误,叫做异常
  2. 作用:增强程序的健壮性
  3. 异常在java中以类的形式存在,每一个异常类都能创建对象
  4. 所有的错误(error)和异常(exception)都是可以抛出的
  5. 所有的错误(error)只要执行,JVM退出(不能处理)

    概述二

  6. 编译时异常和运行时异常都是发生在运行阶段,在编译阶段异常是不会发生

    1. 所有异常都是在执行时发生的:
      1. 因为异常只有在执行时才能new对象
      2. 异常的发生就是new异常对象
  7. 编译时异常为什么而得名?
    1. 因为编译时异常必须在编译阶段预先处理,如果不处理,报错
  8. 运行时异常又称 非受控异常 未受检异常 (UnCheckedException)
  9. 编译时异常又称 受检异常 受控异常 (CheckedExeption)

对异常的处理

java中有两种方式处理异常

  1. 在方法声明的位置上使用throws 关键字 (抛给上一级)
    • 在java中如果一直上抛最后会抛给JVM 最后终止程序的执行
    • 一般不建议在main方法上使用throws关键字,建议使用 try..catch
  2. 使用try..catch 进行异常的捕捉

语法:

  1. try{
  2. // try 尝试 java代码
  3. }
  4. catch(异常 变量名){
  5. //捕捉异常后的分支
  6. }

编译时异常必须处理 要么上抛 要么捕捉

注意:
  1. 只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行
  2. 另外需注意,try语句块中某一行出现异常,该行后面的代码不会执行catch 捕捉到后,后续代码执行

自定义异常

  • 所有异常都有共同的特点
    • 有参构造
    • 无参构造
  • 自定义异常的编写

提供两个构造方法

  1. - 无参
  2. - 有参(string s
  1. class MyException extends Exception {
  2. public MyException(){
  3. }
  4. public MyException(String s){
  5. super (s);
  6. }
  7. }

抛异常

throw 关键字
throw new MyException(“这是一个自定义异常”);

深入 try catch

  • catch 后面的小括号可以是具体的异常类型,也可以是该异常类型的父类型
  • catch可以写多个,建议catch一个一个精准处理
  • catch写多个的时候,从上到下必须是从小到大

    什么时候选择捕捉/上报

  • 如果希望调用者来处理异常,使用上报

  • 其他情况使用捕捉

异常对象的两个重要方法

获取异常简单的描述信息 这个信息就是构造器里的String参数

  1. Exception exception = new Exception("你的程序报错")
  2. String s = exception.getMessage();
  3. System.out.println(s); 这里会输出 你的 程序报错

打印异常追踪的堆栈信息

  1. exception.printStackTrace();
  2. java.lang.Exception: asdfat While03.main(While03.java:6)

异常信息如何看
从上往下,一行一行(sun公司写的代码不用看)

finally

和try..catch 一起使用
  • 在finally子句中的代码时最后执行的,并且一定会执行
  • 即使try出了异常,也会执行
    try和fianlly可以联合使用(没有catch)
    1. try{
    2. System.out.println("aaa");
    3. return;
    4. } finally{
    5. System.out.println("bbb");
    6. }
    7. //输出结果 aaa bbb
    但是如果try中有System.exit(0); //退出jvm
    finally不执行 只有这一条代码能治他

总结

未命名图片.png


集合

概述

  1. 集合在JDK java.util.* 包下

所有集合类和集合接口都在

  1. 集合是一个载体,一个容器,一次可以容纳多个对象
  2. 集合里存的是对象的内存地址
  3. 集合本身也是一个对象(有内存地址)
  4. 集合里可以存集合
  5. 不同的集合底层对应不同的数据结构
  6. 集合中不能直接存储基本数据类型,他会自动的帮你装箱

    在Java中集合分为两大类

  7. 一类是单个方式存储元素,超级父接口 java.util.Collection

  8. 一类是以键值对(key,value)的方式存储元素,超级父接口 java.util.Map

Collection

  1. Collection 是集合里面的超级父接口
  2. Collection可以存储那些元素

在没有使用泛型的情况下可以存储Object所有子类
使用了泛型,只能存储某个具体的类型

Collection 常用方法

  1. boolean add(Object e) //向集合里面添加元素(末尾)
  2. int size() //查询集合中元素的个数
  3. void clear() //清空集合
  4. boolean contains(Object o) // 判断集合中是否包含

底层调用了equals()判断,所以放在集合中的元素需要重写equals()方法
如果u2 和集合中的u1 内容完全相同,判断结果是true

  1. remove(Object o) //删除集合中某个元素

底层调用了equals()判断,所以放在集合中的元素需要重写equals()方法
如果u2 和集合中的u1 内容完全相同,删除u2,u1会被删除

  1. boolean isEmply() //判断集合是否为空 空=true 不空 =false
  2. Object[] toArray() //将集合转化成数组,返回一个Object数组
  3. Iterator iterator() //拿到迭代器 返回一个Iterator

增强for循环

用来遍历集合/遍历数组

  1. for(元素类型 变量名 数组或者集合){
  2. 循环体 //System.out.println(变量名);遍历集合
  3. }

collection 继承结构图

未命名图片.png

List/Set/SortedSet特点

未命名图片.png

集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,
集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)
list.add(100); //自动装箱Integer
注意:

  • 集合在java中本身是一个容器,是一个对象。
  • 集合中任何时候存储的都是“引用”。

在java中集合分为两大类:

  • 一类是单个方式存储元素:
    • 单个方式存储元素,这一类集合中超级父接口:java.util.Collection;
  • 一类是以键值对儿的方式存储元素
    • 以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;

Collection-List接口

旗下有ArrayList 、 LinkedList 、 Vector

特点

  • 有序
  • 可重复
  • 有下标 0开始 以1递增

List接口为Collection的子接口,也就是说Collection中有的方法,这里都有

创建集合 List l = new ArrayList(); 多态

List集合常用方法

  1. void add(下标,元素) //在指定的位置插入元素
  2. Object get(下标) //得到指定位置的元素
  3. int indexOf("元素") //得到该元素第一次出现的下标
  4. int lastIndexOf("元素") //得到该元素最后一次出现的下标
  5. Object remove(下标) // 删除指定位置的元素
  6. Object set(下标,元素) //修改指定下标的元素

链表

优点
随机增删元素效率较高
缺点
查询效率底
在开发中如果遇到了随机增删元素较多的业务时,建议使用LinkedList

ArrayList

  • ArrayList集合初始化容量10
  • 扩容为原容量1.5倍。
  • 底层是数组。

  • 数组优点和缺点要能够说出来!

  • 另外要注意:ArrayList集合末尾增删元素效率还是可以的。

Vector:

  • Vector初始化容量是10.
  • 扩容为原容量的2倍。
  • 底层是数组。
  • Vector底层是线程安全的。

  • 怎么得到一个线程安全的List:

  • Collections.synchronizedList(list);

集合的遍历/迭代器

此内容只能在Collection中使用Map集合不能使用

  1. Iterator i = 集合.iterator(); // 拿到迭代器

迭代器常用方法
boolean hasNext()
如果返回true表示有元素可以迭代
如果返回false表示没有元素可以迭代
Object next();
让迭代器前进一位,并且拿到该元素
迭代器对象最初没有指向任何元素

遍历集合

  1. Collection c = new ArrayList(); // 创建集合 多态
  2. Iterator i = c.iterator(); //拿到迭代器
  3. while(i.hasNext()){ //如果有元素返回true ,执行循环,没有则退出
  4. System.out.println(i.next()); // 迭代
  5. }

注意

  1. 当集合发生结构变化,一定要重新获取迭代器
  2. 在迭代元素时不能调用c.remove()方法 ,删除元素但是可以调用i.remove()方法 ,删除元素

泛型

在JDK5.0出现的新特性
List myList = new ArrayList<>(); <>钻石表达式
使用泛型后myList集合中只允许出现Animal类或者他的子类
优点
使用泛型后,集合中的数据类型更加统一
缺点
导致集合中的储存元素缺乏多样性
注意
使用泛型之后迭代器迭代的就不是Object类型了而是<> 这里面的类型


Collection-TreeSet集合/Vector集合

  1. 底层是TreeMap
  2. TreeMap底层是二叉树
  3. 放到TreeSet集合中的元素 等同于放到TreeMap的key部分
  4. 特点

无序不可重复
自动排序,从小到大

排序可以自定义

比较规则
升序 : return this.age-c.age;
降序 : return c.age - this.age;
例如

  1. TreeSet<B> treeSet2 = new TreeSet<>(new Comparator<B>() {
  2. @Override
  3. public int compare(B b, B t1) {
  4. return b.age - t1.age;
  5. } //匿名内部类
  6. });
  7. treeSet2.add(new B(520));
  8. treeSet2.add(new B(500));
  9. treeSet2.add(new B(510));
  10. treeSet2.add(new B(400));
  11. treeSet2.add(new B(300));
  12. for ( B b : treeSet2){
  13. System.out.println(b);
  14. }

结论

  1. 放到TreeSet或者TreeMap集合中key部分想要排序包括两种方式
    • 集合中的元素类中实现Comparable接口
    • 在构造的时候传一个比较器Comparator接口(对象)
  2. 如果比较规则不变使用Comparable接口
  3. 如果比较规则有多个,需要切换,用Comparator接口(匿名内部类)

Vector 集合

  • 底层是数组
  • 初始容量为10
  • 扩容之后是原容量的2倍 10—>20—>40
  • 所有的方法都是线程同步的(所以不常用)

Collection-集合继承结构图

未命名图片.png


Map

概念

Map集合以key和value的方式储存数据(键值对)

  1. key和value是引用数据类型
  2. key和value保存的是对象的内存地址
  3. key起主导作用,value是附属品

    Map集合常用方法

  4. put(k,v) //向Map集合中添加键值对

  5. get(Object key) // 通过key找到value
  6. void clear() //清空集合
  7. boolean containsKey(Object key) // 判断集合里有没有key(只在key中找)
  8. boolean contiansValue(Object value) //判断集合中有没有value(只在value中找)
  9. boolean isEmpty() //判断集合是否为空
  10. int size() //获取键值对的数量,一组为一个
  11. remove (Object key) // 通过key来删除键值对
  12. Collection values() // 得到所有的value元素 用一个Collection 集合接收
  13. Set keySet() //得到所有的key元素 用Set集合接收

哈希表数据结构(散列表)

  1. 哈希表是数组和单向链表的结合体
  2. 哈希表就是将传进来的key元素,通过hashCode算出来一个下标,将key存进去
  3. 如果重写hashCode方法返回都是一样的值,那么就变成了纯链表
  4. 如果重写的hashCode方法返回的值都不一样,那么就变成了纯数组
  5. 如果put(k重复了,value会覆盖)

    重点

  • 放在HashMap/HashSet集合里key部分的元素必须同时重写HashCode()和equals()
  • hashCode()和equals()方法不需要自己写直接idea生成
  • HashMap集合初始化容量必须是2的次幂,这也是官方推荐 【推荐16】

简易Map继承图

未命名图片.png

HashMap

  • HashMap集合的默认初始化容量为16,默认加载因子为0.75
  • 默认加载因子是指HashMap集合底层数组的容量达到75%以后开始扩容

Properties集合

继承Hashtable
key和value都只能存String
属性类对象(线程安全)

方法()

setProperty(k,v) //存元素
getProperty(k); //通过key得到value

自平衡二叉树

遵循左小右大的原则存放

遍历

前序遍历 根左右
中序遍历 左根右
后序遍历 左右根

集合工具类Collections

java.util.Collections
Collentions.synchronizedList(); //静态方法,变成线程安全的
Collentions.sort(集合名); // 静态方法排序
(必须是list集合 前提是实现了Comparable接口)


Map集合遍历

  1. 通过获取所有的key,通过遍历key,来遍历value ```java Mapmap = new HashMap<>(); map.put(1,”张三”); map.put(2,”李四”); map.put(3,”王五”); Set set = map.keySet(); // 得到所有的key元素 Iterator it = set.iterator(); //拿到迭代器 while(it.hasNext()) {
    1. Integer i = (Integer) it.next(); // 得到迭代的key
    2. String i1 = map.get(i); //通过得到迭代的key 得到value
    3. System.out.println(i);
    4. System.out.println(i1);
    }
  1. 2. **增强for**
  2. ```java
  3. Map<Integer,String>map = new HashMap<>();
  4. map.put(1,"张三");
  5. map.put(2,"李四");
  6. map.put(3,"王五");
  7. Set<Integer> set = map.keySet(); // 得到所有的key元素
  8. for(Integer i : set){
  9. System.out.println(i+"="+map.get(i));
  10. }
  1. 大数据量时使用

    1. Set<Map.Entry<Integer,String>> set1 = map.entrySet();
    2. for (Map.Entry<Integer,String> node :set1){
    3. System.out.println(node.getKey()+"="+node.getValue());
    4. }

    Map总结

  2. ArrayList 底层是数组

  3. LinkedList 底层双向链表
  4. Vector 底层是数组,线程安全 效率底,使用较少
  5. HashSet 底层是HashMap,放在HashSet集合中的元素,相当于放在HashMap的key部分
  6. TreeSet 底层是TreeMap,放到TreeSet集合里的元素等同于放在TreeMap集合中的key部分
  7. HashMap 底层是哈希表
  8. Hashtable 底层是哈希表,线程安全,效率低,使用少
  9. Properties 线程安全 并且key和value中只能存储字符串 String
  10. TreeMap 底层是二叉树,TreeMap集合中的key可以自动按照从小到大的顺序排序

未命名图片.png


IO

概念

  • I: input O: output
  • java.io.* 包下
  • 通过IO可以完成对硬盘的读和写

字节流

  • 万能流,一次读一个字节(byte) = 8个二进制位
  • 啥都能读取

字符流

  • 一次读一个字符
  • 只能读纯文本文件 .txt

区分

  • 在Java中类名以Stream结尾的都是字节流
  • 以Writer/Reader结尾的都是字符流

所有的流都实现了Closeable接口,都是可以关闭的

  • 流用完一定要关

所有的输出流都实现了Flushable接口,都是可刷新的

  • 最后输出之后一定要flush()刷新一下(清空管道)

未命名图片.png

IO四大家族(都是抽象类)

  • java.io.InputStream 字节输入流
  • java.io.OutputStream 字节输出流
  • java.io.Reader 字符输入流
  • java.io.Writer 字符输出流

文件复制原理

未命名图片.png

需要掌握的流

文件专属流

  • java.io.FileInputStream
  • java.io.FileOutputStream
  • java.io.FileReader
  • java.io.FileWriter

转换流
(将字节流转换成字符流)

  • java.io.InputStreamReader
  • java.io.OutputStreamWriter

缓冲流专属

  • java.io.BufferedReader
  • java.io.BufferedWriter
  • java.io.BufferedInputStream
  • java.io.BufferedOutputStream

数据流专属

  • java.io.DataInputStream
  • java.io.DataOutputStream

标准输出流

  • java.io.PrintWriter
  • java.io.PrintStream

对象专属流

  • java.io.ObjectInputStream
  • java.io.ObjectOutputStream

File In/Out putStream

万能流,所有文件都可以用来读

int read() 读取第一个字节(每调用一次向下移一个)
int i = stream.read();
返回一个ascll码 读到末尾 ,读不到了就返回-1

int available() 返回流当中剩余的没有读到的字节数量

作用:一上来就可以获取它的总字节数量

int i = stream.available();
long skip() 跳过几个字节不读

用while循环读取文件

  1. FileInputStream s = null;
  2. try {
  3. s = new FileInputStream("I_O/src/FileInputStreamTast01/My");
  4. byte[] bytes = new byte[14]; int i1 = 0 ;
  5. while( (i1 = s.read(bytes)) != -1){
  6. System.out.println(i1);
  7. }
  8. } catch (FileNotFoundException e) {
  9. e.printStackTrace();
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. } finally{
  13. if (s != null) {
  14. try {
  15. s.close();
  16. } catch (IOException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }

FileOutputStream

写完一定要flush() 刷新一下
构造方法里跟一个地址(只有地址)
会把地址里面的文件清空,后写入
构造方法里跟一个 地址,true 表示追加写入

write() 写入
write(byte[]数组,开始下标,结束下标) 写入指定长度的文件

文件复制

  1. FileInputStream in = null;
  2. FileOutputStream out = null;
  3. try {
  4. in = new FileInputStream("E:\\仝子瑜\\tongziyu.jpg"); //创建输入流
  5. out = new FileOutputStream("E:\\tongziyu.jpg"); //创建输出流
  6. byte[] bytes = new byte[1024];
  7. int i = 0;
  8. while ((i = in.read(bytes)) != -1){ //读文件
  9. out.write(bytes,0,i); //写文件
  10. }
  11. out.flush(); //刷新一下
  12. } catch (FileNotFoundException e) {
  13. e.printStackTrace();
  14. } catch (IOException e) {
  15. e.printStackTrace();
  16. } finally{
  17. if (in != null) {
  18. try {
  19. in.close();
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. if (out != null) {
  25. try {
  26. out.close();
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }

FileReader

一次读取一个字符,只能读取普通文本文件
char数组接收
和FileInputStream差不多,就是用char[]数组接收数据

FileWriter
一个写入一个字符 “a/中”
引用.flush() 刷新不要忘

BufferedReader/PrintStream

BufferedReader概念

  1. 带有缓冲区的字符输入流
  2. 使用时不惜要byte[] 或者 char[] 数组 自带缓冲
  3. 当一个流(包装流,处理流)的构造方法需要传进去一个流(节点流)的时候
  4. 关闭流时只需要管理包装流即可

String readLine() // 读取一行
String s = 引用.readLine();
读不到内容时会返回null
bufferedReader的构造方法里只能跟字符流
如果要用字节流,就需要转换流

转换流
  1. FileInputStream in = new FileInputStream("路径"); //字节流
  2. InputStreamReady ready = new InputStreamReady(in); // 转换成字符流

使用缓冲字符输入流读文件

  1. BufferedReader s = null;
  2. FileReader reader = null;
  3. try {
  4. reader = new FileReader("E:\\java\\Java 资料\\JAVA语法.TXT");
  5. s = new BufferedReader(reader);
  6. String s5 = null;
  7. // 因为 readLine() 在都不到的情况下会返回null 由此判断
  8. while ((s5 = s.readLine()) != null ){
  9. System.out.println(s5);
  10. }
  11. }

PrintStream

  • 标准输出字节
  • 不需要使用close()关闭
  • 标准输出流是指不再向控制台输出,而是指向这个文件输出↓
  • PrintStream ps = new PrintStream(new FileOutputStream(“log”))
  • System.setOut(ps); // 改变输出方向
  • System.out.println(“HelloWorld”); // 不会输出到控制台,会输出到log文件里

File类

和四大家族无关,所以不能读和写

file对象
  • 可能对应的是一个目录,或者文件
  • 只是一个路径名的抽象表示形式

掌握File类的常用方法

  1. File s = new File(“路径”) // 创建file对象
  2. boolean exists(); //判断是否存在
  3. boolean mkdir() //以目录形式新建
  4. boolean mddirs() //以多重目录新建
  5. File getAbsoluteFile() //获取绝对路径
  6. String getParent() //获取父路径
  7. String getName() //获取文件名

序列化

英文未命名图片.png
  • 序列化:Serialize
  • 反序列化:DeSerialize

参与序列化的和反序列化的对象必须都要实现Serializable接口
Serializable只是一个标志性接口,里面没有任何代码

在java中如何区分一个类
  • 类名
  • 序列化版本号(实现Serializeble接口)

    1. Jvm会自动给这个类一个序列化版本号<br />但是后期修改代码的时候,序列化版本号也会自动修改<br />**所以建议给一个不变的序列化版本号:**<br />private static final long serialVersionVID = ~~~L; //可参考源码

序列化多个对象,创建一个list集合,对象放进去,序列化集合即可
transient关键字(不参加序列化操作)

  • 例如private transient String name;
  • 表示序列化多个对象,创建一个e不参加序列化操作

writeObject(对象或者引用); // 序列化
readObject (); 反序列化

  1. ObjectOutputStream s = null;
  2. ObjectInputStream a = null;
  3. try {
  4. /* s = new ObjectOutputStream(new FileOutputStream("E:\\asd.TXT"));
  5. s.writeObject(1);*/ // 序列化对象
  6. a = new ObjectInputStream(new FileInputStream("E:\\asd.TXT"));
  7. Object s1 = a.readObject(); //反序列化
  8. System.out.println(s1);
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. } catch (ClassNotFoundException e) {
  12. e.printStackTrace();
  13. } finally{
  14. /*try {
  15. *//*s.close();*//*
  16. } catch (IOException e) {
  17. e.printStackTrace();
  18. }*/
  19. }