封装:将重复代码写到函数中,需要使用的时候 通过函数调用形式让代码执行。 面向对象思想始于封装。 两种情况: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条)