一、java的异常处理
Java的异常处理机制允许开发人员在程序中主动抛出异常和捕获异常。这种机制可以帮助开发人员在程序出现错误或不可预测的情况下,更加优雅地处理异常情况。
Java中的异常处理主要有以下几种方式:
- 1、捕获:try-catch语句:使用try-catch语句可以捕获并处理异常。在try块中放置可能会引发异常的代码,如果发生异常,则将控制转移到catch块中进行处理。
try {
// 可能会引发异常的代码
// ...
} catch (Exception e) {
// 异常处理
// ...
}
- finally块:使用finally块可以放置一些无论是否发生异常都需要执行的代码。
try {
// 可能会引发异常的代码
// ...
} catch (Exception e) {
// 异常处理
// ...
} finally {
// 无论是否发生异常都会执行的代码
// ...
}
- 2、抛出:在Java中,可以使用
throw
语句来主动抛出异常。throw
语句后面跟着一个异常对象,这个异常对象可以是Java内置的异常类,也可以是自定义的异常类。例如,下面的代码中,使用throw
语句抛出了一个自定义的异常类MyException
:
public class MyException extends Exception {
// 自定义异常类
public MyException(String message) {
super(message);
}
}
public class Main {
public static void main(String[] args) {
try {
throw new MyException("This is a custom exception.");
} catch (MyException e) {
System.out.println(e.getMessage());
}
}
}
- 在上述代码中,
throw new MyException("This is a custom exception.")
语句抛出了一个MyException
异常对象,然后在catch
语句中捕获并处理这个异常。catch
语句中的代码会打印出异常的信息。 - 除了使用
throw
语句来主动抛出异常,Java中还有一些内置的异常类,可以在特定条件下自动抛出。例如,NullPointerException
异常会在代码中出现了对空对象的操作时被抛出,ArrayIndexOutOfBoundsException
异常会在访问数组元素时索引超出范围时被抛出,等等。 - 总之,Java的异常抛出机制可以帮助开发人员在程序中更好地处理异常情况,保证程序的健壮性和可靠性。
- 3、自定义捕获:在Java中,我们可以通过自定义异常类来捕获和处理特定的异常情况。自定义 异常类是一个继承自Java内置异常类的用户自定义类。以下是如何定义和使用自定义异常的步骤:
- 创建自定义异常类:创建一个类,这个类继承自Java内置的异常类,例如RuntimeException或Exception。可以给自定义异常类添加自定义的构造方法和其他方法。
示例:
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
- 在需要捕获特定异常的代码块中抛出自定义异常:当在代码中发生了特定的异常情况时,使用throw关键字抛出自定义异常对象。
示例:
public class Example {
public static void main(String[] args) {
try {
int result = divide(10, 0);
System.out.println("Result: " + result);
} catch (MyException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
public static int divide(int num1, int num2) throws MyException {
if (num2 == 0) {
throw new MyException("Divisor cannot be zero");
}
return num1 / num2;
}
}
- 在上面的示例中,divide方法中检查了除数是否为零,如果为零则抛出了自定义异常对象。在main方法中,我们通过捕获MyException类型的异常来处理这个特殊情况。
二、Java常用类
1、包装类
Java中的包装类用于将原始类型(int,char,float等)转换为相应的对象。
8个基本类型中的每一个都有对应的包装器类。
-
将基本类型转化为包装对象
示例:
class Main {
public static void main(String[] args) {
//创建原始类型
int a = 5;
double b = 5.65;
//转换为包装对象
Integer aObj = Integer.valueOf(a);
Double bObj = Double.valueOf(b);
if(aObj instanceof Integer) {
System.out.println("创建一个Integer对象。");
}
if(bObj instanceof Double) {
System.out.println("创建一个Double对象。");
}
}
}
在上面的示例中,我们使用了valueOf()将原始类型转换为对象的方法。在这里,我们使用instanceof运算符来检查生成的对象是否属于Integer或Double类型。
-
自动装箱和拆箱
java中的自动装箱(autoboxing)和拆箱(unboxing)是指自动地在基本类型和其对应的包装类之间进行转换。
自动装箱:是将一个基本类型的值转换为对应的包装类对象。例如,将int类型的值转换为Integer对象。自动装箱是通过Java编译器在编译时进行的。
int i = 10;
Integer integer = i; // 自动装箱
自动拆箱是将一个包装类对象转换为对应的基本类型值。例如,将Integer对象转换为int类型的值。自动拆箱是通过Java编译器在编译时进行的。
Integer integer = 10;
int i = integer; // 自动拆箱
自动装箱和拆箱可以使得基本类型和其对应的包装类之间的转换更加方便。但是在频繁进行装箱和拆箱操作时,会产生一定的性能开销。因此,在性能要求较高的场景下,最好手动进行装箱和拆箱操作。
2、String(buffer、build)
在Java中,String、StringBuffer和StringBuilder是字符串处理的三个主要类。
-
String类: String类是Java中最常用的字符串类。它是不可变的,一旦创建就不能修改。String对象的值在创建后不能被改变,任何对String对象的修改都会创建一个新的String对象。这是因为String类中的方法都是返回新的字符串。例如:
String str = "Hello"; str = str + " World!";
上述代码中,对字符串进行连接操作时,实际上是创建了一个新的String对象,原始的"Hello"字符串对象并没有被修改。
-
StringBuffer类: StringBuffer类是可变的,用于处理可变的字符串。与String不同,StringBuffer对象可以直接进行修改,而无需创建新的对象。这在需要频繁修改字符串的场景下具有性能上的优势。例如:
StringBuffer sb = new StringBuffer("Hello"); sb.append(" World!");
上述代码中,使用append()方法在原始的StringBuffer对象后追加字符串,而不需要创建新的对象。
StringBuffer类还提供了许多其他常用的方法,比如insert()、delete()、replace()等,用于对字符串进行插入、删除、替换等操作。
-
StringBuilder类: StringBuilder类与StringBuffer类类似,也是可变的字符串类。与StringBuffer相比,StringBuilder类的性能更高,但是不是线程安全的。在单线程环境下,推荐使用StringBuilder类。例如:
StringBuilder sb = new StringBuilder("Hello"); sb.append(" World!");
StringBuilder类也提供了类似于StringBuffer类的方法,用于对字符串进行修改和操作。
3、BigDecimal
在Java中,BigDecimal类是用于高精度的十进制计算的类。它提供了精确的数值运算,避免了浮点数运算可能出现的精度丢失问题。
BigDecimal类的常用方法如下:
构造方法:
BigDecimal(String val)
:使用指定的字符串创建一个BigDecimal对象。
基本数值操作方法:
add(BigDecimal val)
:将指定的BigDecimal值与当前对象相加。subtract(BigDecimal val)
:将指定的BigDecimal值与当前对象相减。multiply(BigDecimal val)
:将指定的BigDecimal值与当前对象相乘。divide(BigDecimal val)
:将当前对象除以指定的BigDecimal值。
精度和舍入模式设置方法:
setScale(int scale)
:设置小数部分的精度(保留的小数位数)。setScale(int scale, RoundingMode roundingMode)
:设置小数部分的精度,并指定舍入模式。
比较方法:
compareTo(BigDecimal val)
:将当前对象与指定的BigDecimal对象进行比较。
其他方法:
abs()
:返回当前对象的绝对值。intValue()
、longValue()
、floatValue()
、doubleValue()
:返回当前对象的整数、长整数、浮点数、双精度数值。- 以下是BigDecimal类的一个示例用法:
import java.math.BigDecimal;
public class BigDecimalExample {
public static void main(String[] args) {
BigDecimal num1 = new BigDecimal("10.50");
BigDecimal num2 = new BigDecimal("5.25");
BigDecimal sum = num1.add(num2);
BigDecimal difference = num1.subtract(num2);
BigDecimal product = num1.multiply(num2);
BigDecimal quotient = num1.divide(num2, 2, BigDecimal.ROUND_HALF_UP);
System.out.println("Sum: " + sum);
System.out.println("Difference: " + difference);
System.out.println("Product: " + product);
System.out.println("Quotient: " + quotient);
}
}
在上述示例中,我们使用BigDecimal类进行数值的加减乘除操作,并设置了小数部分的精度为两位小数。运行结果如下:
Sum: 15.75
Difference: 5.25
Product: 55.125
Quotient: 2.00
通过使用BigDecimal类,我们可以确保在进行高精度的十进制计算时不会出现精度丢失的问题。
三、泛型
1、简介
在Java中,泛型(Generics)是一种参数化类型的概念,它允许我们在定义类、接口和方法时使用类型参数,从而实现代码的重用和类型安全。
泛型的使用方式如下:
- 类型参数的声明:在类、接口或方法的名称后面使用尖括号(<>)定义一个或多个类型参数。例如:
public class MyClass<T> {
// ...
}
- 类型参数的使用:我们可以在类的成员变量、方法参数、方法返回值等位置使用类型参数。例如:
public class MyClass<T> {
private T myVariable;
public void myMethod(T param) {
// ...
}
public T myMethod() {
// ...
return myVariable;
}
}
2、列表
在Java中,列表(List)是一种常用的数据结构,用于存储一组元素。列表允许存储重复的元素,并且元素的顺序是有序的。Java提供了多种实现列表的类,其中常用的有以下几种:
ArrayList:ArrayList是基于数组实现的动态数组,可以自动扩容。它提供了高效的随机访问和插入/删除操作的方法。
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
System.out.println(list.get(0)); // 输出:Apple
System.out.println(list.size()); // 输出:3
LinkedList:LinkedList是基于链表实现的列表,它支持快速的插入和删除操作,但随机访问元素的效率较低。
List<String> list = new LinkedList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
System.out.println(list.get(0)); // 输出:Apple
System.out.println(list.size()); // 输出:3
Vector:Vector是线程安全的动态数组,与ArrayList类似。与ArrayList不同的是,Vector的方法是同步的,即在多线程环境下可以安全地使用。
List<String> list = new Vector<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
System.out.println(list.get(0)); // 输出:Apple
System.out.println(list.size()); // 输出:3
3、set
在Java中,Set是一种不允许包含重复元素的集合类型。它是基于数学上的集合概念,因此不关心元素的顺序,只关心元素是否存在。Java提供了多种Set的实现类,常用的有以下几种:
- HashSet:HashSet是基于哈希表实现的Set,它不保证元素的顺序,允许插入null元素。它提供了常数时间的插入、删除和查找操作。
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");
System.out.println(set.contains("Apple")); // 输出:true
System.out.println(set.size()); // 输出:3
- TreeSet:TreeSet是基于红黑树实现的有序Set,它会根据元素的自然顺序进行排序。TreeSet不允许插入null元素。
Set<String> set = new TreeSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");
System.out.println(set.first()); // 输出:Apple
System.out.println(set.size()); // 输出:3
- LinkedHashSet:LinkedHashSet是基于哈希表和双向链表实现的Set,它保留元素插入的顺序。LinkedHashSet允许插入null元素。
Set<String> set = new LinkedHashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");
System.out.println(set.contains("Apple")); // 输出:true
System.out.println(set.size()); // 输出:3
4、map
在Java中,Map是一种键值对(Key-Value)的数据结构,它用于存储一组不重复的键和对应的值。Java提供了多种Map的实现类,常用的有HashMap,TreeMap,LinkedHashMap。