在线视频:尚硅谷2024最新Java入门视频教程(下部)-Exception&Object
课程资料:尚硅谷2024新版Java基础
随堂代码:https://gitee.com/an_shiguang/learn-java
重点内容:
1.分清楚什么是编译时期异常,什么是运行时期异常
2.知道处理异常的2种方式
3.知道finally关键字的使用场景
4.知道Object是啥
5.知道Object中toString以及equals方法的作用
6.知道重写完Object中的toString以及equals方法的作用
API文档
1 2 3 4 5
| 1.什么叫做API:Application Programming Interface,简称API,又称之为应用编程接口 说白了:定义出来的类以及接口,以及其中的方法等 2.为了方便我们去查询开发好的接口以及类,以及其中的方法,会对应提供一个文档 -> API文档 3.API文档作用:查询我们要使用的对象,以及方法,是我们程序员的"字典"
|
异常
异常介绍
1
| 1.概述:代码出现了不正常的现象;在java中,异常都是一个一个的类
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Demo01Exception { public static void main(String[] args) throws ParseException {
int[] arr1 = new int[3];
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = "2000-10-10 10:10:10"; Date date = sdf.parse(time); System.out.println(date); }
public static void method(){ method(); } }
|
异常出现的过程
创建异常对象(了解)
创建异常对象,只是为了后面学习如何处理异常,其他的暂时没有啥意义
1 2
| 1.关键字:throw 2.格式: throw new 异常
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Demo03Exception { public static void main(String[] args) { String s = "a.tx1t"; method(s); } public static void method(String s){ if (!s.endsWith(".txt")){ throw new NullPointerException(); } System.out.println("我要执行了"); } }
|
异常处理方式(重点)
异常处理方式一:_throws
1 2 3 4
| 1.格式:在方法参数和方法体之间位置上写 throws 异常 2.意义:处理异常 将异常往上抛
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Demo04Exception { public static void main(String[] args)throws FileNotFoundException { String s = "a.txt1"; add(s); delete(); update(); find(); }
private static void add(String s)throws FileNotFoundException { if (!s.endsWith(".txt")) { throw new FileNotFoundException("文件找不到"); } System.out.println("我要执行了"); }
private static void find() { System.out.println("查询功能"); }
private static void update() { System.out.println("修改功能"); }
private static void delete() { System.out.println("删除功能"); } }
|
异常处理方式一:_throws多个异常
1 2 3 4 5
| 1.格式:throws 异常1,异常2 2.注意: 如果throws的多个异常之间有子父类继承关系,我们可以直接throws父类异常 如果不知道多个异常之间是否有子父类继承关系,我们可以直接throws Exception
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class Demo05Exception { public static void main(String[] args)throws Exception { String s = null; add(s); delete(); update(); find(); }
private static void add(String s)throws Exception { if (s==null){ throw new IOException("IO异常"); } if (!s.endsWith(".txt")) { throw new FileNotFoundException("文件找不到"); } System.out.println("我要执行了"); }
private static void find() { System.out.println("查询功能"); }
private static void update() { System.out.println("修改功能"); }
private static void delete() { System.out.println("删除功能"); }
}
|
异常处理方式二:_try…catch
1 2 3 4 5 6
| 1.格式: try{ 可能出现异常的代码 }catch(异常 对象名){ 处理异常的代码-> 将来开发会将异常信息保存到日志文件中 }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class Demo06Exception { public static void main(String[] args){ String s = "a.txt1"; try{ add(s); }catch (FileNotFoundException e){ System.out.println(e); }
delete(); update(); find(); }
private static void add(String s)throws FileNotFoundException { if (!s.endsWith(".txt")) { throw new FileNotFoundException("文件找不到"); } System.out.println("我要执行了"); }
private static void find() { System.out.println("查询功能"); }
private static void update() { System.out.println("修改功能"); }
private static void delete() { System.out.println("删除功能"); }
}
|
异常处理方式二:_多个catch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 1.格式: try{ 可能出现异常的代码 }catch(异常 对象名){ 处理异常的代码-> 将来开发会将异常信息保存到日志文件中 }catch(异常 对象名){ 处理异常的代码-> 将来开发会将异常信息保存到日志文件中 }catch(异常 对象名){ 处理异常的代码-> 将来开发会将异常信息保存到日志文件中 }catch(异常 对象名){ 处理异常的代码-> 将来开发会将异常信息保存到日志文件中 }... 2.注意: 如果catch的多个异常之间有子父类继承关系,我们可以直接catch父类异常 如果不知道多个异常之间是否有子父类继承关系,我们也可以直接catch Exception
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public class Demo07Exception { public static void main(String[] args) { String s = null;
try { add(s); }catch (Exception e){ e.printStackTrace(); } delete(); update(); find(); }
private static void add(String s) throws FileNotFoundException, IOException { if (s == null) { throw new IOException("IO异常"); } if (!s.endsWith(".txt")) { throw new FileNotFoundException("文件找不到"); } System.out.println("我要执行了"); }
private static void find() { System.out.println("查询功能"); }
private static void update() { System.out.println("修改功能"); }
private static void delete() { System.out.println("删除功能"); }
}
|
finally关键字
1 2 3 4 5 6 7 8 9 10
| 1.概述:代表的是不管是否触发了异常,都会执行的代码块 特殊情况:如果之前执行了System.exit(0)终止当前正在执行的java虚拟机 2.使用:都是配合try...catch使用 try{ 可能出现异常的代码 }catch(异常 对象名){ 处理异常的代码-> 将来开发会将异常信息保存到日志文件中 }finally{ 不管是否有异常,都会执行的代码 }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Demo08Exception { public static void main(String[] args){ String s = "a.txt"; try { add(s); } catch (FileNotFoundException e) { e.printStackTrace(); }finally { System.out.println("我必须滴执行"); } }
private static void add(String s)throws FileNotFoundException { if (!s.endsWith(".txt")) { throw new FileNotFoundException("文件找不到"); } System.out.println("我要执行了"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Demo09Exception { public static void main(String[] args) { int result = method(); System.out.println(result); }
public static int method() { try { String s = null; System.out.println(s.length()); return 2; } catch (Exception e) { return 1; } finally { System.out.println("我一定要执行"); } } }
|
finally的使用场景:
1.关闭资源
2.原因:对象如果没有用了,GC(垃圾回收器)回收,用来回收堆内存中的垃圾,释放内存,但是有一些对象GC回收不了,比如:连接对象(Connection),IO流对象,Socket对象,这些对象GC回收不了,就需要我们自己手动回收,手动关闭
将来不能回收的对象new完之后,后续操作不管是否操作成功,是否有异常,我们都需要手动关闭,此时我们就可以将关闭资源的代码放到finally中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Test { public static void main(String[] args) { FileWriter fw = null; try { fw = new FileWriter("day13_exception_object\\1.txt"); fw.write("哈哈哈"); } catch (IOException e) { throw new RuntimeException(e); } finally { if (fw != null) { try { fw.close(); } catch (IOException e) { throw new RuntimeException(e); } }
} } }
|
抛异常时注意的事项
1 2 3 4
| 1.如果父类中的方法抛了异常,那么子类重写之后要不要抛? 可抛可不抛 2.如果父类中的方法没有抛异常,那么子类重写之后要不要抛? 不要抛
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Demo10Exception { public static void main(String[] args) {
} class A{ public void method(){
} }
class B extends A{ @Override public void method(){
} } }
|
try_catch和throws的使用时机
1 2
| 1.如果处理异常之后,还想让后续的代码正常执行,我们使用try...catch 2.如果方法之间是递进关系(调用),我们可以先throws,但是到了最后需要用try...catch做一个统一的异常处理
|
1.编译时期异常是必须要处理的,不处理爆红,没法往下写
a.throws
b.try…catch
2.运行时期异常我们一般不处理,一旦出现运行时期异常,肯定是代码写的有问题,我们直接修改代码细节就行啦
自定义异常
1
| 1.需求:键盘录入一个用户名,实现登录功能,如果登录失败,抛出LoginUserException
|
1 2 3 4 5 6 7 8 9
| public class LoginUserException extends Exception{ public LoginUserException() { }
public LoginUserException(String message) { super(message); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Demo11Exception { public static void main(String[] args) throws LoginUserException { String username = "root"; Scanner sc = new Scanner(System.in); System.out.println("请您输入要登录的用户名:"); String name = sc.next(); if (name.equals(username)){ System.out.println("登录成功了"); }else{ throw new LoginUserException("登录失败了,用户名或者密码有问题"); } } }
|
1.定义一个类
2.如果继承Exception 就是编译时期异常
3.如果继承RuntimeException,就是运行时期异常
打印异常信息的三个方法
1 2 3 4
| Throwable类中的方法: String toString() :输出异常类型和设置的异常信息 String getMessage(): 输出设置的异常信息 void printStackTrace():打印异常信息是最全的:包括异常类型,信息,以及出现的行数等
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Demo11Exception { public static void main(String[] args) { String username = "root"; Scanner sc = new Scanner(System.in); System.out.println("请您输入要登录的用户名:"); String name = sc.next(); if (name.equals(username)) { System.out.println("登录成功了"); } else { try { throw new LoginUserException("登录失败了,用户名或者密码有问题"); }catch (Exception e){ e.printStackTrace(); } } } }
|
Object类
1
| 1.概述:所有类的根类(父类),所有的类都会直接或者间接继承Object类
|
Object中的toString
1 2 3 4 5 6 7 8 9 10 11
| 1.Object中的toString方法:返回该对象的字符串表示形式 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
2.注意: a.如果没有重写Object中的toString方法,直接输出对象名会默认调用Object中的toString方法,直接输出地址值 b.如果重写了Object中的toString方法,再输出地址值,重写没有意义,所以重写完toString之后,应该返回对象的内容 3.总结: 如果直接输出对象名不想输出地址值,就重写Object中的toString方法
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class Person { private String name; private int age;
public Person() { }
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Test01 { public static void main(String[] args) { Person p1 = new Person("金莲", 26); System.out.println(p1); System.out.println(p1.toString());
System.out.println("==============");
ArrayList<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); list.add("王五"); System.out.println(list); System.out.println(list.toString()); } }
|
快速生成toString
alt+insert -> 选择toString -> 直接下一步
Object中的equals
1 2 3 4 5 6 7 8 9 10 11
| 1.概述:比较两个对象的地址值是否相等 public boolean equals(Object obj) { return (this == obj); }
== 针对于基本数据类型来说,比较的是值 == 针对于引用数据类型来说,比较的是地址值 2.注意: a.如果没有重写Object中的equals方法,那么就会调用Object中的equals方法,比较对象的地址值 b.如果重写了Object中的equals方法,那么就会调用重写后的equals方法,应该比较对象的内容
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| public class Person { private String name; private int age;
public Person() { }
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Test02 { public static void main(String[] args) { Person p1 = new Person("金莲", 26); Person p2 = new Person("金莲", 26); System.out.println(p1==p2); System.out.println(p1.equals(p2)); System.out.println("==============");
ArrayList<String> list = new ArrayList<>(); System.out.println(p1.equals(list));
System.out.println("==============");
System.out.println(p1.equals(null));
System.out.println("=============="); System.out.println(p1.equals(p1));
System.out.println("====================");
String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1.equals(s2)); } }
|
小结:
1.如果直接输出对象名不想输出地址值,重写toString方法
2.如果想比较两个对象的内容,就重写一下equals方法
3.怎么重写:alt+insert -> 选toString 或者equals and hashcode -> 啥也不要管 -> 一路下一步即可
Object中的clone方法
1 2 3 4
| 1.作用:复制一个属性值一样的新对象 2.使用: 需要被克隆的对象实现Cloneable 重写clone方法
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| public class Person implements Cloneable{ private String name; private int age;
public Person() { }
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); }
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
|
1 2 3 4 5 6 7 8 9 10 11
| public class Test03 { public static void main(String[] args) throws CloneNotSupportedException { Person p2 = new Person("涛哥", 16); Object o = p2.clone(); Person p3 = (Person) o;
System.out.println(p2==p3); System.out.println(p2.equals(p3)); } }
|
经典接口
java.lang.Comparable
我们知道基本数据类型的数据(除boolean类型外)需要比较大小的话,之间使用比较运算符即可,但是引用数据类型是不能直接使用比较运算符来比较大小的。那么,如何解决这个问题呢?
Java给所有引用数据类型的大小比较,指定了一个标准接口,就是java.lang.Comparable接口:
1 2 3 4 5
| package java.lang;
public interface Comparable{ int compareTo(Object obj); }
|
那么我们想要使得我们某个类的对象可以比较大小,怎么做呢?步骤:
第一步:哪个类的对象要比较大小,哪个类就实现java.lang.Comparable接口,并重写方法
- 方法体就是你要如何比较当前对象和指定的另一个对象的大小
第二步:对象比较大小时,通过对象调用compareTo方法,根据方法的返回值决定谁大谁小。
- this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)大于0,返回正整数
- this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)小于0 返回负整数
- this对象(调用compareTo方法的对象)减 指定对象(传入compareTo()的参数对象)等于0 返回零
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class Student implements Comparable{ private String name; private int score;
public Student() {
}
public Student(String name, int score) { this.name = name; this.score = score; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getScore() { return score; }
public void setScore(int score) { this.score = score; }
@Override public String toString() { return "Student{" + "name='" + name + '\'' + ", score=" + score + '}'; }
@Override public int compareTo(Object o) { Student s = (Student) o; return this.getScore()- s.getScore(); } }
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class Test01 { public static void main(String[] args) { Student[] students = new Student[3]; Student s1 = new Student("张三", 100); Student s2 = new Student("李四", 60); Student s3 = new Student("王五", 80); students[0] = s1; students[1] = s2; students[2] = s3;
for (int j = 0; j<students.length-1;j++){ for (int i = 0;i<students.length-1-j;i++){ if (students[i].compareTo(students[i+1])>0){ Student temp = students[i]; students[i] = students[i+1]; students[i+1] = temp; } } }
for (int i = 0; i < students.length; i++) { System.out.println(students[i]); } } }
|
java.util.Comparator
思考:
(1)如果一个类,没有实现Comparable接口,而这个类你又不方便修改(例如:一些第三方的类,你只有.class文件,没有源文件),那么这样类的对象也要比较大小怎么办?
(2)如果一个类,实现了Comparable接口,也指定了两个对象的比较大小的规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?
JDK在设计类库之初,也考虑到这种情况了,所以又增加了一个java.util.Comparator接口。
1 2 3 4 5
| package java.util;
public interface Comparator{ int compare(Object o1,Object o2); }
|
那么我们想要比较某个类的两个对象的大小,怎么做呢?步骤:
第一步:编写一个类,我们称之为比较器类型,实现java.util.Comparator接口,并重写方法
第二步:比较大小时,通过比较器类型的对象调用compare()方法,将要比较大小的两个对象作为compare方法的实参传入,根据方法的返回值决定谁大谁小。
- o1对象减o2大于0返回正整数
- o1对象减o2小于0返回负整数
- o1对象减o2等于0返回零
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| public class Student implements Comparator { private String name; private int score;
public Student() {
}
public Student(String name, int score) { this.name = name; this.score = score; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getScore() { return score; }
public void setScore(int score) { this.score = score; }
@Override public String toString() { return "Student{" + "name='" + name + '\'' + ", score=" + score + '}'; }
@Override public int compare(Object o1, Object o2) { Student s1 = (Student) o1; Student s2 = (Student) o2; return s1.getScore()-s2.getScore(); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class Test01 { public static void main(String[] args) { Student[] students = new Student[3]; Student s1 = new Student("张三", 100); Student s2 = new Student("李四", 60); Student s3 = new Student("王五", 80); students[0] = s1; students[1] = s2; students[2] = s3;
Student student = new Student();
for (int j = 0; j<students.length-1;j++){ for (int i = 0;i<students.length-1-j;i++){ if (student.compare(students[i],students[i+1])>0){ Student temp = students[i]; students[i] = students[i+1]; students[i+1] = temp; } } }
for (int i = 0; i < students.length; i++) { System.out.println(students[i]); } } }
|
总结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| 1.异常: a.分类:Throwable Error:错误 Exception:异常 编译时期异常:一编译,就爆红(主要还是调用了某个方法,某个方法底层抛了一个编译时期异常) Exception以及子类(除了RuntimeException之外) 运行时期异常:一运行就报错 RuntimeException以及子类 2.异常处理: throws try...catch 3.finally:不管是否有异常都会执行的代码,要配合try...catch使用 finally的使用场景:关闭资源使用 4.自定义异常: a.定义一个类,继承Excption,变成了编译时期异常 继承RuntimeException,变成了运行时期异常 b.提供构造方法,便于设置异常信息 5.Object:所有类的根类,任何类都会直接或者间接继承Object类 a.toString方法: 没有重写,直接输出对象名,调用的是Object中的toString方法,输出地址值 重写了,直接输出对象名,默认调用重写的toString方法,输出对象内容 b.equals方法: 没有重写,比较对象地址值 重写了,比较对象内容 c.clone方法:需要实现Cloneable接口,重写clone方法 复制一个地址值不一样,属性值一样的对象 6.经典接口: Comparable Comparator
|