1、异常
异常: 程序在运行时出现的非正常状况, 会导致程序崩溃. 应该处理异常.
异常分类
1)受检异常,编译时异常。程序中必须处理的异常,如果不处理,编译会出错。主要包括了Exception及其子类(除了RuntimeException及其子类):不容忽视的一般问题
2)非受检异常,运行时异常。可以不接受检查和处理的异常,如果不处理,编译不会出错,但运行时会出错。主要包括:Error及其子类:太严重;RuntimeException及其子类:太轻微,太常见
异常处理
1、捕获(异常处理最重要的方式)
try catch 可以随意嵌套
try {
可能抛出异常的语句
} catch (XxxException e) {
如果真的抛出了XxxException异常对象后, 要执行这个块
} catch (Xxx2Exception e) {
如果真的抛出了Xxx2Exception异常对象后, 要执行这个块
} catch (Exception e) {
如果真的抛出了其他Exception异常对象后, 要执行这个块
} finally {
无论前面try catch中发生什么, 一定要执行的代码, 通常在这里要释放不在GC区中的资源
}
捕获和不捕获最大的区别?
核心代码是否执行。
2、抛出:throws才是抛出
1)在方法声明中添加throws 后面跟上异常类型列表, 作用是警告调用者, 此方法有可能的风险!!!
2)在方法中使用throw语句,后面跟一个异常对象,实现抛出动作
3)throw语句一旦执行,效果和return一样,会导致方法提前弹栈结束,但是会让调用者不爽
4)throw是一个良好的消息传递机制 。
5)throws后的异常抛出可以是模糊的,可以是列表,可以是整体
throw和throws的关系
1)如果方法声明中有throws,方法体中可以没有throw
2)在方法体中有throw,则在方法证明中必须要有相对应的throws
3)throw 是真的发生,throws是警告,不一定发生
4)hrows应该要和throw对应,诚实!!!
5)throws才是抛出,throw只是语句
throws什么时候用?
受检异常中必须有throws,否则编译不通过
非受检异常中不必须有throws
throws更重要
main() 中尽量不用throws抛出异常,而用try catch 捕获
throw和return 的区别?
return正常结束,和平返回
throw异常结束,带异常返回,会让调用者不爽。
什么情况下抛出异常?
方法不能往下走了
创建用户自定义异常
1)继承Exception
2)提供若干构造器
从父类中传,通常是两个,String massage 和 Throwable cause
如果父类是Exception,自定义异常就是受检异常
要在方法声明中加 thows 解决该问题,免责(药品使用说明书)
不需要无参构造器,防止传入没有没有内容的字符串
回忆方法覆盖
方法覆盖:子类根据父类重写从父类中继承的方法
1)方法的签名完全一致,包括返回值类型,方法名,参数列表
返回值类型如果是引用类型(对象),在子类重写方法时,返回值的类型可以时父类方法返回值类型的子类
例如,父类是Object,可以返回String等类型
而基本类型不可以这样!!!
2)子类的访问控制修饰符要大于等于父类
3)父类和子类方法都必须是非static
4)子类重写方法抛出的受限异常要小于等于父类抛出的受限异常
如果是非受限异常随便抛
因为虚方法调用是以父类为准,运行时以子类为准,要保证catch能接住
3、捕获再抛出异常(最常用)
在方法中先捕获一个已知异常,再捕获到这个异常时,再把它包装到一个自定义异常中,再抛出自定义异常
包装的好处:
1)便于把现有异常都统一成自定义异常。
2)可以随意转换异常的类型,受检异常和非受检异常
包装的本质是对象关联,,一个对象把另一个对象作为成员属性
下图自定义异常包装了已知异常
异常有连锁反应
定位异常找cause by
什么时候使用?
将受检异常包装成非受检异常
有时候希望调用者重视此方法时使用
实际选择依据
看方法在栈中的地位
1)如果方法出问题不会影响栈的生存,尽量抛出异常,因为它时一种更强力的消息传递机制
2)如果方法出问题会影响到栈的生存,尽量捕获异常,防止栈的销毁,栈一旦毁掉,线程就死
main方法补,其他功能方法抛
2、Java中的常用类
单元测试
单元测试不是jdk内置,必须依赖第三方库,jar文件
单元测试方法坐在的类必须是公共类,类中不允许有任何构造器
单元测试方法本省时公共非静态,无参,无返回值
好处:方便运行,不再使用main方法作为测试类的入口
导入第三方库的步骤
1) 复制需要的.jar文件
2) 在项目下新建目录lib, 粘贴.jar文件
3) 把.jar文件添加到项目配置中,右击.jar文件, 选中"Add as Library"
4) 打开moudle设置, 把.jar再添加到module中即可
1)包装类
目的:一切皆对象
作用:把基本数据包装成对象类型,基本数据类型有8个,包装类也是有对应的8个
注意:包装类对象不兼容相关类
装箱(boxing):把基本数据值变成对象的过程
手工装箱 Xxx obj = new Xxx(xxx);
自动装箱:Xxx obj = xxx;
Xxx obj = new Xxx("xxx");
拆箱(unboxing):把包装类对象的基本值取出来
手工拆箱:xxx = obj.xxxValue();
自动拆箱:xxx = obj;
字符串和基本值的转换
把字符串转换为基本值
xxx = Xxx.parseXxx("xxx");
基本值转换为字符串
String s = "" + xxx;
2)字符串(String)相关类
String : 内容不可改变的Unicode字符序列(CharSequence),任何的修改都会产生新的字符串对象
字符串的本质是char数组, 每个字符在String中是有索引的
但不能说字符串就是char数组
s本身变了,但是对象本体不改变
字符串常量放在常量区
字符串拼接注意点:
1)字符串的修改会产生新的字符串对象, 在GC区
String s6 = (s1 + s2); // "atguigujava"
2) intern();把GC区中的字符串拘留到常量区, 如果常量区已经有此对象, 直接返回地址. 如果没有塞入常量区
String s6 = (s1 + s2).intern();
3) 如果全是常量参与接接, 接接的结果还是在常量区
String s7 = "atguigu" + "java";
4)只要有一个变量参与了接接, 结果一定在GC区, 但是如果s1有final修饰, 也算为常量
String s8 = s1 + "java";
3、字符串常见方法
String str = " abc QQQ 我喜欢你, 你喜欢我吗? 我不喜欢你 yyyAZZ ";
1)public int length() : 获取字符串的长度, 字符个数
str.length() => 37
2)public char charAt(int index) 获取参数中指定的下标位置处的字符, 像数组[]操作
str.charAt(12) => '欢', str.charAt(30) => 'y'
3)public char[] toCharArray() 获取字符串相应的char[]的副本
第一个参数是源数组对象, 第2个参数是源数组的开始下标
第3个参数是目标数组对象, 第4个参数是目标数组的开始下标, 第5个参数是要复制的元素个数.
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
内部实现
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
4) public int indexOf(String str) : 检索参数中的子串在当前字符串中首次出现的下标, 从左向右检索
str.indexOf("喜欢") => 11
5)public int indexOf(String str ,int fromIndex) : 检索参数中的子串首次出现的下标, 从fromIndex位置开始
str.indexOf("喜欢", 0) => 11
str.indexOf("喜欢", 12) => 17
str.indexOf("喜欢", 18) => 25
str.indexOf("喜欢", 26) => -1
5)public int lastIndexOf(String str) : 检索参数中的子串首次出现的下标, 是从右向左检索
str.lastIndexOf("喜欢") => 25
6)public int lastIndexOf(String str ,int fromIndex) : 检索参数中的子串首次出现的下标, 是从右向左检索, 从fromIndex开始
str.lastIndexOf("喜欢", 24) => 17
str.lastIndexOf("喜欢", 16) => 11
str.lastIndexOf("喜欢", 10) => -1
总结
今天学习的内容:
1)异常处理的3种方式;
2)字符串相关类和方法