Java 异常 随机数 包装类
异常,随机数,包装类,日期类
正如 “人无完人”一样,程序也不是完美的,它总会存在这样那样的问题,而有些问题并不是能够通过程序员开发更好的代码来解决的,如果我们忽视它,可能就会造成程序的终止,甚至是系统的崩溃。因此,我们需要想办法来合理的解决它,这就是Java中异常的由来。
异常
- 异常的定义:是指在程序运行的过程中出现的非正常的情况,最终可能导致JVM的终止,异常本身是一个类,产生异常就是创建了异常对象并抛出一个异常对象.
- 误区: 异常并不是语法错误,语法错误会直接导致程序无法编译成功,不会产生.class文件,而异常是在程序运行时发生的.
异常的分类
在java中,异常被当成一个对象来看待,其根类是java.lang.Throwable
,Throwable类又分为Error
和Exception
- Error:不能处理的异常,这是系统内部异常,运行时报错,属于系统问题.一般发生Error异常,JVM会选择终止程序,开发人员需提前避免该异常
- Exception:可以处理的异常,这是比较常见的异常,开发人员可以根据java中异常得类来处理.
Error
- 对于严重的Error,没有办法处理,只能做到提起规避.常见的Error有:
(栈溢出错误)和 (内存溢出错误)。 - Java中堆是用来存储对象实例的,因此如果我们不断地创建对象, 并且对象没有被垃圾回收, 那么当创建的对象过多时, 会导致内存不足, 进而引发
异常。
Exception
我们一般说的异常都是指的是Exception异常,这种异常一旦出现我们就要堆代码进行更正修复程序.
- 根据编译时期还是运行时期可以将异常分为一下两类
编译时异常(checked Exception)
- 即在编译时期就会检查程序是否有的异常,如何没有处理异常,则会编译失败,如文件无法找到等异常,异常对于编译时异常我们必须处理否则无法编译通过.
运行时异常(runtime Exception)
- 即在运行时就对程序检查的异常,在编译时期运行异常不会被编译器检测(开发工具不会提示,只有运行时才会报的异常),如空指针异常,类型转化异常,数字操作异常.
public class Test01 {
public static void main(String[] args) {
//FileInputStream inputStream = new FileInputStream("java笔记.txt");//会报编译时异常
String str=null;
System.out.println(str.length());//运行时异常->空指针异常
Object o = new Object();
String s=(String) o;//运行时异常->类型转换异常
int i=10/0;//运行时异常->数字操作异常
}
}
异常的传递
在java程序
try
语块中抛出一个异常,若这个异常没有被catch
语句块捕获,这个异常会沿着调用栈向上传递,直到它被某个catch
语句捕获,或者若直到到达程序顶层(main
方法或程序入口)仍没有被捕获,那么程序就会终止,并打印出异常堆栈的信息.该过程就是异常传递
异常的处理
异常的处理有三种,throw(抛出),throws(声明,向上抛),try-catch(捕获)代码块
throw
java程序出现异常时会创建一个异常对象,该对象将会被提交到java运行系统,并将控制权转移给能够处理该异常的代码,这个过程被称为抛出→抛出一个异常对象
- 自动生成:程序运行时,JVM检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应的异常类的实例对象并抛出,即自动抛出
- 手动生成:
Expectation expectaion=new Expectation();
这样创建的异常对象若不抛出则对程序没有任何影响,即和创建一个普通对象一样,但是一旦抛出,就会对程序运行产生影响,会导致程序终止.
//自动抛出异常例子
public class Test01 {
public static void main(String[] args) {
int arr[]={1,2,3,4};
int index=4;
//我们写相应的异常处理程序代码,由虚拟机自动检测创建异常对象自动抛出。
System.out.println(getElements(arr, index));
}
public static int getElements(int arr[],int index)
{
return arr[index];//下标越界之后JVM会自动识别异常并创建一个异常对象并抛出
}
}
//手动抛出异常
public class Test01 {
public static void main(String[] args) {
int arr[]={1,2,3,4};
int index=4;
System.out.println(getElements(arr, index));
}
public static int getElements(int arr[],int index)
{
if (arr==null) throw new NullPointerException("数组为空");//手动抛出异常
if(index<0||index>arr.length-1) throw new IndexOutOfBoundsException("下标越界");
return arr[index];
}
}
throws
与
throw
不同相同的是,throws
,只是在可能出现异常的方法声明异常,throws
不会抛出一个异常对象,作用的对象是方法
- 不处理异常:与
try-catch
不同,throws
并不会在方法内部处理异常,只是声明告诉调用者”该方法可能会抛出这些异常,你需要处理它”若调用者不处理可接着throws
接着甩锅 - 向上传递:若一个地方使用了
throws
声明了可能会抛出的异常,但方法内部没有将其捕获,那么这些异常会向上传递到调用该方法的代码中. - 受检查异常与非受检查异常:
public class Test01 {
public static void main(String[] args) //在主函数也可以向上抛出FileNotFoundException
{
//调用该方法时会报错,以为getFile的异常被抛到调用其方法的代码
getFile();
}
public static void getFile () throws FileNotFoundException//向上抛出异常,但不处理,交给调用者处理
{
FileInputStream inputStream = new FileInputStream("java开发");
}
}
try-catch
try-catch
的核心思想是将程序中可能会出现异常的代码块(try
块)与处理异常代码(catch
块)分离,从而提高程序处理异常的能力
- 异常捕获:
try
块中包含了可能抛出异常的代码.当执行这些代码发生异常,java会立即停止try
块中的剩余代码,创建一个异常对象并抛出,并查找与之匹配的catch
块. - 异常处理:
catch
用于处理try
块中
public class Test02 {
public static void main(String[] args) {
int result;
try{
result=10/0; //此时有除0异常
System.out.println("result:" + result);//若没有异常此语句将会被执行
}
catch (ArithmeticException e){
System.err.println("An arithmeticException happened here"+e.getMessage());
}
System.out.println("try-catch语句之后保持顺序执行");
}
}
finally
finally
是java异常处理中一个重要的部分,它与try
语句和catch
语句共同使用,以确保无论是否发生异常,某些代码都是能运行的 ,即finally
块用于包含那些无论是否发生异常都必须执行的代码
执行时机
- 正常完成:如果
try
块中的代码正常运行,没有发生异常,则finally
块在try
块之后运行 - 异常发生:如果
try
块中的的代码抛出异常,并且这个异常被相应的catch
块捕获(或者没有被catch
捕获但异常被传递出去),则finally
块会在catch
块之后执行,或者是在try
块之后异常传递之前执行 - Return:若在
try
块和catch
块中带有return
关键字,则finally
块会在return
之前执行,但finally
块不会改变return
的返回值,除非finally
块中也包含return
语句,则返回finally
块中的值
public class Test01 {
public static void main(String[] args)throws
{
getFile();
}
public static void getFile ()
{
try {
//可能会找不到文件
FileInputStream inputStream = new FileInputStream("java开发");
}
catch (FileNotFoundException e){
//若找不到文件者抛出notFound异常
System.out.println(e.getMessage());
}
finally {
//无论如何都会执行关闭文件语句
System.out.println("关闭文件");
}
}
}
自定义异常
通过继承java中
Exception
类或其他子类(如RuntimeException
)来创建异常类,该方式可以让开发者自定义特定的错误异常,可以更灵活和准确处理程序中的错误异常
自定义异常的创建
- 确定基类(父类)
- 自定义异常应该继承相应的Exception或其子类,如希望检验受检异常则应该继承
Exception
,如果希望运行时异常,则应该继承RuntimeException
因此在每次自定义异常时要准确的继承相应基类
- 编写自定义异常类
- 可以创建一个新的类,并使其继承所选择的异常父类
- 可添加自定义属性和方法
- 可重写相应的的
toString() getMessage()
方法
public class LessThan0Exception extends RuntimeException{
//自定义一个异常类LessThan0Exception 继承了RuntimeException类
public LessThan0Exception() { //无参构造方法
super("该数为负数!");//调用父类抛出信息方法
}
}
public static void main(String[] args) {
int age=-10;//主函数中
if(age<10)
{ //若age为负数则会抛出自定义异常
throw new LessThan0Exception();
}
}
随机数
随机数在日常开发中也是十分常见的,例如抽奖,随机点名等等,所有随机数都是
Random
类的使用
基本用法
public static void main(String[] args) {
Random random = new Random();//实例化一个random对象
System.out.println(random.nextInt());//随机产生一个int类型的数
System.out.println(random.nextInt(10));//随机产生一个[0,10)的数
System.out.println(random.nextDouble());//随机产生一个双精度的浮点数
System.out.println(random.nextDouble(10));//随机产生一个[0,9)的浮点数
}
日期类
在开发工作中日期类也是十分常见的
Date
作为一个最基础的日期类,是我们学习的必要
public static void main(String[] args) {
Date date = new Date();
//Date重写了toString()方法
System.out.println(date);//以美国国家习惯打印出该天的日期格式符
System.out.println(date.getTime());//打印从1970.01.01到目前为止的毫秒数
}
日历类
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();//获取日历类对象
System.out.println(calendar.get(Calendar.YEAR));//获取当前年份
System.out.println((calendar.get(Calendar.MONTH) + 1));//获取当前月份
//由于java月份范围是[0,11] 因此要加上一个1
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//显示今天是该月的第几天
System.out.println(calendar.get(Calendar.HOUR));//获取当前小时数(12进制)
System.out.println(calendar.get(Calendar.HOUR_OF_DAY));//获取当前小时(24进制)
System.out.println(calendar.get(Calendar.MINUTE));//获取分钟数
System.out.println(calendar.get(Calendar.SECOND));//获取秒数
System.out.println(calendar.get(Calendar.MILLISECOND));//获取毫秒数
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//获取该填是该年的第几天
System.out.println(calendar.get(Calendar.DAY_OF_WEEK));//获取该天是该周的第几天即 星期几
calendar.set(Calendar.MONTH,6);//设置当前月份为6月
System.out.println(calendar.get(Calendar.MONTH));
calendar.add(Calendar.YEAR,1);//add(),将y,m,d或加上一定的数
System.out.println(calendar.get(Calendar.YEAR));
calendar.getTime();
}
SimpleDataFormat
该类是用于格式化和解析日期的具体类,允许进行格式化(日期→文本),解析(文本→日期)和规范化
- 构造方法:
SimpleDataFormat(String pattern)
指定日期格式 其中y:年,MM:月,dd日 HH:小时,mm:分钟,ss秒;例如”yyyy-MM-dd HH:mm:ss”
则表示为 2024-07-03 22:42:15 - 日期格式化:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//将当前的日期格式化为yyyy-MM-dd HH:mm:ss
String date=simpleDateFormat.format(new Date());//传入一个Date类型的参数
System.out.println(date);
结果为:2024-07-03 23:26:58
- 日期解析:在日期解析中会用到
SimpleDateFormat
类中的Parse
函数,其主要的作用是数据类型的转换(包括将字符串转化为程序所需的类型,int,float,date,time等等),复杂数据结构的生成(主要包括引用数据类型,数组,列表,等等),
String dateString="2000-01-01 12:00:00";
try{ //可能会出现解析错误异常因此要做好异常处理
Date date1 = simpleDateFormat.parse(dateString);
System.out.println(date1);
}
catch (ParseException e)
{ //当出现解析错误异常则向控制台打印出相应的错误
e.printStackTrace();
}
结果为:Sat Jan 01 12:00:00 CST 2000
包装类
包装类,是基本数据类型的封装形式,它允许将基本数据类型当作对象来处理,从而可以调用相应的方法.
基本数据类型与包装类对应关系
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
包装类的作用
- 提供对象化的方法:包装类提供了一系列的方法,允许对基本数据类型进行跟复杂的操作,如类型转化,解析字符串等等
- 自动装箱与拆箱:允许包装类与基本数据类型可以相互转化,简化了编程工作
自动装箱与拆箱
自动装箱
自动装箱指的是java编译器在编译阶段自动将基本数据类型转化为包装类,该过程是透明的,无需手动编写代码
int num=10;
Integer integer = num; //相当于Integer integer= Integer.valueof(num);
System.out.println(integer);
解释:num
是基本数据类型int
,integer
是一个Integer类型变量,当把num
的值赋给integer
时,编译器会自动执行装箱操作,将int
类型的num
转化为Integer
类型
底层实现原理
- 自动装箱实际是调用包装类
valueOf()
方法实现的,编译器会自动将装箱操作转化为对valueOf()
方法的调用,例如上述例子就是自动调用了
Integer integer=Integer.valueOf(num);
- 注意!!
每次JVM执行时,对于Integer
,Short
,Byte
,Character
,Boolean
会自动缓存-128到127之间的整数(Byte,Short
)以及字符值和布尔值.这意味着在给范围内的装箱操作会返回缓存中的对象引用,而不是新创建对象
自动拆箱
自动拆箱是装箱的逆过程,指的是在编译阶段自动将包装类转化为基本数据类型的过程,该操作也是透明的,无需手写转化代码
Integer integer=10;
int i=integer;// int num=integer.intValue(i);
System.out.println(i);
解释:num
是基本数据类型int
,integer
是一个Integer类型变量,当把num
的值赋给integer
时,编译器会自动执行拆箱操作,将Integer
类型的num
转化为int
类型
底层实现原理
自动拆箱的过程实际上是调用了包装类中的xxxValue()
方法(如 doubleValue()
,intValue()
),编译器会自动将拆箱操作转化为相对应的xxxValue()
操作,上述例子实际被编译器转为