一、包装类
1、什么是包装类?
- 在进行类型转换时,有一种特殊的转换:将int这样的基本数据类型转换为对象
- 包装类是基本数据类型对应的类,每个基本数据类型对应一个包装类
- 基本数据类型不能直接参与引用类型的使用或计算,使用包装类将基本数据类型转换为引用数据类型,可以参与到其他引用类型的使用
- 包装类是不可变类,在构造了包装类对象后,不允许更改包装在其中的值
- 包装类是final的,不能继承
2、包装类赋值实例
Integer.valueOf()、 Double.valueOf()将基本数据类型转换为包装类对象。
/**
* @document: 基本数据类型包装类
* @Author:SmallG
* @CreateTime:2023/8/1+16:19
*/
public class Demo01 {
public static void main(String[] args) {
//创建基本数据类型包装类对象
Integer i1 = new Integer(128); //已经过时,不推荐使用
//通过基本数据类型转换为包装类对象
Integer i2 = Integer.valueOf(128); //推荐使用
System.out.println(i1 == i2); //false 对象的引用指向的是地址
System.out.println(i1.equals(i2)); //true
Double d1 = Double.valueOf(130.76);
Double d2 = Double.valueOf(130.76);
System.out.println(d1 == d2); //false
System.out.println(d1.equals(d2)); //true
//包装类转基本数据类型 转换的时候要符合基本数据类型的表示范围
int i11 = i1.intValue();
int i21 = i2.intValue();
System.out.println(i11 == i21); //true
double d = d1.doubleValue();
System.out.println(d); //130.76
}
}
3、Number及其主要方法
- 抽象类Number是Byte、Double、Float、Integer、Long和Short类的父类
- Number类本身是一个抽象类,不能直接实例化,而是作其他数值类的基类
- 使用Number类及其子类,可以执行各种数值计算和转换操作,根据具体的需求将数值对象转换为不同的数据类型
4、自动拆装箱
对象------>基本数据类型(拆箱)
基本数据类型------>对象(装箱)
/**
* @document: 自动拆装箱
* @Author:SmallG
* @CreateTime:2023/8/1+16:52
* Java自动拆箱 有数据范围:-128~127
* Java自动装箱 没有数据范围
*/
public class Demo03 {
public static void main(String[] args) {
//
Integer i1 = 127; //自动装箱(将基本数据类型转换为对象) 装箱没有范围
Integer i2 = 127;
System.out.println(i1 == i2); //true (一个字节内)-128~127之间的数字Java完成自动拆箱(把对象转换为基本数据类型)
System.out.println(i1.equals(i2)); //true
Integer i3 = Integer.valueOf(127);
Integer i4 = Integer.valueOf(127);
System.out.println(i3 == i4); //true
Integer i5 = 128;
Integer i6 = 128;
System.out.println(i5 == i6); //false
System.out.println(i5.equals(i6));//true
}
}
5、大数类
- 在Java中,存储的数据可能超过基本数据类型中整型最大范围,所以提供了BigInteger类来表示任意大小的整数,提供了BigDecimal类来表示任意大小且精度完全准确的浮点数
- BigInteger和BigDecimal被称为Java中的大数字类,位于java.math包下,两个类均为Number类的子类
整数型大数类示例:
/**
* @document: 大数字类
* @Author:SmallG
* @CreateTime:2023/8/1+17:23
*/
public class Demo04 {
public static void main(String[] args) {
//创建BigInteger对象 需要用字符串的形式传递数值
BigInteger i1 = new BigInteger(String.valueOf(121231313));
BigInteger i2 = new BigInteger("12313131313131313131313133134141414545151525");
System.out.println(i1.add(i2)); //加
System.out.println(i1.multiply(i2)); //乘
System.out.println(i1.subtract(i2)); //减
System.out.println(i1.divide(i2)); //除
i2.longValueExact();//超long的范围会抛异常
}
}
浮点型大数字类示例:
/**
* @document: 浮点型大数字类
* @Author:SmallG
* @CreateTime:2023/8/1+17:38
*/
public class Demo05 {
public static void main(String[] args) {
BigDecimal d1 = new BigDecimal("1234.1414141");
BigDecimal d2 = d1.multiply(d1);
System.out.println(d2);
//BigDecimal使用scale()计算小数位数
BigDecimal d3 = new BigDecimal("12.34");
BigDecimal d4 = new BigDecimal("12.3400");
BigDecimal d5 = new BigDecimal("123400");
System.out.println(d3.scale()); //2
System.out.println(d4.scale()); //4
System.out.println(d5.scale()); //0
//BigDecimal可以使用setScale设置精度
BigDecimal d6 = d1.setScale(2, RoundingMode.HALF_UP); //四舍五入保留两位
BigDecimal d7 = d1.setScale(2, RoundingMode.DOWN); //只舍不入保留两位
System.out.println(d6);
System.out.println(d7);
//判断两个值的数据是否相等
BigDecimal d8 = new BigDecimal("123.456");
BigDecimal d9 = new BigDecimal("123.45600");
System.out.println(d8.equals(d9)); //false 精度不一样,equals在比较的时候要求数值和精度都要相等
//compareTo()比较数值是否相等
System.out.println(d8.compareTo(d9));// 0表示相等 1表示不相等
}
}
二、异常
1、异常概述
让一个没有任何指向的引用去执行操作,会报异常。
异常类型继承关系
- 异常对象的类型之间存在继承关系,异常类都是从Throwable类派生而来
- Throwable是Java异常类层次结构的根类,它分为两个主要的子类:Error和Exception,Exception又分为两种类型:检查异常(Checked Exception)和非检查异常(Unchecked Exception)。
- (1)检查异常在编译时需要进行处理,否则编译器会报错。
- (2)非检查异常在编译时不需要进行处理,因为他们通常表示程序内部错误、逻辑错误或者编程错误。也称运行时异常,它们可以在代码中捕获和处理,但也可以选择不处理。常见的非检查异常包括空指针异常、数组越界异常等。
Throwable类的API
- getMessage():获取异常的详细描述信息。返回一个字符串,描述异常的原因或相关信息。
- getCause():获取导致当前异常的原因。返回一个Throwable对象,表示导致当前异常的异常或错误。
- printStackTrace():打印异常的堆栈跟踪信息。将异常的堆栈跟踪信息输出到标准错误流,用于调试和错误诊断。
- getStackTrace():获取异常的堆栈跟踪信息。返回一个StackTraceElement数组,包含异常发生时方法的调用链信息。
- toString():返回异常对象的字符串表示。通常返回异常类的名称,以及异常的详细描述信息。
2、处理异常
(1)try-catch语句块
将可能出现异常的语句放在try里面,如果出现异常会跳过try执行catch语句。
/**
* @document: try-catch处理异常
* @Author:SmallG
* @CreateTime:2023/8/2+9:33
*/
public class Demo07 {
public static void main(String[] args) {
System.out.println("程序开始了");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = scanner.nextLine(); // 接收一行内容
//输入null 表示什么都没输
str = str.equals("null") ? null : str;
try {
System.out.println(str.length());
System.out.println(str.charAt(1));
//转换为整型 当字符串不是数字 会出现NumberFormatException(数字格式化异常)
System.out.println(Integer.parseInt(str));
//当出现异常之后 在try语句以下部分代码都不会执行
System.out.println("!!!!!!!!!!!!!");
} catch (NullPointerException e1) {
//获取异常信息
System.out.println(e1.getMessage());
System.out.println("出现空指针异常!");
} catch (StringIndexOutOfBoundsException e2) {
//获取字符串的一个位置,超过了字符串的长度 会出现下标越界异常
System.out.println(e2.getMessage());
System.out.println("出现字符串下标越界异常!");
} catch (NumberFormatException e3) {
System.out.println(e3.getMessage());
System.out.println("出现了数字格式化异常!");
}
/* catch (Exception e){
//最大捕获异常
System.out.println("出现了异常");
}*/
System.out.println("程序结束了!");
}
}
(2)finally语句块
finally语句块在try或catch语句块之后,不论try语句块中是否出现异常。finally语句块中的代码均会被执行,主要用于执行释放资源的逻辑。
/**
* @document: finally语句块
* @Author:SmallG
* @CreateTime:2023/8/2+10:17
*/
public class Demo08 {
public static void main(String[] args) {
System.out.println("程序开始");
String str1 = null;
try {
System.out.println(str1.length());
} catch (Exception e) {
System.out.println("出现了空指针异常");
} finally {
//无论try语句块中的代码是否出现异常 finally语句块都会执行
System.out.println("finally执行了");
}
System.out.println("程序结束了!");
}
}
(3)**finally代码中的执行时机(面试会问)
情况一:先将finally里的代码执行完毕后,再返回方法中的数值。
/**
* @document: finally代码的执行时机
* @Author:SmallG
* @CreateTime:2023/8/2+10:24
*/
public class Demo09 {
public static void main(String[] args) {
System.out.println(get()); // 3 2
}
public static int get() {
int a = 1;
try {
return a + 1; //return结果已经返回
} finally {
a = 3;
System.out.println(a);
}
}
}
情况二:如果finally里面有return,则返回值以finally里面的return为准。
/**
* @document: finally代码的执行时机
* @Author:SmallG
* @CreateTime:2023/8/2+10:24
*/
public class Demo09 {
public static void main(String[] args) {
System.out.println(get2()); //3
}
//以最后一次return为准
public static int get2() {
int a = 1;
try {
return a + 1;
} finally {
a = 3;
return a;
}
}
}
情况三:如果在try-catch中JVM突然中断,强制退出,那么终止以下的代码不会被执行。或者try-catch存在死循环、进程被杀死等都不会执行。
/**
* @document: finally代码的执行时机
* @Author:SmallG
* @CreateTime:2023/8/2+10:24
*/
public class Demo09 {
public static void main(String[] args) {
System.out.println(get3()); //不会输出任何内容
}
public static int get3() {
int a = 1;
try {
System.exit(0); //强制退出程序
return a + 1;
} finally {
a = 3;
return a;
}
}
}
3、抛出异常
当出现异常的时候,由当前代码主动创建并抛出一个异常对象,抛出异常的目的是通知上层调用者或异常处理机制,表明当前代码无法正常处理某个特定情况,需要由上层调用者或异常处理机制来处理。
(1)throw
在代码中显式的抛出一个异常,在代码块中声明。
/**
* @document: throw抛出异常
* @Author:SmallG
* @CreateTime:2023/8/2+10:44
*/
public class Demo10 {
public static void main(String[] args) {
String str = null;
try {
print(str);
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}
}
public static void print(String str) {
if (str == null) {
//程序满足抛出异常条件 ,余下代码就会终止
//把异常抛给了调用者
throw new NullPointerException("对象为空");
}
System.out.println(str.length());
}
}
(2)throws
在方法签名中声明
/**
* @document: throws抛出异常
* @Author:SmallG
* @CreateTime:2023/8/2+10:44
*/
public class Demo10 {
public static void main(String[] args) {
String str = null;
try {
hello(str);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("hello");
}
public static void hello(String str) throws NullPointerException, RuntimeException {
if (str == null) {
throw new NullPointerException("对象为空");
}
if (str.length() < 6) {
throw new RuntimeException("字符串长度不足6位");
}
System.out.println(str);
}
}
(3)*子类重写父类方法 throws规则
/**
* @document: 子类重写父类方法 throws规则
* @Author:SmallG
* @CreateTime:2023/8/2+11:18
*/
public class Demo11 {
}
class Person {
//父类的方法抛出的异常
public void print(String str) throws RuntimeException {
if (str == null) {
throw new NullPointerException("对象为空");
}
System.out.println(str);
}
}
class Student extends Person {
//子类重写父类方法时,可以抛父类的异常或者时父类异常的子类,不能大于父类抛出的异常范围
public void print(String str) throws NullPointerException {
}
}
4、自定义异常
开发者自己定义的异常,创建自定义异常的步骤:
- 创建一个继承Exception或RuntimeException的子类,如果希望自定义异常是受检异常继承Exception,如果希望自定义异常是非受检异继承RuntimeException类
- 在自定义异常类中,给类起名见名知意,以Exception结尾
- 在自定义异常类中,通常需要显式声明构造函数
创建自定义异常
/**
* @document: 自定义异常
* 1、命名遵守见名知意 以Exception结尾
* 2、继承Exception(受检异常/编译型异常)或者RuntimeException(非受检异常/运行时异常)
* 3、重写父类的构造方法(5个)
* @Author:SmallG
* @CreateTime:2023/8/2+11:34
*/
public class PasswordLengthLittleException extends RuntimeException {
public PasswordLengthLittleException() {
super();
}
public PasswordLengthLittleException(String message) {
super(message);
}
public PasswordLengthLittleException(String message, Throwable cause) {
super(message, cause);
}
public PasswordLengthLittleException(Throwable cause) {
super(cause);
}
protected PasswordLengthLittleException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
使用自定义异常
/**
* @document: 使用自定义异常
* @Author:SmallG
* @CreateTime:2023/8/2+11:40
*/
public class Demo12 {
public static void main(String[] args) {
String password = "123";
try {
print(password);
} catch (NullPointerException e) {
System.out.println(e.getMessage());
} catch (PasswordLengthLittleException e) {
System.out.println(e.getMessage());
}
}
public static void print(String password) throws NullPointerException, PasswordLengthLittleException {
if (password == null) {
//抛出异常
throw new NullPointerException("密码为空");
}
if (password.length() < 6) {
//抛出自定义异常
throw new PasswordLengthLittleException("密码长度不足6位");
}
System.out.println("密码是:" + password);
}
}
三、练习
1 输入数字字符串,转换为整数或浮点数
用户从控制台接收一个字符串,通过程序判断该字符串是整数,还是小数。如果是整数,将该字符串转换成int类型并输出结果;如果是小数,将该字符串转换成double类型并输出结果;如果既不是整数也不是小数,程序输出“数字格式不正确”。
提示:请使用正则表达式而不是异常来实现类型判断。
程序交互过程如下所示:
1、用户输入整数字符串的情况,如下图所示:
2、用户输入为小数的情况,如下图所示:
3、用户输入的既不是整数也不是小数的情况,如下图所示:
/**
* @document: 输入数字字符串,转换为整数或浮点数
* @Author:SmallG
* @CreateTime:2023/8/1+16:51
*/
public class StringToIOrF {
public static void main(String[] args) {
String isInt = "^[0-9]+$";
String isDouble = "^[0-9]+\\.[0-9]+$";
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字:");
//输入数字字符串
String s = scanner.next();
if (s.matches(isInt)){
int i = Integer.parseInt(s);
System.out.println("这是一个整数:"+i);
}else if (s.matches(isDouble)){
double d = Double.parseDouble(s);
System.out.println("这是一个小数:"+d);
}else{
System.out.println("数字格式不正确!");
}
}
}
2 输入数字字符串,转换为整数或浮点数
本题整体需求与第一题相同,但是要求使用异常处理机制而非正则表达式来实现第一题的需求。
/**
* @document: 输入数字字符串,转换为整数或浮点数
* @Author:SmallG
* @CreateTime:2023/8/1+16:51
*/
public class StringToIOrF2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字:");
//输入数字字符串
String s = scanner.next();
try {
int i = Integer.parseInt(s);
System.out.println("这是一个整数:"+i);
}catch (NumberFormatException e1){
try {
double d = Double.parseDouble(s);
System.out.println("这是一个小数:"+d);
}catch (NumberFormatException e2){
System.out.println("数字格式不正确!");
}
}
}
}
3 计算数字乘积
已知有一个整型数组{1280, 2560, 5120, 10240, 20480, 40960},现需要计算其中元素的乘积。计算规则为,按顺序逐一选出数组中的一个元素,计算它与数组中前面所有元素的乘积并输出。
程序运行结果如下所示:
/**
* @document: 数字乘积
* @Author:SmallG
* @CreateTime:2023/8/1+17:19
*/
public class productNum {
public static void main(String[] args) {
int[] arr = {1280, 2560, 5120, 10240, 20480, 40960};
BigInteger sum = new BigInteger(String.valueOf(arr[0]));
for (int i = 0; i < arr.length; i++) {
if (i!=0){
sum = sum.multiply(BigInteger.valueOf(arr[i]));
}
System.out.println(sum);
}
}
}