Java学习13(异常)

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java学习13(异常)相关的知识,希望对你有一定的参考价值。

Java学习13

今天怎么过呢,还没想好哈哈
2021.5.8(下了雷阵雨马上就出彩虹了,哈哈,心情瞬间满格了),今天争取把这个复习完把

对日期的处理

java.util.Date
获取系统当前时间(精确到豪秒,但是其中的toString不会显示毫秒),直接调用无参构造就行,输出的时间是国外那种形式的日期
如果用有参构造,传入的参数是毫秒,获取的时间是自 1970年1月1日0时 加上参数的时间

日期怎么格式化?即将日期类型Date,按照指定的格式进行转换,转换成一定格式的日期字符串String
    SimpleDateFormat是java.text包下的。专门负责日期的格式化
    yyyy 年(年是4位的)
    MM月 (月是2位)
    dd日  (日是2位)
    HH时
    mm分
    ss秒
    SSS毫秒 (毫秒3位,最高999,1000毫秒等于1秒)
    注意:在日期格式中,除了给定的字符不能随便写,其他随意组织
    
    Date nowTime = new Date();   //先获取系统当前时间
    System.out.println(nowTime);    
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");  //更改格式
    String now = sdf.format(nowTime); //调用format方法,将Date改为String
    System.out.println(now);
    
怎么将String类型转换为Date类型?
    String time = "2008-08-08 08:08:08 888";
    //构造方法中的格式必须和String time的日期格式相同
    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
    Date dateTime = sdf2.parse(time);   //调用parse方法
    System.out.println(dateTime);

获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数
    System.currentTimeMillis();  //可以统计运行时长   北京在东八区,所以从8点开始计算
//系统当前时间
        Date nowTime = new Date();
        System.out.println(nowTime);    //Sat May 08 19:51:02 CST 2021
        //Date转换成字符串
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
        String now = sdf.format(nowTime);
        System.out.println(now);        //2021-05-08 19:51:02 周六
        //字符串转换成Date
        String time = "2008-08-08 08:08:08 888";
        //构造方法中的格式必须和String time的日期格式相同
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        Date dateTime = sdf2.parse(time);
        System.out.println(dateTime);       //Fri Aug 08 08:08:08 CST 2008
		Date time = new Date(1);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String stf = sdf.format(time);
        System.out.println(stf);        //1970-01-01 08:00:00 001
		long nowTimeMills = System.currentTimeMillis();
        System.out.println(nowTimeMills);           //1620474799045

        //统计运行时长
        long begin = System.currentTimeMillis();
        for(int i = 0; i < 1000000000; i++){}
        //System.out.println(i);
        long end = System.currentTimeMillis();
        System.out.println(end - begin);            //3

暂时总结System

System.out 【out是System类的静态变量】
System.out.println()    【println()方法不是System类的,是PrintStream类的方法】
System.gc()  建议启动垃圾回收器
System.exit(0)   退出JVM
System.currentTimeMillis()

数字相关类

java.text.DecimalForamt 专门负责数字格式化的
DecimalFormat df = new DecimalForamt(“数字格式”);

数字格式有哪些?
    # 代表任意数字
    , 代表千分位
    . 代表小数点
    0 代表不够时补零
例子:###,###.##

java.math.BigDemical;  
BigDemical 属于大数据,精度极高,不属于基本数据类型,属于java对象,这是一个类,专门用在财务软件中
DecimalFormat df = new DecimalFormat("###,###.0000000");
        String s = df.format(12234.5656);
        System.out.println(s);              //12,234.5656000    

        BigDecimal v1 = new BigDecimal(100);
        BigDecimal v2 = new BigDecimal(200);
        System.out.println(v1.add(v2));        //300
随机数:
    java.util.Random;
    //产生任意数
    Random random = new Random();
    int num1 = random.nextInt();  //nextInt无参数,无边界产生随机数
    
    int num1 = random.nextInt(101);  //产生0-100之间的随机数,不能产生101
                                     //nextInt翻译为:下一个int类型数据是101,表示只能取到100
Random random = new Random();
        //生成五个不同的随机数,放在数组中
        int[] array = new int[5];
        for(int t = 0; t < 5; t++){
            array[t] = -1;
            System.out.println(array[t]);
        }
        boolean flag= false;
        for(int i = 0; i < 5; i++){
            int num = random.nextInt(5);
            System.out.println("生成的随机数"+num);
//            array[i] = num;
            for(int j = 0; j < 5; j++){
//                if(i == j)
//                    continue;
                if(num == array[j]){
//                    array[i] = -1;
                    i--;
                    flag = true;
                    break;
                }
                flag = false;
            }
            if(flag == false)
                array[i] = num;
        }
        for(int x = 0; x < 5; x++)
            System.out.println(array[x]);
//结果
-1
-1
-1
-1
-1
生成的随机数2
生成的随机数2
生成的随机数0
生成的随机数1
生成的随机数3
生成的随机数0
生成的随机数0
生成的随机数4
2
0
1
3
4

枚举

枚举:当一个方法执行结果超过两种情况,并且是一枚一枚可以列举出来的时候,建议返回值类型设计为枚举类型。
枚举编译之后也是生成class文件
枚举也是一种引用数据类型
枚举中的每一个值可以看做是常量
枚举类型语法:
    enum 枚举类型名{
        枚举值1,枚举值2,枚举值3(全部大写)
    }
    
****switch语句支持枚举类型
public class EnumTest {
    public static void main(String[] args) {
        Result r = divide(10,0);
        System.out.println(r == Result.FAIL? "计算失败":"计算成功");    //计算失败

        switch (Season.AUTUMN){
            case SPRING:
                System.out.println("春天放风筝");
                break;
            case SUMMER:
                System.out.println("夏天大太阳");
                break;
            case AUTUMN:
                System.out.println("秋天大丰收");        //√
                break;
            case WINTER:
                System.out.println("冬天下大雪");
                break;
        }
    }
    public static Result divide(int a, int b){
        try{
            int c = a / b;
            return Result.SUCCESS;
        } catch (Exception e){
            return Result.FAIL;
        }
    }
}
enum Result{
    SUCCESS,FAIL
}

enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER
}

异常

程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
java语言是很完善的语言,提供了异常的处理方式,程序在执行过程中出现了不正常的情况,java把该异常信息打印输出到控制台,供程序员参考,程序员看到异常信息之后,可以对程序进行修改,让程序更加健壮。
异常信息是JVM打印的
异常的作用:增强程序的健壮性

在java中异常以类的形式存在,每一个异常类都可以创建异常对象

实际上JVM执行到不正常处时,会new异常对象,并且JVM将new的异常对象抛出,打印到控制台上

异常在现实生活中:
    	火灾(异常类):
        小明家着火了(异常对象)
        小芳家着火了(异常对象)

java的异常处理机制

1.异常的继承结构是怎样的?
    我们可以使用UML图来描述一下继承结构
    画UML图有很多工具,例如:Rational Rose(收费的)、starUML等..
2.什么是UML?有什么用?
    UML是一种统一建模语言
    一种图标式语言(画图的)
    UML不是只有java使用,只要是面向对象的编程语言,都有UML
    一般画UML图的都是软件架构师或者说是系统分析师,软件设计人员使用UML
    在UML图中可以描述类和类的关系,程序执行的流程,对象的状态等

 Object下有Throwable(可抛出的)
 Throwable下有两个分支:Error 和 Exception
不管是错误,还是异常,都是可抛出的
所有的错误只要发生,java程序只有一个结果,那就是终止程序的执行。退出JVM,错误是不能处理的
异常可以处理,异常包括两个分支:
    第一个是Exception的直接子类(ExceptionSubClass),叫做编译时异常。编译时异常是表示必须在编写程序的时候,预先对这种异常进行处理,如果不处理,编译器报错
    第二个是运行时异常:RuntimeException。运行时异常,在编写程序阶段可以处理也可以选择不处理

编译时异常和运行时异常,都是发生在运行阶段,编译阶段异常是不会发生的
(******)所有异常都是在运行阶段发生的,因为只有程序运行阶段才可以new对象,因为异常的发生就是new异常对象
编译时异常和运行时异常的区别?
    编译时异常一般发生的概率比较高
    运行时异常一般发生的概率比较低
编译时异常又被称为受检异常(CheckedException),还叫做受控异常
运行时异常又称为:未受检异常(UnCheckedException),或者非受控异常
 
假设java中没有对异常进行划分,没有分为:编译时异常和运行时异常,所有的异常都需要在编写阶段对其进行预处理,将是怎样的结果?
    首先,如果这样的话,程序肯定是绝对安全的
    但是程序员编写程序太累,代码到处都是处理异常的代码

java中对异常的处理有两种方式:
    第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级
        谁调用我,我就抛给谁
    第二种方式:使用try...catch语句进行异常的捕捉
        这件事发生了,谁也不知道,因为我给抓住了
        
    思考:
        异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常也有两种处理方式
    注意:如果异常发生之后一直上抛,最终抛给了main方法,main方法继续上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果,终止程序的执行

处理异常的第一种方式:

在方法声明的位置上使用throws关键字抛出,谁调用我这个方法,我就抛给谁,抛给调用者来处理
throws后面也可以写多个异常,可以用逗号隔开
除了抛当前的异常,也可以抛出该异常的父类异常
一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM,JVM只有终止。(异常处理机制的作用就是增强程序的健壮性,即异常发生了也不影响程序的执行,所以main方法中的异常建议时使用try..catch进行捕捉)

第二种:捕捉

使用try...catch语句对异常进行捕捉,异常抛到此处,不再上抛了
在catch分支中干什么?处理异常

注意:
    只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行
    一个方法体当中的代码出现异常之后,如果上报的话,此方法结束
    另外需要注意,try语句块中的某一行出现异常,该行后面的代码不会执行
    
1.catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型
2.catch可以写多个,建议精确处理一个个异常,这样有利于程序的调试
3.catch写多个的时候,从上到下,必须遵守从小到大的原则
4.catch在JDK8之后可以写或者关系,例如
    catch(FileNotFoundException | NullPointerException)


5.finally
    第一:在finally字句中的代码是最后执行的,并且一定会执行的,即使try语句块中的代码出现了异常,即使try中有return(但是有System.exit(0);退出JVM就不会执行了)
    必须和try...catch一起出现
    第二:finally通常使用在哪些情况下?
        通常在finally语句块中完成资源的释放/关闭
        因为finally中的代码比较有保障
    第三:try和finally可以连用,没有catch也可以

上报和捕捉怎么选择?如果希望调用者处理,就上报;其他情况使用捕捉

异常对象有两个重要的方法

获取异常简单的描述信息:
    String msg = exception.getMessage();

打印异常追踪的堆栈信息:(常用)
    java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的
    exception.printStackTrace();
怎么看异常追踪的堆栈信息,来快速调试程序?
    异常追踪信息从上往下一行一行看
    但是需要注意的是:SUN公司写的就不要看了,主要看自己写的代码上

面试题(特殊情况)

例子见ExceptionTest06:
public static void main(String[] args) {    
    int result = m();    
    System.out.println(result);
}
public static int m(){    
    int i = 100;    
    try{        
        return i;    
    }finally { 
        i++;    
    }
}                   //输出100

反编译之后的代码可以解释:
public static int m(){
    int i = 100;
    int j = i;
    i++;
    return j;
}

java语法规则(有一些规则是不能破坏的):
    方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法)
    return语句一旦执行,整个方法必须结束

final finally fianlize 有什么区别?

final是一个关键字,修饰的变量表示最终的不变的,修饰的方法不可覆盖,修饰的类不能继承
fianlly也是一个关键字,和try联用,使用在异常处理机制中,在finally语句块中的代码是一定会执行的
fianlize()是Object中的一个方法,作为方法名出现,是一个标识符
    fianlize()方法是由垃圾回收器GC负责调用的

自定义异常

1.SUN提供的JDK内置的异常肯定是不够用的,实际开发中和业务挂钩
2.怎么自定义异常?(死记硬背)
    第一步:编写一个类继承Exception和RuntimeException
    第二步:提供两个构造方法,一个有参带有String参数,一个无参

手动抛异常

语法:
    throw new 异常对象;
    
    ###之前知识点:
        重写之后的方法不能比重写之前的方法抛出更多的(更宽泛)的异常,可以更少
        特殊点:父类不抛异常,子类可以抛出运行异常RuntimeException
		//通过异常类实例化异常对象
        NullPointerException npe = new NullPointerException("我发生了异常");
        System.out.println(npe);

        int a = 10;
        int b = 0;
        //实际上JVM在执行到此处的时候,会new异常对象: new ArithmeticException("/by zero");
        //并且JVM将new的异常对象抛出,打印到控制台上
        int c = a / b;//发生了异常
        //Exception in thread "main" java.lang.ArithmeticException: / by zero
        System.out.println(c);
//异常处理两种方式
public class ExceptionTest02 {
    /*public static void main(String[] args) throws ClassNotFoundException {
        //由于ClassNotFoundException是一个编译时异常,没有处理编译器报错
        //第一种处理方式:在方法声明的位置继续上抛,抛给调用者
        doSome();
    }
    */
    public static void main(String[] args) {
        //第二种处理方式是try..catch进行捕捉
        try {
            doSome();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void doSome() throws ClassNotFoundException{
        System.out.println("我在做什么");
    }
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionTest03 {
    public static void main(String[] args){
        System.out.println("main begin");
        try {
            m1();
            //m1出异常,下面的输出就不执行了,跳到catch语句中执行
            System.out.println("hello world");
        } catch (FileNotFoundException e) {
            //这个分支中可以使用e引用,e引用保存的内存地址是那个new出来异常对象的内存地址
            //catch是捕捉异常之后走的分支
            //e.printStackTrace();
            System.out.println(e.getMessage());
            //System.out.println("找不到该文件");
        }
        System.out.println("main end");
    }
    //throws FileNotFoundException的父类IOException
    private static void m1() throws FileNotFoundException{
        System.out.println("m1 begin");
        m2();
        System.out.println("m1 end");
    }

    private static void m2() throws FileNotFoundException{
        System.out.println("m2 begin");
        m3();
        System.out.println("m2 end");
    }
    private static void m3() throws FileNotFoundException {
        //创建一个输入流对象,该流指向一个文件
        /* 这里编译报错的原因是什么?
                第一:这里调用了一个构造方法FileInputStream(String name)
                第二:这个构造方法的声明位置上有:throws FileNotFoundException
                第三:通过类的继承机构看到:FileNotFoundException 父类是 IOException,IOException的父类是Exception
                最终得知,FileNotFoundException是编译时异常
        * */
        new FileInputStream("C:\\\\Users\\\\清风\\\\Desktop\\\\JAVA学习\\\\001-JavaSE课堂笔记+思维导图\\\\07-JavaSE进阶每日复习与笔记\\\\day27课堂笔记.txt");

        System.out.println("如果出异常,这里不会执行");
    }
}
----------------------
//无异常输出如下:
main begin
m1 begin
m2 begin
如果出异常,这里不会执行
m2 end
m1 end
hello world
main end
--------------------
有异常输出如下:
main begin
m1 begin
m2 begin
C:\\Users\\清风\\Desktop\\JAVA学习\\day27课堂记.txt (系统找不到指定的文件。)
main end
		try{
            System.out.println(100/0);
            FileInputStream fis = new FileInputStream("C:\\\\Uers\\\\清风\\\\Desktop\\\\JAVA学习\\\\day27课堂笔记.txt");		
            System.out.println(100/0);
        }catch (FileNotFoundException e){
            System.out.println("文件不存在");
        }catch (ArithmeticException e){
            System.out.println("除数不能为0");       //输出:除数不能为0
        }
		//这里只是new了异常对象,并没有抛出,JVM会认为这是一个普通的Java对象
        NullPointerException e = new NullPointerException("空指针异常");
        //获取异常的简单描述信息:这个信息实际上就是构造方法上面String参数
        String msg = e.getMessage();
        System.out.println(msg);        //空指针异常

        //打印异常堆栈信息
        //以下代码:先输出try0000000,再输出final,再执行return
        try{
            System.out.println("try00000000");
            return;
        }finally {
            System.out.println("fianl");
        }
	//下面程序,先输出101,再输出100
    public static void main(String[] args) {    
        int result = m();    
        System.out.println(result);	//100
    }
    public static int m(){    
        int i = 100;    
        try{        
            return i;    
        }finally { 
            i++;   
            System.out.println(i);	//101 
        }
    }                  

以上是关于Java学习13(异常)的主要内容,如果未能解决你的问题,请参考以下文章

从片段内部访问 Toolbar/ActionBar 对象

PCL异常处理:pcl 1.8.13rdpartyoostincludeoost-1_64oost ypeofmsvc ypeof_impl.hpp(125): error(代码片段

java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.database.sqlite异常(代码片段

10/13-10/19 java学习总结(没有课堂的课后学习总结) &实验总结6

Java学习13(异常)

getApplicationContext给出空指针异常[重复]