Java基础-知识点03(面试|学习)
Java基础-知识点03
- String类
- String类的作用及特性
- String不可以改变的原因及好处
- String、StringBuilder、StringBuffer的区别
- String中的replace和replaceAll的区别
- 字符串拼接使用+还是使用Stringbuilder
- String中的equal()与Object方法中equals()区别
- String a = new String("abc");创建了几个对象?
- 成员变量
- 实例变量
- 静态变量
- 静态变量与实例变量的内存分配有何不同?
- 静态变量在多线程环境下的安全性如何保证?
- 如何实现常量(不可变)类:
- 成员变量的默认值
- 成员变量的访问权限
- hashcode
- hashCode 方法的原理和实现
- hashcode和equals()区别
- 为什么重写 equals() 时必须重写 hashCode() 方法?
- 为什么 JDK 还要同时提供这两个方法呢?
- 为什么不同的对象可能会有相同的hashcode?什么是哈希冲突?
- 如何解决哈希冲突?
- 哈希表的负载因子
- 为什么哈希表负载因子默认为0.75?
- 异常
- 异常的层次结构
- 受检异常(非运行时异常)
- 非受检异常(运行时异常)
- Error类及其子类
- Java 中的异常处理机制
- try-catch-finally 中哪个部分可以省略
- 异常的声明
- 异常的抛出
- 抛出异常的场景
- 什么是异常链(Exception Chaining)?如何使用异常链?
- 如何自定义异常类?
String类
String
类是Java中用于表示字符串的类。在Java中,字符串是一系列字符的序列,用于表示文本数据。
String类的作用及特性
1、创建字符串: 可以通过字符串字面量或使用new关键字来创建字符串对象。
String str1 = "Hello"; // 使用字符串字面量创建
String str2 = new String("World"); // 使用new关键字创建
2、字符串长度: 可以使用length()方法获取字符串的长度。
String str = "Hello, World!";
int length = str.length(); // length = 13
3、字符串连接: 可以使用+运算符或concat()方法将字符串连接起来。
String str1 = "Hello";
String str2 = "World";
String result = str1 + " " + str2; // 使用+运算符连接
String result2 = str1.concat(" ").concat(str2); // 使用concat()方法连接
4、字符串比较: 可以使用equals()方法比较两个字符串是否相等。
String str1 = "Hello";
String str2 = "hello";
boolean isEqual = str1.equals(str2); // false,区分大小写
5、子串提取: 可以使用substring()方法从字符串中提取子串。
String str = "Hello, World!";
String sub = str.substring(7); // 提取从索引为7开始的子串:"World!"
6、字符串查找: 可以使用indexOf()方法查找指定字符或子串在字符串中的位置。
String str = "Hello, World!";
int index = str.indexOf("World"); // index = 7,子串"World"在字符串中的位置
7、字符串替换: 可以使用replace()方法替换字符串中的字符或子串。
String str = "Hello, World!";
String replaced = str.replace("World", "Java"); // 替换子串:"Hello, Java!"
8、字符串拆分: 可以使用split()方法根据指定的分隔符将字符串拆分为字符串数组。
String str = "apple,orange,banana";
String[] fruits = str.split(","); // fruits = ["apple", "orange", "banana"]
9、字符串转换: 可以使用toLowerCase()、toUpperCase()等方法将字符串转换为小写或大写形式。
String str = "Hello, World!";
String lowerCase = str.toLowerCase(); // 转换为小写:"hello, world!"
String upperCase = str.toUpperCase(); // 转换为大写:"HELLO, WORLD!"
String类还提供了许多其他方法,如去除空白字符、字符查找、字符替换等
String不可以改变的原因及好处
1、String类不该可变的原因:
- String内部使用
char数组
存储数据,该数组被声明为 final。所以数组初始化后就不能引用其他数组。 - String内部没有提供更改 char数组 的方法。 因此保证 String 不可变。
2、String对象不可变的好处:
- 安全性和可靠性: 不可变性确保了字符串对象的安全性和可靠性。
- 可以缓存 hash 值 (String 用做 HashMap 的 key)
- String Pool 的需要,如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
String、StringBuilder、StringBuffer的区别
String, StringBuffer, 和 StringBuilder 是 Java 中用于处理字符串的三个类,它们在功能和性能上有一些区别:
1、String:
- String 是
不可变
的类,一旦创建后就不能修改其内容,线程安全
。 - 每次对 String 进行修改(如拼接、替换等操作)都会生成一个新的 String 对象,原有的对象不变。
- 适用于那些不需要频繁修改的字符串,如存储常量、配置信息等。
2、StringBuffer:
- StringBuffer 是
可变
的类,可以动态修改其内容。 - 提供了许多方法来进行字符串的拼接、插入、删除、替换等操作。
- 是
线程安全
的,所有的公共方法都使用了synchronized
关键字进行同步。 - 适用于
多线程
环境下需要频繁修改字符串的场景。
3、StringBuilder:
- StringBuilder 是
可变
的类,和 StringBuffer 类似,但不保证线程安全
。 - 没有对方法进行同步处理,因此在单线程环境下性能更好。
- 适用于
单线程
环境下需要频繁修改字符串的场景,比如字符串拼接、动态生成文本等。
记忆表格
特点 | String | StringBuffer | StringBuilder |
---|---|---|---|
可变性 | 不可变 | 可变 | 可变 |
线程安全性 | 线程安全 | 线程安全 | 非线程安全 |
内容修改方式 | 生成新的String对象 | 直接修改原对象 | 直接修改原对象 |
同步机制 | 不需要 | 使用synchronized关键字同步 | 不需要 |
性能 | 较低(频繁修改时) | 一般 | 较高(频繁修改时) |
适用场景 | 不需要频繁修改的字符串 | 多线程环境下需要频繁修改的字符串 | 单线程环境下需要频繁修改的字符串 |
String中的replace和replaceAll的区别
String类中的replace和replaceAll方法都用于替换字符串中的字符或子串。
1、replace方法:
replace方法接受两个参数:要替换的旧字符或子串,和替换成的新字符或子串。
它只会替换字符串中所有匹配的旧字符或子串为新字符或子串,不涉及正则表达式。
2、replaceAll方法:
replaceAll方法接受两个参数:要替换的正则表达式,和替换成的新字符串。
它使用正则表达式来匹配要替换的内容,可以实现更灵活的替换规则。
记忆
:replace方法是基于字符或子串的简单替换,而replaceAll方法则更加灵活,可以基于正则表达式进行替换,因此在需要复杂替换规则或匹配模式时,更适合使用replaceAll方法。
字符串拼接使用+还是使用Stringbuilder
在进行字符串拼接时,推荐使用StringBuilder或StringBuffer而不是简单的使用+操作符,特别是在有大量字符串拼接的情况下。因为StringBuilder和StringBuffer可以提供更好的性能和内存利用率。
使用+操作符进行字符串拼接时,会调用StringBuilder 的 append() 方法实现拼接,然后通过 toString() 方法将 StringBuilder 转换为最终的字符串对象。但是在循环体中,每循环一次就会创建一个新的对象,这样会导致大量的对象创建和内存消耗。
如果是在单线程环境下进行字符串拼接,推荐使用StringBuilder,因为它的性能更高,不需要同步操作。如果在多线程环境下进行字符串拼接,应该使用StringBuffer,因为它是线程安全的,内部方法都使用了synchronized关键字进行同步。
String中的equal()与Object方法中equals()区别
1、String类中的equals()方法:
String类重写了Object类中的equals()方法,用于比较两个字符串对象的内容是否相同。String类的equals()方法比较的是字符串的内容,而不是引用地址。
String str1 = "hello";
String str2 = "hello";
boolean result = str1.equals(str2); // true,比较的是字符串内容
2、Object类中的equals()方法:
Object类中的equals()方法是用于比较两个对象的引用地址是否相同。如果一个类没有重写Object类的equals()方法,则默认使用Object类中的方法进行引用地址的比较。
Object obj1 = new Object();
Object obj2 = new Object();
boolean result = obj1.equals(obj2); // false,比较的是对象的引用地址
String a = new String(“abc”);创建了几个对象?
创建了2个对象。
1、使用new关键字,首先会在堆中创建一个实例对象,即创建了一个字符串常量 “abc” 的对象。这个对象存储在字符串常量池中,因为字符串常量是不可变的,所以它可以被多个字符串变量引用,并且在内存中只有一份拷贝。
2、创建了一个新的字符串对象 a。这个对象是通过调用 new String(“abc”) 构造方法创建的,它在堆内存中独立存在,并且包含了字符串常量 “abc” 的内容。
成员变量
Java 中的成员变量是指定义在类中的变量,包含实例变量和静态变量。用于存储对象的状态或类的共享状态。
实例变量
- 实例变量是属于对象的变量,每个对象都有自己的一份实例变量,它们在内存中存储在对象的内部。
- 实例变量在对象被创建时被初始化,并且每个对象的实例变量值是相互独立的。
- 实例变量通常用于存储对象的状态信息,比如一个人的姓名、年龄、性别等。
- 实例变量只能通过对象来访问,不能通过类名来访问。
public class MyClass {int instanceVar; // 实例变量
}
静态变量
- 静态变量是属于类的变量,所有对象共享一份静态变量,它们在内存中只会有一份拷贝,无论该类被实例化多少次,该变量的值都是相同的。
- 静态变量通常用于存储所有对象共享的数据,比如常量、全局计数器等。
- 静态变量可以通过类名来访问,也可以通过对象来访问,但是建议使用类名来访问。
public class MyClass {static int staticVar; // 静态变量
}
静态变量与实例变量的内存分配有何不同?
- 实例变量在每个对象创建时分配内存,每个对象都有自己的实例变量副本。
- 静态变量在类加载时分配内存,只会被分配一次,所有类的实例共享同一个静态变量。
静态变量在多线程环境下的安全性如何保证?
- 静态变量可以在多线程环境下共享,但是需要注意同步访问静态变量的操作,可以使用
synchronized
关键字或者volatile
关键字来保证线程安全性。
如何实现常量(不可变)类:
- 使用 final 关键字修饰类,防止类被继承。
- 使用 final 关键字修饰变量,防止变量被修改。
- 使用构造方法或静态代码块初始化不可变对象的值。
- 提供只读访问方法,不提供修改方法。
成员变量的默认值
- 对于基本数据类型的成员变量,默认值为0或false。
- 对于对象引用类型的成员变量,默认值为null。
成员变量的访问权限
成员变量的访问权限可以通过访问修饰符来控制,常用的访问修饰符包括public、private、protected
和默认访问修饰符。
hashcode
hashCode
是 Java 中用于获取对象哈希码的方法。哈希码是一个整数,用于快速定位对象在哈希表等数据结构中的位置,比如在集合类如 HashMap、HashSet 中的使用。hashCode 方法定义在 Object 类中,因此所有 Java 类都可以调用 hashCode 方法。
hashCode 方法的原理和实现
- hashCode 方法返回的是对象的哈希码,可以理解为对象的逻辑地址。hashCode 方法的默认实现是根据对象的地址计算哈希码,即将对象的内存地址转换成一个整数值。。
- 相同对象调用 hashCode 方法多次应该返回相同的结果。
- 对于不同的对象,其哈希码一般应该是不同的,但不保证不同对象的哈希码绝对唯一。
hashcode和equals()区别
equals() 是用来判断两个对象是否相等,即内容是否相相等。
hashCode 方法用于获取对象的哈希码,用于快速定位对象在哈希表等数据结构中的位置。hashcode 也可以用来两个对象是否相等,但是判断结果不准确,因为哈希码相等的两个对象不一定是同一个对象。
为什么重写 equals() 时必须重写 hashCode() 方法?
因为两个相等的对象的 hashCode 值必须是相等。如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,但hashCode 值却不相等。
总结:
- 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。
- 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等。
- 如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等。
为什么 JDK 还要同时提供这两个方法呢?
为了提高效率。在一些容器(比如 HashMap、HashSet)中,有了 hashCode() 之后,判断元素是否在对应容器中的效率会更高。
在Java的⼀些集合类的实现中,比较两个对象是否相等时,先调用对象的 hashCode()方法得到hashCode进行比较,如果hashCode不相同,就可以直接认为这两个对象不相同,如果hashCode相同,进⼀步调用equals()方法进行比较。
而equals()⽅法,就是⽤来最终确定两个对象是不是相等的,因为equals()方法的实现会比较重,逻辑⽐较多,⽽hashCode()主要就是得到⼀个哈希值,实际上就⼀个数字,效率较快,所以在比较两个对象时,通常都会先根据 hashCode先比较⼀下。
为什么不同的对象可能会有相同的hashcode?什么是哈希冲突?
不同的对象可能会有相同的哈希码,这种情况通常称为哈希冲突。哈希冲突是指两个不同的对象经过哈希函数计算后得到相同的哈希码。
这种情况可能发生的原因包括以下几点:
- 哈希码范围有限: 哈希码是一个整数,在有限的范围内取值。如果两个不同的对象经过哈希函数计算后得到的哈希码在这个范围内是相同的,就会发生哈希冲突。
- 对象属性相似性: 如果两个对象的属性在哈希计算中具有相似性或者相等性,那么它们的哈希码可能会相同。
- 哈希码与内存地址无关: Java 中的哈希码通常与对象的内存地址无关,因此即使两个不同的对象在内存中存储位置不同,它们的哈希码也有可能相同。
如何解决哈希冲突?
哈希冲突是指两个不同的对象经过哈希函数计算后得到相同的哈希码。为了解决哈希冲突,通常采用以下几种常见的方法:
1、开放寻址法:
当发生哈希冲突时,使用一定的规则找到下一个可用的存储位置,直到找到一个空闲位置或者遍历整个表。常见的开放寻址法包括线性探测
、平方探测
、双重散列
等。
- 线性探测法:从当前占用的地址往后,逐一排查,有空的地址就占用。如果查到表尾还没有就返回到表头,直到查完。
- 平方探测法:探测的主要思想是,如果在原始哈希码的位置发生冲突,就通过计算一个增量序列来寻找下一个空闲位置。这个增量序列通常采用二次方的增量。如从发生冲突的位置d[i],按照地址+平方往后找,即d[i]+12,d[i]+22,d[i]+32直到找到空地址。
- 双重散列法:双重散列法的基本思想是,当发生哈希冲突时,通过第一个哈希函数计算原始位置,然后通过第二个哈希函数计算增量,不断尝试将冲突的位置加上增量直到找到空闲位置或者遍历整个哈希表。
2、链地址法
在链地址法中,哈希表的每个桶(存储位置)都对应一个链表,发生哈希冲突时,新元素会直接添加到对应桶的链表末尾,形成一个链式结构。
链地址法的基本思想是,将具有相同哈希码但不同的键值的元素存储在同一个桶中,通过链表将它们串联起来。这样,在发生哈希冲突时,不需要重新计算位置或者探测空闲位置,只需要在对应桶的链表中进行插入、查找或删除操作即可。
链地址法的具体过程:
- 使用哈希函数计算键值的哈希码,确定存储位置(桶)。
- 如果该桶为空,直接将元素插入到该桶中。
- 如果该桶非空,遍历链表查找是否存在相同键值的元素:
- 如果存在相同键值的元素,则更新该元素的值。
- 如果不存在相同键值的元素,则将新元素添加到链表末尾。
3、链地址法的优化
在链地址法中,当链表过长时可能会影响性能。可以采用链表长度超过阈值时,将链表转换为更高效的数据结构,如红黑树,来优化查找和操作性能。
这些方法各有优缺点,选择合适的解决方法取决于具体的应用场景和性能需求。在实际开发中,常见的哈希表实现如 HashMap 就是通过链地址法来解决哈希冲突,并对桶的数量和链表长度等进行动态调整来保持性能。
哈希表的负载因子
哈希表的负载因子是指哈希表中已存储元素个数与哈希表容量之比,通常用公式表示为负载因子 = 元素个数 / 哈希表容量。负载因子是衡量哈希表空间利用率的重要指标之一。
负载因子反映了哈希表的密集程度。当负载因子较小时,哈希表中空槽较多,可能会浪费一些存储空间;当负载因子较大时,哈希表中的槽可能会被填满,导致哈希冲突的概率增加,查找、插入、删除等操作的时间复杂度可能会变高。
在 Java 中,哈希表的默认负载因子
通常是 0.75
。这个默认值指的是当哈希表中的元素个数达到容量的 75% 时,会触发哈希表的扩容操作。
为什么哈希表负载因子默认为0.75?
这个负载因子的选择是经过实践和考量的结果,旨在保持哈希表的性能和空间利用率的平衡。
1、空间利用率: 负载因子为 0.75 表示在哈希表容量的 75% 时触发扩容,这样可以保证哈希表的空间利用率比较高,减少了内存浪费。
2、性能平衡: 通过控制负载因子,可以在空间利用率和性能之间寻找一个平衡点。负载因子过小会导致频繁的扩容操作,影响性能;负载因子过大会增加哈希冲突的概率,也会影响性能。
3、哈希冲突管理: 适度的负载因子可以有效控制哈希冲突的发生,避免在元素插入、查找和删除等操作时频繁地发生冲突。
在 Java 中,可以通过 HashMap 和 HashSet 等类的构造函数来自定义负载因子。例如,在创建一个 HashMap 实例时,可以使用指定负载因子的构造函数来设置自定义的负载因子值。
Map<String, Integer> map = new HashMap<>(16, 0.8f); // 设置负载因子为 0.8
Set<String> set = new HashSet<>(32, 0.6f); // 设置负载因子为 0.6
异常
异常在 Java 中是一种用于处理程序运行时错误的机制。
异常的层次结构
Java 的异常类主要分为两大类:Throwable
类及其子类和 Error
类及其子类。Throwable 类是所有 Java 异常类的根类,它有两个主要的子类:Exception 类和 Error 类。
Exception
类: 是表示程序可以处理的异常情况的基类,它包括了各种受检异常(非运行时异常)和非受检异常(运行时异常)。
Error
类: 表示严重的错误,通常由系统级问题引起,比如内存不足、虚拟机错误等。Error 类及其子类不需要程序员显式地处理或者抛出,通常是由虚拟机或系统级别的组件处理。
受检异常(非运行时异常)
受检异常是指在编译时强制要求程序处理的异常。Exception 的子类中,除了 RuntimeException 及其子类之外的所有异常,都属于受检异常。这些异常通常是由外部因素引起的,比如文件不存在、网络连接失败等。受检异常必须在代码中显式地处理或者通过 throws 关键字声明抛出。
常见的受检异常:
IOException
:输入输出异常,比如文件读写错误。SQLException
:数据库操作异常。
public void readFile() throws IOException {FileInputStream fis = new FileInputStream("file.txt");// 处理文件读取逻辑fis.close();
}
非受检异常(运行时异常)
非受检异常也称为运行时异常,是指在运行时可能会发生但不需要强制处理的异常。RuntimeException 及其子类属于非受检异常,这些异常通常是由程序逻辑错误引起的,比如空指针异常、数组下标越界等。非受检异常不要求在代码中显式处理,但可以选择捕获并处理,也可以通过 throws 关键字声明抛出。
RuntimeException:运行时异常的基类
NullPointerException
:空指针异常。ArrayIndexOutOfBoundsException
:数组索引越界异常。ClassCastException
:类转换异常等。
public void divide(int a, int b) {if (b == 0) {throw new ArithmeticException("除数不能为零");}int result = a / b;System.out.println("结果:" + result);
}
Error类及其子类
Error 类及其子类:程序中无法处理的错误, 此类错误一般表示代码运行时 JVM 出现问题。此类错误发生时,JVM 将终止线程。这些错误是不受检异常,非代码性错误。
通常有:
Virtual MachineError
(虚拟机运行错误)NoClassDefFoundError
(类定义错误)OutOfMemoryError
:内存不足错误StackOverflowError
:栈溢出错误
Java 中的异常处理机制
Java 中的异常处理机制通过 try-catch-finally
块来实现。
try 块: 在 try 块中编写可能会引发异常的代码。try 块是异常处理的起点,用于包裹可能出现异常的代码段。
try 用于监听,其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
try {// 可能会引发异常的代码块
} catch (异常类型1 变量名1) {// 处理异常的代码块
} catch (异常类型2 变量名2) {// 处理其他类型的异常
} finally {// 最终执行的代码块// 无论是否发生异常,都会执行
}
catch 块: 在 catch 块中处理 try 块中可能抛出的异常。catch 块可以有多个,用于捕获不同类型的异常。
//捕获特定类型的异常:
try {// 可能会引发异常的代码块
} catch (IOException e) {// 处理 IOException 异常
} catch (NullPointerException e) {// 处理 NullPointerException 异常
}//捕获通用异常(Exception 类的子类):
try {// 可能会引发异常的代码块
} catch (Exception e) {// 处理所有类型的异常
}
finally 块: finally 块中的代码无论是否发生异常都会执行,用于执行一些必须要完成的操作,比如释放资源、关闭连接等。
try {// 可能会引发异常的代码块
} catch (异常类型1 变量名1) {// 处理异常的代码块
} finally {// 最终执行的代码块// 无论是否发生异常,都会执行
}
异常处理机制的工作流程
- 当程序执行到 try 块中的代码时,如果发生异常,则会立即跳转到与异常类型匹配的 catch 块中执行对应的处理代码。
- 如果发生异常但没有匹配到对应的 catch 块,则异常会沿着方法调用链向上抛出,直到找到匹配的 catch 块或者到达方法的最外层(main 方法)。
- 如果在 try 块中没有发生异常,则会跳过 catch 块,直接执行 finally 块中的代码,然后继续执行 try-catch-finally 结构之后的代码。
注意:
不要在 finally 语句块中使用 return! 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。这是因为 try 语句中的 return 返回值会先被暂存在一个本地变量中,当执行到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。
try-catch-finally 中哪个部分可以省略
在使用 try-catch-finally
块时,可以省略 catch
或 finally
中的任何一个部分,但不能同时省略它们。这是因为 try 块中必须至少有一个 catch 块或一个 finally 块,用于处理可能出现的异常或资源释放。
如果省略 catch 块,则表示将异常传播到调用方处理,而如果省略 finally 块,则表示不需要执行任何清理代码,例如关闭文件或数据库连接等。
需要注意的是,try-catch 块是合法的,即省略了 finally 块。这种情况下,如果出现异常,catch 块会处理异常,并且程序将继续执行 try-catch 块之后的代码。如果没有异常,则程序也将继续执行 try-catch 块之后的代码。
异常的声明
异常的声明主要涉及两个方面:方法声明可能会抛出的异常和自定义异常类的声明。
1、方法声明可能会抛出的异常: 在方法声明中可以使用 throws 关键字来声明方法可能会抛出的异常,需要在调用时进行异常处理或者继续向上抛出异常。
public void myMethod() throws IOException, SQLException {// 可能会引发 IOException 或 SQLException 的代码块
}
在上面的例子中,myMethod() 方法声明可能会抛出 IOException 和 SQLException 两种异常,调用者在调用这个方法时需要对这些异常进行处理或者继续向上抛出。
2、自定义异常类的声明:自定义异常类的声明主要包括定义异常类的结构和功能,以及异常的使用方式。自定义异常类一般需要继承自 Exception 类或其子类,并根据实际需求添加合适的构造方法和其他方法。
public class MyCustomException extends Exception {public MyCustomException(String message) {super(message);}
}
在这个例子中,声明了一个名为 MyCustomException 的自定义异常类,它继承自 Exception 类,并提供了一个带有异常信息的构造方法。
异常的抛出
抛出异常的目的是告诉调用者或者上层代码发生了异常,并且中断当前的执行流程,让异常处理机制来处理这个异常。通常通过 throw 关键字来实现。
如果代码可能会引发某种错误,可以创建一个合适的异常类实例并抛出它。
public static double method(int value) {if(value == 0) {throw new ArithmeticException("参数不能为0"); //抛出一个运行时异常}return 5.0 / value;
}
有时我们会从 catch 中抛出一个异常,目的是为了改变异常的类型。多用于在多系统集成时,当某个子系统故障,异常类型可能有多种,可以用统一的异常类型向外暴露,不需暴露太多内部异常细节。
private static void readFile(String filePath) throws MyException { try {// code} catch (IOException e) {MyException ex = new MyException("read file failed.");ex.initCause(e);throw ex;}
}
习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函数(Throwable 的 toString 方法会打印这些详细信息,调试时很有用), 比如下面用到的自定义MyException:
public class MyException extends Exception {public MyException(){ }public MyException(String msg){super(msg);}// ...
}
抛出异常的场景
- 检测到错误情况: 当程序检测到某些错误情况时,可以抛出异常来中断程序的执行,并提供错误信息以便后续处理。
- 业务逻辑异常: 在业务逻辑中,某些特定情况可能需要抛出异常来通知调用者或者上层代码。
- 异常转换: 在某些情况下,需要将底层异常转换成更高层次的异常抛出,以便更好地管理和处理异常。
在使用 throw 抛出异常时,需要注意以下几点:
- 抛出的异常应该是合理的,能够准确描述错误的情况,并提供有用的异常信息。
- 抛出的异常应该被上层代码捕获和处理,以避免未捕获的异常导致程序崩溃。
- 自定义异常类时,可以继承自 Java 的 Exception 或其子类,或者直接实现 Throwable 接口来定义异常类。
什么是异常链(Exception Chaining)?如何使用异常链?
异常链是指在捕获和处理异常时,将当前异常和导致当前异常的原因异常(根异常)链接起来,形成一个异常链。这种链式结构可以帮助调试和追踪异常的来源,提供更全面的异常信息,方便进行故障排查和修复。
在 Java 中,可以通过在捕获异常时使用 initCause() 方法或者在抛出新异常时将原始异常作为参数传递来创建异常链。
如何自定义异常类?
要自定义异常类,在 Java 中通常需要继承自 Exception 类或其子类,并提供合适的构造方法和其他必要的成员方法。步骤如下:
1、创建异常类: 创建一个新的 Java 类,并继承自 Exception 类或其子类。
public class MyCustomException extends Exception {// 可以在这里添加异常类的成员变量和方法
}
2、添加构造方法:在自定义异常类中添加构造方法,通常需要至少提供一个带有异常信息的构造方法。
public class MyCustomException extends Exception {// 构造方法,传入异常信息public MyCustomException(String message) {super(message);}
}
3、添加其他方法(可选): 根据需要,可以在自定义异常类中添加其他方法或成员变量,以满足特定的异常处理需求。
public class MyCustomException extends Exception {private int errorCode;// 构造方法,传入异常信息和错误代码public MyCustomException(String message, int errorCode) {super(message);this.errorCode = errorCode;}// 获取错误代码的方法public int getErrorCode() {return errorCode;}
}
4、在代码中使用自定义异常类: 在需要抛出异常的地方,使用 throw 关键字抛出自定义异常对象。
public class MyClass {public void myMethod() throws MyCustomException {// 某些条件满足时抛出自定义异常if (someCondition) {throw new MyCustomException("发生了自定义异常", 500);}}
}
使用自定义异常类时,需要注意:
- 异常类通常需要提供带有异常信息的构造方法,以便在抛出异常时传递描述性的异常信息。
- 可以根据需要添加其他方法或成员变量,来扩展自定义异常类的功能。
- 在代码中抛出自定义异常时,需要使用 throw 关键字并创建异常对象。
- 在捕获自定义异常时,可以根据异常类型来捕获并处理异常,以及获取异常对象中的信息。
相关文章:
Java基础-知识点03(面试|学习)
Java基础-知识点03 String类String类的作用及特性String不可以改变的原因及好处String、StringBuilder、StringBuffer的区别String中的replace和replaceAll的区别字符串拼接使用还是使用StringbuilderString中的equal()与Object方法中equals()区别String a new String("a…...
【GIS学习笔记】ArcGIS/QGIS如何修改字段名称、调整字段顺序?
在先前的ArcGIS学习中,了解到字段名称是不能修改的,只能用新建一个字段赋值过去再删除原字段这种方法实现,字段顺序的调整如果通过拖拽也是不能持久的,需要用导出一个新数据这种方法进行保存,可参考以下链接࿱…...
Study Pyhton
PyCharm PyCharm是一个写python代码的软件,用PyCharm写代码比较方便。 PyCharm快捷键ctrl alt s打开软件设置ctrl d复制当前行代码 shift alt 上\下将当前行代码上移或下移crtl shift f10运行当前代码文件shiftf6重命名文件 ctrl a全选ctrl c\v\x复制、粘贴、…...
【MySQL】:深入解析多表查询(下)
🎥 屿小夏 : 个人主页 🔥个人专栏 : MySQL从入门到进阶 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一. 自连接1.1 自连接查询1.2 联合查询 二. 子查询2.1 概述2.2 分类2.3 标量子查…...
图像入门处理4(How to get the scaling ratio between different kinds of images)
just prepare for images fusion and registration ! attachments for some people who need link1 图像处理入门 3...
【项目精讲】Swagger接口文档以及使用方式
Swagger 介绍 Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(https://swagger.io/) 前后端分离开发,有利于团队合作接口的文档在线自动生成,降低后端开发人员编写接口文档的负担功能测试 如何使…...
ThingsBoard通过服务端获取客户端属性或者共享属性
MQTT基础 客户端 MQTT连接 通过服务端获取属性值 案例 1、首先需要创建整个设备的信息,并复制访问令牌 2、通过工具MQTTX连接上对应的Topic 3、测试链接是否成功 4、通过服务端获取属性值 5、在客户端查看对应的客户端属性或者共享属性的key 6、查看整个…...
(78)删除有序数组中的重复项(79)排序矩阵查找
文章目录 1. 每日一言2. 题目(78)删除有序数组中的重复项2.1 解题思路2.2 代码 3. 题目(79)排序矩阵查找3.1 解题思路3.1.1 暴力查找暴力查找代码 3.1.2 二分查找二分查找代码 3.1.3 贪心贪心代码 4. 结语 1. 每日一言 水晶帘动微风起,满架蔷薇一院香。 —高骈- 2.…...
elasticSearch从零整合springboot项目实操
type会被弃用 ,就是说之后的elasticSearch中只会存在 索引(indices) 和 一行(document) 和字段(fields) elasticSearch 和solr的区别最大的就是 es对应的 是 json的格式 。 solr有xml和josn等…...
【Linux实践室】Linux高级用户管理实战指南:用户所属组变更操作详解
🌈个人主页:聆风吟_ 🔥系列专栏:Linux实践室、网络奇遇记 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 一. ⛳️任务描述二. ⛳️相关知识2.1 🔔Linux查看用户所属组2.1.1 👻使…...
C语言: 字符串函数(下)
片头 在上一篇中,我们介绍了字符串函数。在这一篇章中,我们将继续学习字符串函数,准备好了吗?开始咯! 1.strncpy函数 1.1 strncpy函数的用法 strncpy是C语言中的一个字符串处理函数,它用于将一个字符串的一部分内容…...
WPF 数据绑定类属性 和数据更新
WPF中数据绑定是一个非常强大的功能,不仅可以绑定后台数据,还可以进行实时更新。 数据绑定实例 : 在后台创建模型类,然后在标签页面进行导入并绑定。 第一步: // 在后台创建模型类 public class MyData {public string Name { get; set; }…...
使用云服务器搭建CentOS操作系统
云服务器搭建CentOS操作系统 前言一、购买云服务器腾讯云阿里云华为云 二、使用 XShell 远程登陆到 Linux关于 Linux 桌面下载 XShell安装XShell查看 Linux 主机 ip使用 XShell 登陆主机 三、无法使用密码登陆的解决办法 前言 CentOS是一种基于Red Hat Enterprise Linux&#…...
unity的引用传递和数组的联系
引用传递 //引用传递 static void SetY(out int x,out int y ){x 0;y 0;x 1000;}static void Main(string[] args){int x 0;int y 10;SetY(out x, out y);Console.WriteLine($"x{x},y{y}");} 结果是:x1000,y0 数组的引用传递 数组值…...
Android bug Unresolved reference: BR
新建项目后 导入viewBinding 编译后提示 Unresolved reference: BR 解决办法 app 目录下 build.gradle 中 plugins 节点 添加 id kotlin-kapt参考 https://stackoverflow.com/questions/77409050/could-not-find-androidx-corecore-ktx1-8-10...
Unity DOTS1.0 入门(1) ECS机制与概述
ECS机制与概述 Entity:实体 由一个一个的Component组合在一起,是连续的内存布局。通过EnitityManager来负责高效的分配和释放相关entity. World:世界 一个entity的集合,在当前世界里面,每个Entity都有唯一不同的entityld;运行时Unity会自动创建一个D…...
root管理员用户启动kibana报错
问题描述: CentOS7.9.2009环境,以root管理员用户启动kibana7.11.1程序报如下错误: Kibana should not be run as root. Use --allow-root to continue. [root@elasticsearch bin]# whoami root [root@elasticsearch bin]# pwd /usr/local/kibana-7.11.1-linux-x86_64/bi…...
【leetcode面试经典150题】50. 插入区间(C++)
【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主,题解使用C语言。(若有使用其他语言的同学也可了解题解思路,本质上语法内容一致&…...
第二期书生浦语大模型训练营第三次笔记
RAG RAG是什么? RAG(Retrieval Augmented Generation)技术,通过检索与用户输入相关的信息片段,并结合外部知识库来生成更准确、更丰富的回答。解决 LLMs 在处理知识密集型任务时可能遇到的挑战, 如幻觉、知识过时和缺…...
SpringMVC(一)【入门】
前言 学完了大数据基本组件,SpringMVC 也得了解了解,为的是之后 SpringBoot 能够快速掌握。SpringMVC 可能在大数据工作中用的不多,但是 SSM 毕竟是现在就业必知必会的东西了。SpringBoot 在数仓开发可能会经常用到,所以不废话学吧…...
SQL Server详细使用教程
SQL Server 是 Microsoft 公司开发的关系型数据库管理系统(RDBMS),用于存储和检索数据。以下是 SQL Server 的详细使用教程: 目录 1. 安装 SQL Server 2. 连接到 SQL Server 3. 创建数据库 4. 创建数据表 5. 插入数据 6. 查…...
Spring Boot项目启动时执行指定的方法
项目场景: 本文介绍Spring Boot项目启动时执行指定的方法两种常用方式和他们之间的区别。 实现方案: 方式一:使用注解PostConstruct Component public class PostConstructTest {PostConstructpublic void postConstruct() {System.out.prin…...
红豆Cat 1开源|项目三: 从0-1设计一款HTTP版本RTU(支持GNSS)产品的软硬件全过程
HTTP版RTU(支持GNSS)项目概述 RTU(Remote Terminal Unit),中文即远程终端控制系统,负责对现场信号、工业设备的监测和控制。RTU是构成企业综合自动化系统的核心装置,通常由信号输入/出模块、微…...
在 Mac 上配置高级内容缓存设置
在 Mac 上配置高级内容缓存设置 您可以使用高级配置参数针对网络配置微调内容缓存。 您可以在“终端”中使用命令行或通过修改“/资源库/Preferences/com.apple.AssetCache.plist”文件中的键值,来设定内容缓存的高级配置参数。若要使某些更改生效,必须…...
算法与数据结构 顺序栈(C++)
随机产生10个100以内的整数建立一个顺序栈,从栈顶到栈底依次显示栈内元素;从键盘输入出栈元素个数 n (1< n <10),将 n 个元素依次出栈并显示出栈元素,再显示此时栈顶元素。 #include <iostream> #include <cstd…...
【WSL】在WIN11安装并使用Linux子系统(Ubuntu)
前言: 最近买了4060Ti 16G,可以尝试在本地实验大模型。一开始尝试使用Vmware搞Linux,发现没有办法加载GPU(或者另外有办法没找到)。所以只剩下了两条路:要么搞双系统,要么使用WSL(W…...
【vim 学习系列文章 20 -- a:mode 的值有哪些?】
请阅读【嵌入式开发学习必备专栏 之 Vim】 文章目录 a:mode 的值有哪些?举例Vim 底部状态栏设置 a:mode 的值有哪些? 在 Vim 脚本语言中,a:mode 常常用于函数内部,以获取该函数被调用时 Vim 正处于的模式。它主常用于那些可以从不同模式下被调用的函数…...
sed命令多行处理
1. sed 如何工作的 sed 维护两个空间: 模式空间保留空间 sed是以行为周期来处理文本的。 sed从输入流中读取一行,去掉最后的换行符,把它放入模式空间。随后执行命令,每个命令都有关联的地址和条件,只有匹配时才执行…...
Secure Copy Protocol or SCP - 安全拷贝协议
Secure Copy Protocol or SCP - 安全拷贝协议 1. scp 文件传输1.1. 将远程文件拷贝到本地1.2. 将本地文件拷贝到远程1.3. 将远程目录拷贝到本地 References Secure Copy (remote file copy program) The SCP program is a software tool implementing the SCP protocol as a s…...
Java面试题:什么是Java的值传递和引用传递?列举其应用场景,并说明其特点
在Java中,值传递和引用传递是两种不同的参数传递机制。它们在Java程序中扮演着重要的角色,影响着方法如何接收和处理参数。了解这两种传递机制对于编写高效、可靠的Java代码至关重要。 值传递(Pass by Value) 值传递是指在调用方…...
吉林省 网站建设/百度不收录网站怎么办
启动hive的时候出现如下错误 [rootBigdata01 bin]# hive ls: 无法访问/opt/module/spark/lib/spark-assembly-*.jar: 没有那个文件或目录 20/09/03 20:29:03 WARN conf.HiveConf: HiveConf of name hive.metastore.local does not existLogging initialized using configurati…...
用dw怎么做网站/淘宝权重查询入口
背景 在上午探索了Windows下时间任务创建运行的可视化界面和Schtasks命令行工具且默默失败后,下午我决定不依不饶地去看一下Linux系统下是怎么创建时间任务的。其实我Linux接触得不多,而且今天也是新接触的crontab命令,所以不免会踩坑踩雷&am…...
wordpress安装模版500/如何做网页设计
一、官网下载: 先去官网下载安装包: postman的官网 二、下载后,创建安装包,postman会自动安装成功。直接打开即可。 三、如果没有账号,退出再次登录即可...
wordpress 多语言版本/推广运营怎么做
1、 1、 在加载控件的地方插入一个PlaceHolder:加载代码: WEbControl wc new WebControl(HtmlTextWriterTag.Textarea); PlaceHolder1.Controls.Add(wc); 这样就可以在PlaceHolder处插入一个Textarea 2、自定义显示用户控件 在从一个Web页面…...
网站页面设计与制作实践/石家庄疫情最新情况
三元运算:if 11 2 :print (True)else:print (False)#等同于:print (True if 112 else False)函数的基本语法def XX():定义函数# return aa 返回值# 或 pass 什么也不返回# XX() 调用函数#函数的有三中不同的参数:#------普通参数------def f…...
做企业的网站都要准备什么手续/淘宝关键词优化软件
文章目录一、正则表达式1.1正则表达式的定义1.2 grep1.3基础正则表达式1.4 扩展正则表达式1.5 元字符操作案例二、文本处理器2.1 cut:列截取工具2.2 sort :排序工具2.3 uniq:去除连续的重复行2.4 tr :替换工具一、正则表达式 1.1…...