Java 异常 随机数 包装类

异常,随机数,包装类,日期类

正如 “人无完人”一样,程序也不是完美的,它总会存在这样那样的问题,而有些问题并不是能够通过程序员开发更好的代码来解决的,如果我们忽视它,可能就会造成程序的终止,甚至是系统的崩溃。因此,我们需要想办法来合理的解决它,这就是Java中异常的由来。

异常

  • 异常的定义:是指在程序运行的过程中出现的非正常的情况,最终可能导致JVM的终止,异常本身是一个类,产生异常就是创建了异常对象并抛出一个异常对象.
  • 误区: 异常并不是语法错误,语法错误会直接导致程序无法编译成功,不会产生.class文件,而异常是在程序运行时发生的.

异常的分类

在java中,异常被当成一个对象来看待,其根类是java.lang.Throwable ,Throwable类又分为ErrorException

  1. Error:不能处理的异常,这是系统内部异常,运行时报错,属于系统问题.一般发生Error异常,JVM会选择终止程序,开发人员需提前避免该异常
  2. 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)来创建异常类,该方式可以让开发者自定义特定的错误异常,可以更灵活和准确处理程序中的错误异常

自定义异常的创建

  1. 确定基类(父类)
  • 自定义异常应该继承相应的Exception或其子类,如希望检验受检异常则应该继承Exception,如果希望运行时异常,则应该继承RuntimeException 因此在每次自定义异常时要准确的继承相应基类
  1. 编写自定义异常类
  • 可以创建一个新的类,并使其继承所选择的异常父类
  • 可添加自定义属性和方法
  • 可重写相应的的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() 操作,上述例子实际被编译器转为

posted @ 2024-07-04 01:04  ihav2carryon  阅读(27)  评论(0编辑  收藏  举报