第十一章
异常(Exception)
-
异常的概念
-
异常体系图!!!
-
常见的异常
-
异常处理!!!
-
自定义异常
-
throw和throws的对比
将该代码块选中
快捷键ctrl + alt + t
然后选择try-catch
异常
异常介绍
基本概念:Java语言中,将程序执行中发生的不正常情况称为异常(开发过程中的语法错误和逻辑错误不是异常)
执行过程中所发生的异常可分为两类
-
Error(错误):Java虚拟机无法解决的严重问题。如:JVM系统内部错误,资源耗尽等严重情况
-
Exception:其他因变成错误而偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。比如:空指针的访问,试图读取不存在的文件,网络连接中断等。
-
运行时异常(有默认的处理机制)
-
编译时异常
-
异常体系图
体现了继承和实现关系
-
运行时异常
-
编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常
-
java.lang.RuntimeException类及它的子类都是运行时异常
-
对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响
-
-
编译时异常
- 要求必须处置的异常
常见运行时异常
-
NullPointerException空指针异常
-
ArithmeticException实现运算异常
-
ArrayIndexOutOfBoundsException数组下届标越界异常
-
ClassCastException类型转换异常
-
NumberFormatException数字格式不正确异常
常见的编译异常
-
SQLException//操作数据库时,查询表可能发生异常
-
IOException//操作文件时发生异常
-
FileNotFoundException//当操作一个不存在的文件时发生异常
-
ClassNotFoundException//加载类找不到时的异常
-
EOFException//操作文件,到文件的末尾发生异常
-
IllegalArguementException//参数异常
异常处理
-
try -catch - finally
- 程序员在代码中捕获发生的异常,自行处理
//程序如下try{代码可能有异常}catch(Exception e){//捕获异常//系统将异常封装成Exception对象e,传递给catch//得到异常对象后,程序员自己处理//注意:如果没有发生异常catch代码块不执行}finally{//不管try代码块是否有异常发生,最终都要执行finally//通常将释放资源的代码,放在finally}//注:没有finally,语法是允许
-
throws
-
将发生的异常抛出,交给调用这来处理,最顶级的处理者就是JVM
-
JVM处理异常
-
输出异常
-
退出程序
-
-
注意事项
-
try - catch
-
如果异常发生了,则异常发生后面的代码不会执行,直接进入catch块
-
如果异常没有发生发生,则顺序执行try的代码块,不会进入catch
-
如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),则使用finally()
-
可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前。(比如:Exception在后,NullPointerException在前)如果发生异常,只会匹配一个catch
-
允许使用try - finally 配合使用。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
-
//try - catch 的使用实例public class data01 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int a;while(true){try {System.out.println("请输入一个数字");a = Integer.parseInt(scanner.nextLine());System.out.println("输入成功");break;} catch (NumberFormatException e) {System.out.println(e.getMessage());}}}}
异常处理
-
throws
-
如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应现实的声明抛出异常,表明该方法将不对这些异常处理,而由该方法的调用着负责处理
-
在方法声明中throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类
-
public class data01 {public static void main(String[] args) {}public void f2() throws Exception{//throws 抛出异常 放调用f2的调用者 处理//throws 后面的异常类型可以是方法中参数的异常类型,也可以是它的父类//throws 关键字后可以是 异常列表,即可以抛出多个异常FileInputStream fis = new FileInputStream("d://aa.txt");}}
细节
-
对于编译异常,程序必须处理
-
运行异常,程序中如果没有处理,默认就是throws的方式处理
-
子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型与父类抛出的异常一致,或是父类抛出异常的类型的子类型
-
在throws过程中,如果由方法try-catch,就相当于处理异常,就不必throws
自定义异常
概念:当程序出现某些“错误”,但该错误没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该类错误信息
步骤
-
自定义异常类名(程序员自己写)继承Exception或RuntimeException
-
如果继承Exception,属于编译异常
-
如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)
//写一个自定义异常//一般情况下,我们自定义是继承RuntimeExcception//即把自定义异常做成运行异常,好处是我们可以使用默认处理机制public class data01 {public static void main(String[] args) {int age = 10;if(!(age >= 18 && age <= 125)){throw new AgeException("年龄范围错误");}}}class AgeException extends RuntimeException {public AgeException(String message) {super(message);}}
throw和throws的区别
常用类
-
String
-
StringBuffer
-
StringBuilder
-
Math
-
Data,Calendar,LocalDate
-
System
-
Arrays
-
BigInteger BigDecimal
String,StringBuffer,StringBuilder
包装类(wrapper)
-
针对八种基本数据类型相应的引用类型–包装类
-
有了类的特点,就可以调用类中的方法
接口的实现和关系的继承
包装类和基本数据的转换
* jdk5前是手动装箱和拆箱的方式* 装箱:基本类型->包装类型//手动装箱int n1 = 10;Integer a1 = new Integer(n1);Integer a2 = Interger.valueOf(n1);//手动拆箱int i = a1.intValue();//jdk5之后就可以自动装箱和自动拆箱了//底层还是调用手动装箱int n2 = 200;Integer a3 = n2;//自动拆箱int n3 = a3;
-
jdk5以后是自动装箱和拆箱
-
自动装箱底层调用的是valueOf方法,比如Integer.valueOf()
包装类型和String相互转换
Integer i = 100;//方式1String str1 = i + "";//方式2String str2 = i.toString();//方式3String str2 = String.valueof(i);//打String转换成包装类String str4 = "12345";Interger i2 = Interger.parseInt(str4);Interger i3 = new Integer(str4);//用构造器
常用的一些方法
String类
-
理解:String对象用于保存字符串,也就是一组字符序列
-
字符串常量对象是用双引号括起来的字符序列
-
字符串的字符使用Unicode字符编码,一个字符占两个字节
-
String类常用构造器
String s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[]a);
String s4 = new String(char[]a,int startIndex,int count); -
String实现了接口 Serializable(String 可以串行化:可以网络传输)
-
String实现了接口Comparable(说明String对象可以比较大小)
-
String 是final类,它不能被其他的类继承
-
String 有属性 private final char value[];用于存放字符串内容
-
注意:value是一个final类型,不可以修改(它指向的地址不可修改,但是单个字符内容是可以变化的)
-
补充:final修饰数组时的知识
public class data01{public static void main(String[] args) {final char[] m = {'a','b'};for(char arr:m){System.out.println(arr);}m[0] = 'l';for(char arr:m){System.out.println(arr);}//这里的final 是指不能改变数组指向的空间//但是数组内部的元素可以修改}}
String的创建
-
直接赋值
- 先从常量池查看是否有赋值对象的数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址
-
调用构造器
- 先在堆中创建空间,里面维护了value属性,指向常量池的赋值对象空间。如果常量池没有该对象,重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址
补充:intern方法(如果池中已经包含一个等于此String对象的字符串(用equals(Object)方法确定),则返回池中的字符串。否则将此String对象添加到池中,并返回此String对象的引用)
b.intern()方法最终返回的是常量池的地址
字符串特性
String a = "hello";
String b = "abe";
String c = a + b;//问:上面这段代码创建了几个对象
//答:3个
String的常用方法
说明:String类是保存字符串常量的。每次更新都需要重新开辟空间,效率低,因此java设计者还提供了StringBuilder和 StringBuffer 来争强String的功能,并提高效率
-
equals
- 区分大小写,判断内容是否相等
-
equalslgnoreCase
- 忽略大小写的判断内容是否相等
-
length
- 获取字符的个数,字符串的长度
-
indxOf
- 或许字符在字符串中第一次出现的索引,索引从0开始,如果找不到,返回-1
-
lastIndeOf
- 最后出现的位置,获取字符在字符串中最后异常出现的索引
-
substring
- 截取指定范围的字串
-
trim
- 去前后空格
-
charAt
- 获取某索引处的字符,注意不能使用Str[index] 这种方式
-
toUpperCase
-
toLowerCase
-
concat
- 拼接字符串
-
replace
- 替换字符串中的字符
-
split
-
分割字符串,对于某些分割字符
-
比如以逗号为标准,进行分割,返回数组
-
注意转义字符
-
-
compareTo
-
比较两个字符串的大小
-
两个字符串的长度不等时,会返回长度差
-
相等时,返回Ascii码值的差值
-
-
toCharArray
- 转换成字符数组
-
format
- 格式字符串,%s字符串 %c字符%d整%f浮点型
StringBuffer类
介绍:该类代表可变的字符序列,可以对字符串内容进行增删,很多方法与String相同,但StringBuffer是可变长度的,StringBuffer是一个容器
它的父类AbstractStringBuilder 有属性 char[] value, 不是final ,该value 数组存放字符串的空间是堆空间,StringBuffer 是一个final类,不能被继承
-
String 和 StringBuffer 的对比
-
String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率低//private final char value[];
-
StringBuffer 保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用更新地址,效率高 // char[] value; 放在堆
-
StringBuffer的构造器
-
StringBuffer()
- 构造一个其中不带字符的字符串缓冲区,其初始容量为16分字符
-
StringBuffer(int capacity)
- 构造一个不带字符,但具有指定初始容量的字符串缓冲区,即堆char[] 带下进行指定
-
StringBuffer(String string)
-
构造一个字符串缓冲区。并将其尼尔初始化为指定的字符串内容
-
大小为:字符串的大小加16
-
StringBuffer和String之间的相互转换
public class data01{public static void main(String[] args) {//感受String 和 StringBuffer 之间的转换String a = "Dog";//方式一,直接传参StringBuffer stringBuffer = new StringBuffer(a);//方式二,使用append方法StringBuffer stringBuffer1 = new StringBuffer();stringBuffer1.append(a);System.out.println(stringBuffer);System.out.println(stringBuffer1);StringBuffer b = new StringBuffer("good");//方式一:直接传参String b1 = new String(b);//方式二:使用toString方法String b2 = b.toString();System.out.println(b1);System.out.println(b2);}}
StringBuffer的常用方法
-
append
- 增
-
delet(start,end)
-
replace(start,end,string)
- 将start ----end 间的内容替换掉,不含end
-
indexOf
- c查找子串在字符串第1次出现的索引,如果找不到就返回-1
-
inser(start,string)
- 在索引位置插入string,原来为start的内容自动后移
-
length
StringBuilder类
基本介绍:一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数现实中,它比StringBuffer要快
在StringBuilder 上的主要操作是append和insert方法,可重载这些方法,以接受任意类型的数据
-
StringBuilder 继承 AbstractStringBuilder 类
-
实现了Serializable ,说明StringBuilder对象是可以串行化(对象可以网络传输,可以保存到文件)
-
StringBuilder是final类,不能被继承
-
StringBuilder 对象字符序列仍然存放在其父类AbstractStingBuilder 的 char[] value; 因此,字符序列在堆中
-
StringBuilder的方法 ,没有做互斥的处理,即没有synchronized 关键字,因此在单线程的情况下使用StringBuilder
比较String,StringBuffer,StringBuilder
-
String:不可变字符序列,效率低,但复用率高
-
StringBufffer:可变字符序列,效率较高(增删),线程安全
-
StringBuilder:可变字符序列,效率最高,线程不安全
使用原则
-
如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder
-
如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
-
如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
-
如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息
Math类
-
abs
- 绝对值
-
pow
- 求幂
-
ceil
- 向上取整
-
floor
- 向下取整
-
round
- 四舍五入
-
sqrt
- 求开方
-
random
- 求随机数
-
max
- 求两个数的最大值
-
min
- 求两个数的最小值
Arrays类
-
toString
-
Arrats.toString(arr)
-
返回数组的字符串形式
-
-
sort
-
自然排序sort(arr)
-
定制排序 传入两个参数
-
排序数组
-
实现Comparator接口的匿名内部类,要求实现 compare方法
-
-
//自定义实现sortpublic class data01 {public static void main(String[] args) {Book[] book = new Book[5];book[0] = new Book(23,"好人");book[1] = new Book(39.9,"猪猪");book[2] = new Book(15.3,"狗子");book[3] = new Book(99.9,"one");book[4] = new Book(74.2,"数学");Arrays.sort(book,new Comparator<Book>() {@Overridepublic int compare(Book o1, Book o2) {double tmp = o1.getPrice()-o2.getPrice();if(tmp>0) return 1;if(tmp<0) return -1;return 0;}});for(Book m: book) {m.f();}}}class Book{public Book(double price, String name) {this.price = price;this.name = name;}double price;String name;public void f(){System.out.println(price);}public double getPrice() {return price;}}
-
binarySearch
-
通过二分搜索法镜像查找,要求必须排好
-
int index = Arrays.binarySeach(arr,3);
-
如果数组中不存在该元素,就返回 -(low +1)
-
注:low是因该存在的地方
-
-
copyOf
-
数组元素的复制
-
Integer[] num = Arrays.copyOf(arr,arr.length);
-
如果拷贝的length大于原数组的长度,就会增加null
-
如果小于,就会抛出异常
-
-
fill
-
数组元素的填充
-
使用第二个参数,来替换原数组的所有元素
-
-
equals
-
比较两个数组元素的内容是否完全一致
-
如果完全一样,就返回真
-
-
asList
- 将数组转换成List
System
-
exit
-
退出当前程序
-
exit(0)
-
这里的0代表状态,0----代表正常状态
-
-
arraycopy:
- 复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组
int[] src = {1,2,3};int dest = new int[3];System.arraycopy(src,0,dest,0,3);//五个参数的意义//第一个参数 原数组//第二个参数 原数组的那一索引开始拷贝//第三个参数 目标数组//第四个参数 拷贝到目标数组的哪一个位置//第五个参数 拷贝多少个数据
-
currentTimeMillens
- 返回当前的时间距离 1970 -1-1的毫秒数
-
gc
- 运行垃圾回收机制
BigInteger 和 BigDecimal
应用场景:
BigInteger:适合保存比较大的整型
BigDecimal:适合保存精度更高的浮点数
BigInteger:存较大的数据适合,用双引号引起来
注:进行加减乘除的时候,需要使用相应的方法,不能直接进行 + - * /
-
add
- 加
-
subtract
- 减
-
multiply
- 乘
-
divide
- 除
注:使用BigDecimal时,使用除法可能会出现异常(除不尽)
解决方案:在调用divide 的时,指定精度
BigDecimal.divide(bigDecimal2,BigDecimal.ROUND_CEILING)
Data,Calendar,LocalData
-
第一代日期Data
-
精确到毫秒,代表特定的瞬间
-
SimpleDataFormat:格式和解析日期的类
-
SimpleDateFormat:格式化和解析日期的根据类,它允许进行格式化(日期->文本),解析(文本->日期)和规范
-
-
第一代
-
第一种
-
Data d1 = new Date();
-
获取当前的时间,默认输出的是国外的格式,通常需要对时间进行一个转换
-
SimpleDateFormat sdf = new SimpledateFormat("yyyy年MM月dd日 hh:mm:ss E“)
-
这里的格式使用的字母是规定好的
- String format = sdf.format(d1);
-
-
第二种
- Data d2 = new Data(long);
-
第三种
-
可以把一个格式化的String转成对于的Date
-
输出时,默认是国外的格式
-
在转化格式时,使用的格式需要和String的格式一样,否则会抛出转换异常
String s = “1997年01月01日 10:20:30 星期一”;
Date parse = sdf.parse(s);
System.out.println(“parse=” + parse);
-
Canlender(第二代)
Calendar类是一个抽象类,他为特定瞬间与一组诸如 年月日时 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法
-
Calendar是一个抽象类,并且构造器是private
-
可以通过getInstance()来获取实例
-
提供大量的方法和字段提供程序员
-
Calendar没有提供对于的格式化的类,因此需要程序员自己组合来输出
-
需要24小时进制来获取时间,将Calendar.HOUR----> Calendar.HOUR_OF_DAY
Calendar c = Calendar.getInstance();//创建日历信息//注:每一个时间信息需要我们自己组合System.out.println("月" + c.get(Calendar.YEAR);//so on
前两代日期类的不足分析
JDK 1.0 中包含一个java.util.Data类,但是它的大多数方法已经在JDK 1.1 引入 Calendar 类之后被弃用了。而Calendar也存在问题是:
-
可变性:向日期和时间这样的类应该是不可变的
-
偏移性:Date中的年份是从1900开始的,而月份都是从0开始
-
格式化:格式化只对Date有用,Calendar 则不行
-
此外,他们线程不安全
-
不能处理润秒(每隔两天,多出1s)
第三类(日期类)
-
LocalDate(年月日)
-
LocalTime(时分秒)
-
LocalDateTime(年月日时分秒)
第三类是在JDK8加入的
格式化
Instant(时间戳)
写在后面的话
看到很多小伙伴,在leetcode里坚持刷了一个学期的题目,羡慕之情。羡慕他们真的能坚持做成一件事情,羡慕他们学到了一些具体的东西。我呢!?这一章学的很模糊,前面的异常处理大概是听懂了,但我不知道这东西能在代码中如何使用。后面的8大类的一些方法,感觉就是一些死记硬背的东西,多用就熟练后,自然能记得。
哎!谈不上迷茫,东西要学的还很多。只是快到年底了,蓦然回首,微微有些感概罢了!!!