
封装:将重复代码写到函数中,需要使用的时候 通过函数调用形式让代码执行。 面向对象思想始于封装。 两种情况:1 类的封装[数据模型类封装 其他类封装 ] 2 工具类封装 [数据工具类封装 ArrayTool] 你能封装一个工具类 其他人也能,官方就封装了一个 Arrays Arrays.equals() 判断俩数组是否完全一样 Arrays.sort() 数组排序 Arrays.toString() 将数组转换成格式化字符串 Arrays.copyOf() 克隆数组 Arrays.copyOfRange() 提取范围 前闭后开 Arrays.binarySearch() 查找出现的索引 没找到返回-11.2 为什么需要异常
我们写过一个函数 getMax() 有问题
public class ArrayTool {
public static int getMax(int[] arr){
int max = arr[0];
for(int i=1;imax){
max = arr[i];
}
}
return max;
}
}
当一个数组里面一个数据都没有的时候 就没有最大值一说了。
@Test
public void test(){
int[] arr = {};
int a = ArrayTool.getMax(arr);
System.out.println(a);
}
所以我们今后的代码 70%都是安全判断 30%代码是业务流程 所以我们获取最大值的函数也应该是 先判断是否能获取最大值
public static int getMax(int[] arr){
if(arr.length == 0){
return -1;
}
int max = arr[0];
for(int i=1;imax){
max = arr[i];
}
}
return max;
}
但是我们加了判断之后 发现了一个可怕的问题 条件成立该返回什么呢?
发现返回什么都不好使 返回0 -1 本身就有歧义 返回其他的类型又不匹配 所以说return什么都不行
所以java就造了一套新的返回形式 异常返回
我们以前说 有返回值的函数 一定要有一个可以执行的 return ,但是从今天开始 这句话就不要再说了 因为java对于返回值 有两种形式
return 返回
throw 返回
1.3throw解决问题
public class ArrayTool {
public static int getMax(int[] arr){
if(arr.length == 0){
throw new RuntimeException("?????? 数组为空");
}
int max = arr[0];
for(int i=1;imax){
max = arr[i];
}
}
return max;
}
}
什么时候return 什么时候throw?
如果调用者传递的数据没有问题
我们函数执行方能根据参数正常执行 那就正常return返回
如果传递过来的数据有问题 导致无法正常执行 则 异常throw返回
public void test(){
String str = "hello world";
char a = str.charAt(-50);
System.out.println(a);
}
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
1.4 执行方抛出异常语法
throw 异常对象1.5 异常的分类
Throwable 可抛出的
Error :错误,指的是程序内部出现问题,无法通过代码解决的 例如 OutOfMemoryError 内存超出错误,简单的说 就是内存不够了
[说是代码无法解决 还是你代码的问题 例如 死循环]
Exception:异常,程序传递数据的时候导致无法正常执行代码,通过异常表示。
运行时异常 RuntimeException 和其子类 :程序运行起来之后才会出现的异常 例如:
非运行时异常 RuntimeException分支以外的都称之为非运行时异常:代码写完就会出现 必须要解决 不解决无法执行
例如 Class.forName("123123123");
我们需要记住分类的情况 还要记住常用的异常.
序号 异常名称 异常描述
1 java.lang.ArrayIndexOutOfBoundsException 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
2 java.lang.ArithmeticException 算术条件异常。譬如:整数除零等。
3 java.lang.SecurityException 安全性异常
4 java.lang.IllegalArgumentException 非法参数异常
5 java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常
6 java.lang.NegativeArraySizeException 数组长度为负异常
7 java.lang.NullPointerException 空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。
序号 异常名称 异常描述
1 IOException *** 作输入流和输出流时可能出现的异常
2 EOFException 文件已结束异常
3 FileNotFoundException 文件未找到异常
序号 异常名称 异常描述
1 ClassCastException 类型转换异常类
2 ArrayStoreException 数组中包含不兼容的值抛出的异常
3 SQLException *** 作数据库异常类
4 NoSuchFieldException 字段未找到异常
5 NoSuchMethodException 方法未找到抛出的异常
6 NumberFormatException 字符串转换为数字抛出的异常
7 StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
8 IllegalAccessException 不允许访问某类异常
9 InstantiationException
当应用程序试图使用Class类中的newInstance()方法创建
一个类的实例,而指定的类对象无法被实例化时,抛出该异常
10 java.lang.ClassNotFoundException 找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
1.6 调用方处理异常
A 异常转移(默认方案)
当执行方抛出异常给调用方的时候 ,此时调用方可以使用异常转移的形式来处理异常。
异常转移的语法:
@Test
public void test() throws ClassNotFoundException {
Class.forName("123123123");
}
在函数的参数后面添加一个 throws 关键字,后面写要转移的异常类。
此时当前异常会转移给当前函数的调用者。 上层调用者需要去处理本次异常,如果上层一直选择转移,最后就会转移到JVM。JVM就会帮我们去处理异常。
JVM处理异常的方式非常简单:终止当前程序 打印异常信息到控制台
异常转移可以转移多种异常
@Test
public void test() throws ClassNotFoundException, FileNotFoundException {
Class.forName("asdf");
new FileOutputStream("123");
}
也可以转移一个总异常
@Test
public void test() throws Exception {
Class.forName("asdf");
new FileOutputStream("123");
}
B 异常捕获
通过 try{}catch(Exception e){} 代码块进行异常捕获
@Test
public void test() {
try {
Class.forName("asdf");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
try{
// 可能出现异常的代码
}catch(异常类型 名字){
//出现异常之后的解决方案
}
1.7 catch中异常处理方案
@Test
public void test() {
try {
int a = 0;
int b = 0;
int i = a/b;
System.out.println(i);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("123123123");
}
并且catch可以捕获多个异常:分类捕获
@Test
public void test() {
try {
Class.forName("123");
new FileOutputStream("123");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
但是不能把总异常写到前面
@Test
public void test() {
try {
Class.forName("123");
new FileOutputStream("123");
} catch (Exception e){
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
因为异常的catch是从上往下依次查找执行的 所以我们捕获总异常一般写到最后用来兜底
@Test
public void test() {
try {
Class.forName("123");
new FileOutputStream("123");
System.out.println("12313123123123");
System.out.println("12313123123123");
System.out.println("12313123123123");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
此时 我们的catch 是分类捕获 还是 只捕获总的呢?
分情况: 如果我们不一样的异常处理方案不一样 就需要分类捕获 如果所有的异常处理方案都一样 则直接捕获总的
1 封装函数
2 调用者传递参数可能非法
3 执行方 安全判断 有问题的异常返回 throw 异常对象
4 异常的分类
Throwable Error Exception : 运行时 和 非运行时
5 调用方处理异常
A 异常转移 不处理默认走转移 转移方式 函数后面添加 throws 异常类名 可以写多个 如果一直转就到了JVM 就终止了 打印了
B 异常捕获 通过try{}catch(){} try中写可能出现异常的代码 catch用来在try中代码出现异常之后 处理异常
6 catch 特点: 1 try中出现问题 则直接去catch中执行 接下来try的代码不执行了
2 catch也不是精准制导 而是从上往下依次询问 所以总异常不能写到最上面 应在在最后兜底
3 有的时候我们只写一个总的 因为我们不需要分类处理 统一处理的时候只捕获 Exception
1.8 finally代码块
我们之前讲过final关键字,代表最终的。今天是finally代码块 代表最终执行的代码。也就是说写到finally中的代码 铁定最后要执行
@Test
public void test() {
try {
int i = 1/0;
}catch (Exception e){
e.printStackTrace();
}finally {
// 以后我们关闭的代码写到这里面
System.out.println("123");
}
}
面试题:
1 final 和 finally 和 finalize 的区别?
2 try catch finally 哪些可以组合使用
try-catch try-catch-finally try-finally
3 在try中有个return 请问finally中的代码还执行吗? return前执行还是return后执行?
public class ArrayTool {
public static int haha(){
try {
return 666;
}finally {
System.out.println("你好世界");
}
}
}
如果finally中也有个return 请求到底是哪个生效
public class ArrayTool {
public static int haha(){
try {
return 666;
}finally {
return 777;
}
}
}
1.9 自定义异常
首先我们看一下 Throwable 源码
public void printStackTrace() {
printStackTrace(System.err);
}
看一下Exception 源码
public class Exception extends Throwable {
static final long serialVersionUID = -3387516993124229948L;
public Exception() {
super();
}
public Exception(String message) {
super(message);
}
public Exception(String message, Throwable cause) {
super(message, cause);
}
public Exception(Throwable cause) {
super(cause);
}
protected Exception(String message, Throwable cause,
boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
public
class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
private static final long serialVersionUID = -5116101128118950844L;
public ArrayIndexOutOfBoundsException() {
super();
}
public ArrayIndexOutOfBoundsException(int index) {
super("Array index out of range: " + index);
}
public ArrayIndexOutOfBoundsException(String s) {
super(s);
}
}
我们发现 整个集成体系中 子类基本上什么都没有写 全都是调用父类Throwable的函数 子类就写了个构造函数 构造函数还是调用父类的构造函数
发现Throwable的子类一点新东西都没有,那为什么还要建立这一套继承体系呢?
这样做的目的 为了有语义化
假如没有这些子类 此时所有的以异常只能Throwable表示,代码实现的角度将没有毛病,但是从语义的角度将 我们就很难区分此时的异常到底是 越界了?还是类找不到了?还是文件找不到了?
java的设想非常好 ,但是无法将全部的异常情景给罗列出来,例如 我现在遇到一个问题 账号不存在 ,没有一个异常能语义化表达这层
所以我们可以自定义异常
public class UsernameNotFoundException extends RuntimeException {
private static final long serialVersionUID = -5116101128118950844L;
public UsernameNotFoundException() {
super();
}
public UsernameNotFoundException(String s) {
super(s);
}
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)