Java 进阶(三):包装类与异常处理 前言这一篇继续 Java 进阶语法包装类与异常处理。包装类解决了基本类型不是对象的问题让基本类型也能参与面向对象的操作。异常处理则是程序健壮性的第一课写代码不可能不出错关键是怎么去处理错误。期待和你的一起进步一、为什么要使用包装类1.1 基本类型的局限Java 有 8 种基本类型byte、short、int、long、float、double、char、boolean。它们用起来很方便但有几个问题不是对象不能调用方法不能参与面向对象的操作不能为 null无法表示没有值的状态集合不能存基本类型ArrayListint编译报错1.2 包装类的作用包装类就是把基本类型包装成对象解决上述问题。javaint num 10; // 基本类型 Integer numObj new Integer(10); // 包装类对象1.3 代码示例java// 集合只能存对象 ArrayListInteger list new ArrayList(); list.add(10); // 自动装箱int → Integer // 包装类可以调用方法 Integer num 10; System.out.println(num.toString()); // 10 System.out.println(num.compareTo(20)); // -1 // 包装类可以为 null Integer value null; System.out.println(value null); // true1.4 我的理解基本类型就像散装的零件包装类就像把零件装进盒子。装进盒子后就能贴标签、调用方法、放进集合里了。核心一句话包装类把基本类型变成对象让基本类型也能参与面向对象操作。二、8 种基本类型的包装类2.1 对应关系基本类型包装类父类byteByteNumbershortShortNumberintIntegerNumberlongLongNumberfloatFloatNumberdoubleDoubleNumbercharCharacterObjectbooleanBooleanObject2.2 记忆规律除了 int 和 char其他包装类都是首字母大写int→Integer特殊char→Character特殊数字类型的包装类都继承NumberCharacter和Boolean直接继承Object2.3 代码示例javaInteger i 10; Double d 3.14; Character c a; Boolean b true; // 数字类型的包装类可以互相转换 Number num 10; // 向上转型 System.out.println(num.intValue()); // 10 System.out.println(num.doubleValue()); // 10.0 System.out.println(num.longValue()); // 102.4 我的理解8 种包装类就像8 个盒子每个盒子对应一种基本类型。Integer装intDouble装double一一对应。核心一句话8 种基本类型对应 8 个包装类int→Integerchar→Character其余首字母大写。三、自动装箱与自动拆箱3.1 什么是装箱和拆箱装箱Boxing基本类型 → 包装类拆箱Unboxing包装类 → 基本类型3.2 手动装箱拆箱java// 手动装箱 Integer i1 Integer.valueOf(10); Integer i2 new Integer(10); // 手动拆箱 int num1 i1.intValue();3.3 自动装箱拆箱Java 5java// 自动装箱 Integer i 10; // 等价于 Integer.valueOf(10) // 自动拆箱 int num i; // 等价于 i.intValue()3.4 代码示例java// 自动装箱 ArrayListInteger list new ArrayList(); list.add(10); // int → Integer自动装箱 // 自动拆箱 int first list.get(0); // Integer → int自动拆箱 // 运算时自动拆箱 Integer a 10; Integer b 20; int sum a b; // a、b 自动拆箱后相加3.5 自动拆箱的坑javaInteger i null; int num i; // ❌ NullPointerException原因i是null自动拆箱时调用i.intValue()对null调用方法抛异常。3.6 我的理解自动装箱拆箱就像自动门你不需要手动推编译器自动帮你开。但要注意null拆箱会炸——就像对着空气推门直接摔倒。核心一句话自动装箱 valueOf自动拆箱 xxxValuenull 拆箱会 NPE。四、包装类的常用方法4.1 Integer 常用方法方法说明Integer.parseInt(String)字符串转 intInteger.valueOf(int)int 转 IntegerInteger.valueOf(String)字符串转 IntegerInteger.toString(int)int 转 StringInteger.compare(int, int)比较大小Integer.max(int, int)最大值Integer.min(int, int)最小值Integer.toBinaryString(int)转二进制字符串Integer.toHexString(int)转十六进制字符串4.2 代码示例java// 字符串转 int int num Integer.parseInt(123); System.out.println(num); // 123 // int 转字符串 String str Integer.toString(456); System.out.println(str); // 456 // 转二进制 System.out.println(Integer.toBinaryString(10)); // 1010 // 转十六进制 System.out.println(Integer.toHexString(255)); // ff // 比较 System.out.println(Integer.compare(10, 20)); // -1 System.out.println(Integer.max(10, 20)); // 204.3 其他包装类类似javaDouble.parseDouble(3.14); // 3.14 Boolean.parseBoolean(true); // true Long.parseLong(123456); // 123456L4.4 我的理解包装类的常用方法分三类转字符串、转基本类型、转进制。最常用的是parseXxx字符串转基本类型和valueOf转包装类。核心一句话parseXxx 字符串转基本类型valueOf 转包装类toXxxString 转进制。五、Integer 缓存机制5.1 什么是 Integer 缓存Integer 内部缓存了 -128 到 127 之间的对象这个范围内的值直接复用缓存不创建新对象。5.2 代码验证javaInteger i1 100; Integer i2 100; System.out.println(i1 i2); // true都在缓存范围内 Integer i3 200; Integer i4 200; System.out.println(i3 i4); // false超出缓存范围各自 new 对象5.3 源码分析javapublic static Integer valueOf(int i) { if (i IntegerCache.low i IntegerCache.high) return IntegerCache.cache[i (-IntegerCache.low)]; return new Integer(i); }IntegerCache.low -128IntegerCache.high 127默认可调范围内返回缓存对象范围外new Integer(i)5.4 其他包装类的缓存包装类缓存范围Byte-128 ~ 127全部Short-128 ~ 127Integer-128 ~ 127Long-128 ~ 127Character0 ~ 127Booleantrue / falseFloat无缓存Double无缓存5.5 我的理解Integer 缓存就像便利店常备零钱-128 到 127 这些常用面额直接备好谁来换直接给复用。超出范围的只能现造new。核心一句话Integer 缓存 -128 到 127范围内复用范围外新建比较一律用 equals。六、认识异常6.1 什么是异常异常Exception就是程序运行过程中出现的错误。javaint[] arr new int[3]; System.out.println(arr[5]); // ArrayIndexOutOfBoundsException6.2 异常的作用提示错误告诉开发者哪里出错了中断流程异常发生后续代码不执行可处理可以通过 try-catch 捕获并处理6.3 异常 vs 错误对比项异常Exception错误Error能否处理✅ 可以❌ 一般不能举例NullPointerExceptionOutOfMemoryError原因程序逻辑问题JVM 或系统问题6.4 我的理解异常就像开车时仪表盘亮红灯告诉你哪里出问题了你可以停车检查try-catch也可以继续开throws 抛出。核心一句话异常是程序运行中的错误可以捕获处理Error 是系统级错误一般无法处理。七、异常体系结构7.1 异常继承体系textThrowable / \ Error Exception / \ RuntimeException 其他异常 (运行时异常) (编译时异常)7.2 各层说明类说明Throwable所有异常和错误的根类Error系统级错误如 OutOfMemoryErrorException程序可处理的异常RuntimeException运行时异常编译期不强制处理其他 Exception编译时异常必须处理7.3 常见异常分类运行时异常RuntimeExceptionNullPointerExceptionArrayIndexOutOfBoundsExceptionClassCastExceptionArithmeticExceptionNumberFormatException编译时异常非 RuntimeExceptionIOExceptionFileNotFoundExceptionSQLExceptionParseExceptionClassNotFoundException7.4 我的理解异常体系就像家族树Throwable是老祖宗Error和Exception是两个分支。Exception又分两支RuntimeException运行时异常和其他编译时异常。核心一句话Throwable 是根Error 是错误Exception 是异常RuntimeException 是运行时异常。八、编译时异常与运行时异常8.1 区别对比项编译时异常运行时异常继承Exception非 RuntimeExceptionRuntimeException编译期检查✅ 强制处理❌ 不强制处理要求必须 try-catch 或 throws可处理可不处理举例IOExceptionNullPointerException8.2 代码示例java// 编译时异常必须处理 public void readFile() { try { FileReader reader new FileReader(test.txt); } catch (FileNotFoundException e) { e.printStackTrace(); } }java// 运行时异常可以不处理 public void divide() { int a 10; int b 0; int result a / b; // ArithmeticException编译期不报错 }8.3 为什么这样设计编译时异常可以预见的错误如文件不存在强制处理提高程序健壮性运行时异常通常是代码逻辑错误如空指针应该通过修改代码避免而不是靠捕获8.4 我的理解编译时异常就像出门前必须检查钥匙编译器强制你检查不检查不让出门。运行时异常就像走路可能摔跤编译器不强制你处理但你自己得小心。核心一句话编译时异常必须处理运行时异常可处理可不处理。九、try-catch-finally 处理异常9.1 基本语法javatry { // 可能出错的代码 } catch (异常类型 e) { // 处理异常 } finally { // 无论是否异常都会执行 }9.2 代码示例javapublic class Test { public static void main(String[] args) { try { int[] arr new int[3]; System.out.println(arr[5]); // 抛异常 } catch (ArrayIndexOutOfBoundsException e) { System.out.println(数组越界 e.getMessage()); } finally { System.out.println(finally 执行); } System.out.println(程序继续执行); } }输出text数组越界Index 5 out of bounds for length 3 finally 执行 程序继续执行9.3 多个 catchjavatry { String str null; System.out.println(str.length()); } catch (NullPointerException e) { System.out.println(空指针异常); } catch (Exception e) { System.out.println(其他异常); }注意子类异常在前父类异常在后。否则父类会拦截所有子类异常编译报错。9.4 finally 的特点特点说明一定执行无论是否异常都会执行用于释放资源关闭文件、连接等唯一不执行的情况System.exit(0)退出 JVM9.5 finally 中的 return 陷阱javapublic static int test() { try { return 1; } finally { return 2; // 会覆盖 try 里的 return } } System.out.println(test()); // 2建议不要在 finally 里写 return。9.6 我的理解try-catch-finally 就像出门带伞try出门可能下雨catch下雨了打伞处理异常finally不管下不下雨回来都得锁门释放资源核心一句话try 放可能出错的代码catch 处理异常finally 一定执行用于释放资源。十、throws 声明异常10.1 什么是 throwsthrows 用在方法声明上表示这个方法可能抛出异常由调用者处理。java[访问修饰符] 返回值类型 方法名(参数) throws 异常类型 { // 方法体 }10.2 代码示例javapublic class Test { public static void readFile() throws FileNotFoundException { FileReader reader new FileReader(test.txt); } public static void main(String[] args) { try { readFile(); } catch (FileNotFoundException e) { e.printStackTrace(); } } }10.3 throws vs throw对比项throwsthrow位置方法声明上方法体内作用声明可能抛出的异常抛出一个异常对象数量可以多个一次一个java// throws声明 public void readFile() throws IOException { // throw抛出 throw new IOException(文件读取失败); }10.4 我的理解throws就像提前打招呼我这个方法可能出问题你调用的时候小心点。throw就像直接扔出一个炸弹出问题了接着核心一句话throws 声明异常throw 抛出异常throws 在方法声明上throw 在方法体内。十一、自定义异常11.1 为什么需要自定义异常Java 内置异常不够用业务需要特定的异常类型。比如用户年龄不合法可以抛InvalidAgeException。11.2 定义自定义异常java// 编译时异常继承 Exception public class InvalidAgeException extends Exception { public InvalidAgeException(String message) { super(message); } } // 运行时异常继承 RuntimeException public class InvalidAgeRuntimeException extends RuntimeException { public InvalidAgeRuntimeException(String message) { super(message); } }11.3 使用自定义异常javapublic class User { private int age; public void setAge(int age) { if (age 0 || age 150) { throw new InvalidAgeRuntimeException(年龄不合法 age); } this.age age; } public static void main(String[] args) { User user new User(); try { user.setAge(-10); } catch (InvalidAgeRuntimeException e) { System.out.println(e.getMessage()); // 年龄不合法-10 } } }11.4 我的理解自定义异常就像给业务错误起个名字。InvalidAgeException比Exception更明确一看就知道是年龄问题。核心一句话自定义异常继承 Exception编译时或 RuntimeException运行时通过构造方法传消息。十二、几种常见异常12.1 常见异常表异常原因示例NullPointerException对 null 调用方法或访问属性str.length()str 为 nullArrayIndexOutOfBoundsException数组下标越界arr[10]长度只有 3StringIndexOutOfBoundsException字符串下标越界abc.charAt(10)ClassCastException类型转换错误(Cat) dogArithmeticException算术错误10 / 0NumberFormatException字符串转数字失败Integer.parseInt(abc)IllegalArgumentException参数不合法方法参数不符合要求FileNotFoundException文件不存在new FileReader(x.txt)IOExceptionIO 操作失败读写文件出错SQLException数据库操作失败SQL 执行出错12.2 代码示例java// NullPointerException String str null; // str.length(); // ❌ // ArrayIndexOutOfBoundsException int[] arr new int[3]; // arr[5] 10; // ❌ // ClassCastException Object obj hello; // Integer num (Integer) obj; // ❌ // ArithmeticException // int result 10 / 0; // ❌ // NumberFormatException // int num Integer.parseInt(abc); // ❌12.3 我的理解这些常见异常就像开车常见的故障灯看到空指针就知道哪里用了 null看到数组越界就知道下标写错了。核心一句话常见异常要记住名字和原因出问题时能快速定位。十三、核心口诀知识点口诀包装类意义把基本类型变对象参与面向对象操作8 种包装类int→Integerchar→Character其余首字母大写自动装箱拆箱装箱 valueOf拆箱 xxxValuenull 拆箱 NPE包装类方法parseXxx 字符串转基本类型valueOf 转包装类Integer 缓存-128 到 127 复用比较一律用 equals异常 vs 错误异常可处理错误一般不能异常体系Throwable → Error/Exception → RuntimeException编译时 vs 运行时编译时异常必须处理运行时异常可不处理try-catch-finallytry 放可能出错代码catch 处理finally 一定执行throws vs throwthrows 声明throw 抛出自定义异常继承 Exception 或 RuntimeException常见异常NPE、数组越界、类型转换、算术、数字格式十四、常见易错点易错点说明用 比较包装类超出缓存范围会 false一律用 equalsnull 自动拆箱Integer i null; int n i;会 NPEcatch 顺序写反子类异常在前父类异常在后finally 里写 return会覆盖 try 里的 return不建议throws 和 throw 混淆throws 声明在方法上throw 抛在方法内自定义异常继承错编译时异常继承 Exception运行时继承 RuntimeException忽略异常catch (Exception e) {}空捕获问题被掩盖运行时异常不处理虽然不强制但应该修复代码逻辑